Getting started
Conventions
Rules every endpoint follows: envelope, status codes, time and ids, pagination, idempotency, rate limits, request ids and versioning.
Envelope and status codes
Success is { data, meta }, failure is { error: { code, message, params }, meta }. Create-type endpoints (post / idea / reply / media) return 201, everything else 200; the HTTP status of an error follows error.code, see Errors.
Branch on
error.code, never on the message text — it is an English hint for humans and models and its wording may change.Time and ids
- Timestamps in responses are ISO 8601 UTC (
2026-09-21T10:00:00.000Z); timestamps in requests must carry a timezone (Zor±HH:MM) or you get 400. - Analytics use Beijing calendar days, same as the in-app analytics page.
- Ids are opaque strings valid only within this workspace; do not parse them.
- Platform enum:
x,youtube,instagram,tiktok,facebook,threads(published by popkit) anddouyin,xiaohongshu,wechat_mp(manual channels: recorded, not sent).
Pagination
List endpoints paginate with cursors: a non-null nextCursor means there is more; pass it back as cursor. limit defaults to 20 with a maximum of 100 (the comment inbox is fixed at 30). Cursors are opaque and time-limited; a broken one returns 400.
GET /api/v1/posts?status=published&limit=50
GET /api/v1/posts?status=published&limit=50&cursor=<nextCursor>Idempotency
- Write endpoints accept an
Idempotency-Keyheader (8–128 chars of [A-Za-z0-9_.:-]);clientRequestIdin the body also works, the header wins when both are present. - Required for the publish tier (
action: "publish", confirm, publish / retry, reply); optional on other writes. - Same credential + endpoint + key within 24 hours: you get the first result back with
meta.replayed: trueand anIdempotent-Replayed: trueheader; media uploads cache for only 5 minutes (the upload ticket's lifetime). - The same key with different input is refused, to catch keys used as constants; failures are not cached, so you may reuse the key after fixing the input.
- A concurrent retry while the first call is still running returns 409 (
replay); retry shortly.
Rate limits and daily caps
Three tiers counted per credential (REST and MCP share one budget); exceeding returns 429 with Retry-After in seconds.
| Tier | Per minute | Endpoints |
|---|---|---|
| read | 60 | All GET + publish precheck |
| write | 10 | Create / update (non-publish tiers), reschedule, submit, attach media, create idea |
| publish | 5 | Publish-tier create / update, confirm, publish / retry, reply |
- Per-credential daily publish cap defaults to 20 (operators can adjust per credential); the same account is published to at most once every 600 s; scheduling is capped at 100/day.
- Comment replies: at most 3 replies per comment per 24 h and 500 per credential per day.
- A post targets at most 20 accounts; the plan's monthly scheduling quota is in
GET /v1/workspace→quotas, and exhausting it returns 402 (plan_limit). - Daily-cap 429s carry
params.reason(e.g.publish_daily_cap); retrying does not help until the next day.
Request ids and versioning
- You may send
X-Request-Id(≤36 chars of[A-Za-z0-9._:-]); it is echoed in the response header andmeta.requestId, otherwise one is generated. Quote it when reporting problems. - Only backward-compatible additions happen within
/api/v1; breaking changes get a new major version with advance notice. - Machine-readable definition: OpenAPI 3.1, generated from the same schemas the runtime validates with, so it cannot drift.