Up to 10,000 chars at the API; each platform enforces its own shorter limit. Defaults to `""`.
`mediaItems`
array
0–10 items of `{ type: "image" \
`platforms`
array
1–10 targets of `{ platform, accountId, firstComment? }`.
`idempotencyKey`
string
1–255 chars. Also accepted as the `Idempotency-Key` header; the body field wins.
firstComment is per target, not per post, so the same publish can carry different comment
wording for LinkedIn and Instagram. See First comments.
What is validated up front
Before any network call, Chirio checks in this order:
Body shape — schema violations answer 400 invalid_request.
Accounts exist and belong to your project — otherwise 404 account_not_found.
Platform matches the account — targeting a threads account as instagram answers
400 platform_mismatch.
Per-platform content rules — length, media counts, video/image mixing. A violation on
any target rejects the whole request with 400 invalid_post, before anything publishes.
Quota — 429 quota_exceeded on a plan with no overage. See Quotas.
That ordering is deliberate: everything you can fix is checked before a single byte reaches a
platform, so a rejected request never leaves a half-published post behind.
Reading the response
201 Created (or 200 with replayed: true for an idempotent retry):
Public URL of the post, when the platform returns one
`error`
`code: message` on failure, `null` otherwise
`publishedAt`
When the platform accepted it
`commentStatus`
`none`, `published`, `failed` or `unsupported` — independent of `status`
`commentId` / `commentError`
Outcome of the first comment
Mixed results are normal
Do not treat 201 as success
A 201 means the request was accepted and every target was attempted. Targets fail independently — one platform's rate limit, expired connection or media error does not stop the others. Always iterate post.targets and act per target.
Retrying only the failed targets is also the cheap thing to do: usage is recorded per target
that actually published, so a retry of the third target bills the third target only.
Timing
The call is synchronous and waits for every platform. Image posts settle in seconds. Video is
different — the platform processes the file server-side and Chirio waits for it, up to roughly
four minutes per item, so a video-heavy carousel can take several minutes.
Two consequences worth designing for:
Send an Idempotency-Key so a client-side timeout is safe to retry. See
Idempotency.
Poll GET /api/v1/posts/:id when a replayed response shows targets that have not
settled yet.
Listing history
Newest first. limit is capped at 100 and defaults to 25.
const { post } = await res.json();
const failed = post.targets.filter((t) => t.status === "failed");
if (failed.length > 0) {
// Retry only these accountIds, with a NEW idempotency key.
console.warn(failed.map((t) => `${t.platform}: ${t.error}`));
}