# SosoAPI 發布 API：身分驗證、請求和結果

標準 URL： https://sosoapi.ai/zh-tw/docs/publishing-api-reference

以每個目標一份排程貼文建置伺服器端發布整合。此參考涵蓋於 2026 年十月 20 日 審核的發布 API 契約。範例包含預留位置，不會在此頁面執行。

## 1. 從伺服器進行驗證

在「SosoAPI App → 設定 → 代理程式與 API 存取權」建立 API key。於伺服器環境儲存為 SOSOAPI_API_KEY。請求使用 Authorization: Bearer <your-key> 以及 Content-Type: application/json。絕不要將 key 嵌入網站、行動應用程式套件、URL 或公開儲存庫。

以下所有端點皆使用 POST 與 JSON 主體。Keys 與委派代理程式授權受其能力、允許的 Workspaces 及擁有者目前成員資格限制。讀取需要 agent:operate 及至少 viewer 權限；發布變更需要 agent:publish 及至少 editor 權限。授權無法擴大擁有者的權利。

使用應用程式的目前工作空間和已連結帳號，或呼叫 /identity-api/workspace/list 和 /identity-api/user/social-accounts/list 查找您獲准使用的 ID。不要猜測客戶的工作空間或帳號 ID。

```
// Node.js 20+; run only on your server.
const apiKey = process.env.SOSOAPI_API_KEY;
if (!apiKey) throw new Error("Set SOSOAPI_API_KEY on your server");
const apiBase = "https://gqeshlawtcexsapabaui.supabase.co/functions/v1";

async function sosoPost(path, body) {
  const response = await fetch(apiBase + path, {
    method: "POST",
    headers: {
      Authorization: "Bearer " + apiKey,
      "Content-Type": "application/json"
    },
    body: JSON.stringify(body)
  });
  const result = await response.json();
  if (!response.ok) {
    const requestId = result.request_id ?? response.headers.get("x-request-id");
    // Handler errors use code/message; schema-validation 400s instead use
    // success:false and error:{name:"ZodError",message:...}.
    // Preserve status, available code and requestId in server diagnostics.
    // Never log the key or an Authorization header.
    throw new Error("SosoAPI " + response.status + " (" +
      (requestId ?? "no request id") + ")");
  }
  return result;
}
```

## 2. 發布端點映射

這些路徑相對於伺服器輔助函式使用的 API 基底網址。請取得排程貼文詳細資料，以取得目前版本、可用操作與發布結果。

排程貼文端點；所有請求皆為 POST

| 路徑 | 請求 | 回應與界線 |

| --- | --- | --- |

| /studio-api/scheduled-posts/list | workspace_id；選填 project_id、status、時間配對、limit、cursor。 | posts、next_cursor、returned_count。Workspace 範圍讀取。 |

| /studio-api/scheduled-posts/get | id。 | post、delivery、actions、attempts、outcomes。在此讀取目前 version。 |

| /studio-api/scheduled-posts/eligibility | workspace_id、targets；選填 include_quota。 | destinations 與選填 quota。唯讀預檢，不是資源預留。 |

| /studio-api/scheduled-posts/create | workspace_id、確切帳號、provider_payload、content、scheduled_at、idempotency_key。 | post 和 deduped。新排程為 201；相符重播為 200。 |

| /studio-api/scheduled-posts/bulk-create | workspace_id 與 1–50 個 targets，各自具有自己的 idempotency_key。 | batch_id、successes、failures。至少一項成功時為 201；無任何成功時為 422。請檢查兩個陣列。 |

| /studio-api/scheduled-posts/update | id、expected_version、patch；選填且相符的 provider_payload。 | post。過期版本會遭拒絕；destination 不可變更。 |

| /studio-api/scheduled-posts/publish-now | id 與 expected_version。 | post。請求立即執行；不代表已發布。 |

| /studio-api/scheduled-posts/retry | id、expected_version；選填未來 scheduled_at。 | post。僅限失敗貼文、以證據為前提的復原；絕不盲目重送。 |

| /studio-api/scheduled-posts/cancel | id 和 expected_version。 | post。取消尚未發布的任務；遠端取消可能仍處於待處理狀態。 |

| /studio-api/scheduled-posts/delete | id 和 expected_version。 | post。機器呼叫端無法刪除已發布的平台內容。 |

| /studio-api/scheduled-posts/withdraw-delete | id 和 expected_version。 | post。撤回已停止、僅供驗證的 Instagram Login 刪除請求；保留平台內容。 |

## 3. 在保留範圍的前提下列出和分頁

limit 預設為 50，接受 1–200。選填 status 為 scheduled、publishing、published、failed、expired、needs_reschedule、cancelled 或 deleted 之一。scheduled_from 和 scheduled_to 必須一同提供，格式為帶偏移量的 ISO-8601 時刻；結束時間必須晚於開始時間。

next_cursor 為 null 或含 scheduled_at 和 id 的物件。將整個物件作為 cursor 連同相同工作空間和篩選條件傳回。此端點不接受 page、offset、platform 或 social_account_id 篩選。

```
await sosoPost("/studio-api/scheduled-posts/list", {
  "workspace_id": "<workspace-uuid>",
  "limit": 50
});
```

```
const first = await sosoPost("/studio-api/scheduled-posts/list", {
  workspace_id: "<workspace-uuid>", limit: 50
});
if (first.next_cursor) {
  const next = await sosoPost("/studio-api/scheduled-posts/list", {
    workspace_id: "<workspace-uuid>", limit: 50, cursor: first.next_cursor
  });
  // Consume next.posts; continue only while next_cursor is not null.
}
```

## 4. 驗證並建立一則已審核貼文

將所有預留位置替換為授權範圍內的值和未來時間。執行此範例會排程一則真實的 Threads 文字貼文。呼叫建立操作前，請獲得本人對帳號、內容和時間的確認。

設定 provider_payload.platform 及該平台的 publish_options。伺服器會確認兩者與所選帳號相符。可加入 project_id 記錄貼文來源；專案不會授予發布存取權，也不會控制排程。

建立請求欄位與預設值

| 欄位 | 契約 |

| --- | --- |

| workspace_id / social_account_id | 已授權 Workspace 及確切目標所需的 UUID。 |

| provider_payload | 必填的平台判別欄位與平台專屬 publish_options。 |

| scheduled_at / display_timezone | 必填的含時差 ISO-8601 時間點；有效的 IANA 顯示時區，預設 UTC。 |

| idempotency_key | 必填的去除首尾空白字串，8–160 個字元，對此次意圖保持不變。 |

| caption / hashtags | caption 可為 null，最多 5,000 個字元；預設為 null。hashtags 預設為 []；最多 100 個字串，每個 100 個字元。平台限制可能更嚴格。 |

| media | 預設 []；最多 20 個已登記媒體參照。各參照具有 kind image/video 及標準 url；請加入其已就緒的 asset_id。平台規則可能更嚴格。 |

| link_url | 選填 URL 或 null。目標與貼文類型必須支援此欄位。 |

| local_scheduled_at / schedule_dst_disambiguation | 選填配對：不帶偏移量的本地時間及 exact/earlier/later。兩者都提供或都省略；必須相符預期時刻和時區。 |

| expires_at / automatic_retry_enabled | 選填且晚於 scheduled_at 的到期時間；null 表示不到期。自動重試預設 true，仍受平台安全規則限制。 |

| project_id / source_ref | 選填且可為 null 的 Project UUID 與呼叫端來源物件。兩者皆不變更權限。 |

```
await sosoPost("/studio-api/scheduled-posts/eligibility", {
  "workspace_id": "<workspace-uuid>",
  "include_quota": true,
  "targets": [
    {
      "social_account_id": "<threads-account-uuid>",
      "media": [],
      "provider_payload": {
        "platform": "threads",
        "publish_options": {
          "post_type": "TEXT"
        }
      },
      "draft": {
        "caption": "A reviewed update from our team.",
        "hashtags": [],
        "scheduled_at": "<future-ISO-8601-instant-with-offset>",
        "display_timezone": "Asia/Hong_Kong"
      }
    }
  ]
});
```

```
await sosoPost("/studio-api/scheduled-posts/create", {
  "workspace_id": "<workspace-uuid>",
  "social_account_id": "<threads-account-uuid>",
  "caption": "A reviewed update from our team.",
  "hashtags": [],
  "media": [],
  "provider_payload": {
    "platform": "threads",
    "publish_options": {
      "post_type": "TEXT"
    }
  },
  "scheduled_at": "<future-ISO-8601-instant-with-offset>",
  "display_timezone": "Asia/Hong_Kong",
  "idempotency_key": "<stable-key-for-this-one-intent>"
});
```

## 5. 查看結果並安全取消

建立會回傳 { post, deduped }。清單會回傳 { posts, next_cursor, returned_count }。讀取會回傳 { post, delivery, actions, attempts, outcomes }。貼文包含 id、status、version、destination、schedule，以及可用的平台身分／永久連結；delivery 與 actions 說明目前進度與允許的下一步。

status 為 scheduled 或 publishing 的貼文仍待處理。status 為 published 的終端發布結果才確認已發布，並包含該貼文可取得的平台證據；可能缺少永久連結。如果用戶端中斷連線或回應延遲，請先讀取既有貼文再回報結果。

取消前，先取得貼文詳細資料並傳入目前的數值 version。SosoAPI 取消平台持有的排程時，結果可能為 cancellation_pending。取消排程不會刪除已發布貼文。

```
await sosoPost("/studio-api/scheduled-posts/get", {
  "id": "<scheduled-post-uuid>"
});
```

```
const detail = await sosoPost("/studio-api/scheduled-posts/get", {
  id: "<scheduled-post-uuid>"
});
// Run only after the person confirms cancelling this unpublished post.
await sosoPost("/studio-api/scheduled-posts/cancel", {
  id: detail.post.id, expected_version: detail.post.version
});
```

## 6. 冪等性、衝突與寫入結果不明

重複同一建立請求時，使用相同的 idempotency_key。相符的重播會回傳現有貼文，且 deduped=true。重複使用該 key 但更改內容會導致衝突。這可防止在 SosoAPI 中重複建立，但不保證平台恰好傳送一次。

更新與操作請傳入最新詳細回應中的 expected_version。如有衝突，請重新取得貼文，並依新版本檢閱變更。回應遺失時應檢查既有狀態，不應使用新鍵另建貼文。

重複內容防護可能會拒絕獨立請求，如果其標準化公開內容、帳號和臨近發布時間相同。如獲准讀取，請檢查現有貼文參照，並在更改請求前詢問使用者。批次請求會為每個目標回傳結果；部分可能成功，其他則失敗。

## 7. 錯誤、速率限制與整合限制

處理常式錯誤使用包含 error、message、選填 code、retryable、request_id、選填 details 和 retry_after_seconds 的封裝。schema 驗證 400 錯誤回傳不同結構：{ success: false, error: { name: "ZodError", message: "…" } }。驗證訊息目前包含序列化欄位問題及其路徑；不要假定處理常式封裝欄位存在。

診斷失敗時，請保留 HTTP 狀態、錯誤碼，以及 result.request_id ?? response.headers.get("x-request-id") 的關聯 ID。使用驗證欄位路徑修正請求。若為驗證或權限錯誤，請先修正憑證或授權再重試。

studio-api 目前限制為每位人工使用者每分鐘 240 個請求，以及該使用者獨立機器憑證配額桶每分鐘 480 個請求。這是請求上限，不是發布吞吐量或方案配額。其他端點和社群平台有各自限制。收到 429 或可重試 503 時，遵循即時 Retry-After 回應頭；不要忙循環。

使用者跟進貼文期間，以有界限的間隔讀取狀態，或使用應用程式即時狀態視圖。此 API 不承諾向外傳送 webhooks、訂閱者 SLA、各平台功能一致或固定發布時間。

HTTP 回應與有用的後續操作

| 狀態 | 含義與回應 |

| --- | --- |

| 400 | 結構描述驗證可能回傳 success:false，且 error 中含 ZodError，而非處理常式的回應封裝。請修正欄位問題；若回應內容沒有 request_id，請使用 x-request-id。處理常式層級的無效或不支援請求也可能使用 400。 |

| 401 / 403 | 缺少/過期憑證，或能力、角色、工作空間、帳號存取被拒絕。修復確切授權或成員資格。 |

| 404 | 此資源在已授權範圍內不可用。請驗證身分。 |

| 409 | 狀態/版本、冪等性、重複內容或資格衝突。重新讀取；不要盲目重送。 |

| 批次建立時為 422 | 無任何目標成功。請檢查 failures；部分成功則使用 201。 |

| 429 | 請求節流。遵循 Retry-After，並保持相同的意圖識別。 |

| 503 / 其他 5xx | 暫時服務失敗或內部故障。保留 request_id；重試結果不確定的變更前，檢查現有狀態。 |

- [平台能力對照表](https://sosoapi.ai/zh-tw/docs/publishing-capabilities)

- [設定您自己的 AI 代理程式](https://sosoapi.ai/zh-tw/docs/quickstart)
