服务器 API 参考
SosoAPI 发布 API:身份验证、请求和结果
以每个目标一份 Scheduled Post 构建服务端发布集成。此参考涵盖于 2026年十月20日 审核的发布 API 契约。示例包含占位符,不会在此页面执行。
阅读 Markdown由 SosoAPI 团队审核 ·
1. 从服务器进行验证
在「SosoAPI App → 设置 → agent 与 API 访问权限」创建 API key。于服务器环境存储为 SOSOAPI_API_KEY。请求使用 Authorization: Bearer <your-key> 及 Content-Type: application/json。切勿将 key 嵌入网站、移动应用套件、URL 或公开仓库。
以下所有端点皆使用 POST 与 JSON 主体。Keys 与委派 agent 授权受其能力、允许的 工作区 及所有者当前成员资格限制。读取需要 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 基础 URL。请获取排程帖子详情,以获取当前版本、可用操作与发布结果。
| 路径 | 请求 | 响应与边界 |
|---|---|---|
| /studio-api/scheduled-posts/list | workspace_id;可选 project_id、status、时间对、limit、cursor。 | posts、next_cursor、returned_count。限定于工作区的读取。 |
| /studio-api/scheduled-posts/get | id. | post、delivery、actions、attempts、outcomes。在此读取当前 version。 |
| /studio-api/scheduled-posts/eligibility | workspace_id、targets;可选 include_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。过期版本会被拒绝;目标不可更改。 |
| /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 | 已授权 工作区 及确切目标所需的 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、各平台功能一致或固定发布时间。
| 状态 | 含义与响应 |
|---|---|
| 400 | schema 验证可能返回 success:false,并在 error 中包含 ZodError,而非处理程序封装。修正其字段问题;如正文无 request_id,使用 x-request-id。处理程序层面的无效或不支持请求也可能返回 400。 |
| 401 / 403 | 凭证缺少/过期,或能力、角色、工作区 或账号访问遭拒。请修正确切的授权或成员资格。 |
| 404 | 此资源在已授权范围内不可用。请验证身分。 |
| 409 | 状态/版本、幂等性、重复内容或资格冲突。请重新读取,不要盲目重送。 |
| 批次创建时为 422 | 没有目标成功。检查 failures;部分成功则使用 201。 |
| 429 | 请求节流。遵循 Retry-After,并保持相同的意图识别。 |
| 503 / 其他 5xx | 暂时服务失败或内部错误。保留 request_id;重试结果不明的变更前,先检查现有状态。 |