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 (Z or ±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) and douyin, 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-Key header (8–128 chars of [A-Za-z0-9_.:-]); clientRequestId in 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: true and an Idempotent-Replayed: true header; 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.

TierPer minuteEndpoints
read60All GET + publish precheck
write10Create / update (non-publish tiers), reschedule, submit, attach media, create idea
publish5Publish-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 and meta.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.