伺服器 API 參考
SosoAPI Publishing API:驗證、請求同最終結果
以每個目的帳戶一個 Scheduled Post,建立伺服器發佈整合。以下發佈 API contract 已於 2026 年 10 月 20 日核對。示例包含 placeholders,唔會喺呢個頁面執行。
閱讀 MarkdownSosoAPI 團隊核對 ·
1. 從伺服器進行驗證
喺 SosoAPI App → 設定 → Agents & API Access 建立 API key,並喺伺服器環境存為 SOSOAPI_API_KEY。請求使用 Authorization: Bearer <your-key> 同 Content-Type: application/json。唔好將 key 放入網頁、手機 App bundle、URL 或公開 repository。
以下 endpoints 全部使用 POST 同 JSON body。API key 同 agent 授權受 capabilities、允許嘅 Workspaces 同擁有人目前會籍限制。讀取需要 agent:operate 同至少 viewer 角色;發佈寫入需要 agent:publish 同至少 editor 角色。授權唔會擴大擁有人本身嘅權利。
透過 App 目前嘅 Workspace/已連接帳戶,或者已驗證嘅 /identity-api/workspace/list 同 /identity-api/user/social-accounts/list endpoints,取得獲授權 IDs。唔好猜測客戶嘅 Workspace 或帳戶。
// 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. 發佈 endpoints 一覽
路徑相對於伺服器 helper 嘅 API base。Scheduled Post detail 係目前 version、允許操作同發佈證據嘅來源。
| 路徑 | 請求 | 回應同界線 |
|---|---|---|
| /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、內容、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。兩個 arrays 都要檢查。 |
| /studio-api/scheduled-posts/update | id、expected_version、patch;可選相符 provider_payload。 | post。過期 version 會被拒絕;目的帳戶不可更改。 |
| /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。Machine caller 唔可以刪除已發佈嘅平台內容。 |
| /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 必須一齊提供,使用有 offset 嘅 ISO-8601 時間,而且結束必須遲過開始。
next_cursor 係 null,或者包含 scheduled_at 同 id 嘅 object。下一頁要將整個 object 放返入 cursor,並保留相同 Workspace 同 filters。呢個 endpoint 唔接受 page、offset、platform 或 social_account_id filters。
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
});
// Read next.posts. Continue only when next_cursor is not null.
}4. 驗證同建立一個已確認帖子
將每個 placeholder 換成獲授權範圍內嘅值同未來時間。執行以下示例會建立真實 Threads 文字排程。Create 前先由使用者確認帳戶、內容同時間。
provider_payload 包含 platform 同該平台嘅 publish_options。伺服器會核對所選帳戶是否相符。project_id 只係可選來源記錄;Project 唔會授權發佈或控制排程。
| 欄位 | Contract |
|---|---|
| workspace_id / social_account_id | 必填 UUID:已授權 Workspace 同確實目的帳戶。 |
| provider_payload | 必填 platform discriminator 同平台專用 publish_options。 |
| scheduled_at / display_timezone | 必填帶 offset 嘅 ISO-8601 時間;有效 IANA 顯示時區,預設 UTC。 |
| idempotency_key | 必填,trim 後 8–160 字元,同一意圖保持相同。 |
| caption / hashtags | Caption 可為 null,最多 5,000 字元,預設 null。Hashtags 預設 [],最多 100 個、每個 100 字元。平台限制可能更窄。 |
| media | 預設 [],最多 20 個已登記媒體。每項有 image/video kind 同 canonical url;提供已就緒 asset_id。平台限制可能更窄。 |
| link_url | 可選 URL 或 null;目的平台同帖子類型必須支援。 |
| local_scheduled_at / schedule_dst_disambiguation | 可選成對欄位:無 offset 本地時間,加 exact/earlier/later。兩者一齊提供或一齊省略,並須對應所選時間同時區。 |
| expires_at / automatic_retry_enabled | 可選到期時間,必須遲過 scheduled_at;null 代表無到期限制。自動重試預設 true,仍受平台操作安全規則限制。 |
| project_id / source_ref | 可選 nullable Project UUID 同來源 object;兩者都唔會改變權限。 |
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. 讀取結果同安全取消
Create 回傳 { post, deduped };List 回傳 { posts, next_cursor, returned_count };Get 回傳 { post, delivery, actions, attempts, outcomes }。post 包含 id、status、version、destination、排程同可用平台 ID/permalink;delivery 同 actions 解釋進度及允許嘅下一步。
scheduled 或 publishing 唔等於已發佈。publish 最終 outcome 為 published 先有平台發佈證據;permalink 仍可能未有。延遲或斷線嘅 client,要先查現有狀態,先至可以確認結果。
取消前先 Get 最新 detail,再用目前嘅數字 version。原生平台排程可能先進入 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 cancellation.
await sosoPost("/studio-api/scheduled-posts/cancel", {
id: detail.post.id, expected_version: detail.post.version
});6. Idempotency、衝突同未確認寫入
完全相同嘅 create 意圖要保留同一個 idempotency_key。相符重播會回傳已有 post 同 deduped=true;用同一 key 改內容會衝突。Create idempotency 唔等於平台提供 exactly-once delivery。
Update 同 actions 使用最新 detail 嘅 expected_version。遇到衝突先重讀狀態,再審閱改動。唔好覆蓋新 version,亦唔好因為收唔到回應就用新 key 再 create。
另一個意圖如果喺相同帳戶、相近發佈時間使用一樣嘅 normalized 公開內容,可能被重複內容檢查拒絕。先查看回傳而且獲授權嘅 existing-post reference,再由使用者決定要點改。Bulk 按目的帳戶分開回報,唔係全部成功或全部回滾。
7. 錯誤、rate limit 同整合界線
Handler 錯誤使用 envelope:error、message、可選 code、retryable、request_id、可選 details 同 retry_after_seconds。Schema-validation 400 使用另一個格式:{ success: false, error: { name: "ZodError", message: "…" } }。目前 validation message 包含序列化嘅欄位 issues 同 paths;唔好假設有 handler envelope 嘅欄位。
診斷時保留 HTTP status、可用 code,同 result.request_id ?? response.headers.get("x-request-id") 取得嘅 correlation ID。按 validation error 嘅欄位 paths 修正請求。驗證/權限失敗需要修復相應 credential 或授權;重複相同請求唔會取得存取權。
目前 studio-api 每位 human user 每分鐘上限 240 次;同一使用者分開嘅 machine credential bucket 為每分鐘 480 次。呢啲係請求上限,唔係發帖速度或方案 quota。其他 endpoints 同社交平台另有上限。429 或可重試 503 要依照實際 Retry-After header 等待,唔好 busy-loop。
採用有上限、由使用者發起嘅狀態讀取,或者 App 已有嘅即時狀態介面。呢份參考唔承諾 outbound webhook delivery、subscriber SLA、所有平台完全一致或固定發佈延遲。
| Status | 含義同處理 |
|---|---|
| 400 | Schema validation 可能回傳 success:false 同 error 入面嘅 ZodError,而唔係 handler envelope。修正欄位 issues;body 冇 request_id 時用 x-request-id。Handler 層請求不合規格或 payload 唔支援亦可能用 400。 |
| 401 / 403 | Credential 缺失/過期,或 capability、角色、Workspace/帳戶權限被拒。修復確實授權或會籍。 |
| 404 | 喺已授權範圍內搵唔到資源。核對身份。 |
| 409 | 狀態/version、idempotency、重複內容或資格衝突。先重讀,唔好盲目重送。 |
| Bulk-create 嘅 422 | 全部目的帳戶失敗。查看 failures;部分成功會用 201。 |
| 429 | 請求太密。依照 Retry-After 等待,保留相同意圖 identity。 |
| 503 / 其他 5xx | 暫時服務問題或內部錯誤。保留 request_id;對未確認寫入先查現有狀態,再決定重試。 |