Composer

Never gets rejected

Every write validates every channel against its platform's real rules and returns errors with real numbers and machine fixes — one ready flag is the only gate, and autofix repairs what it safely can.

Inklate validates every channel against the real rules of its platform — length limits, media counts, aspect ratios, required titles — on every write and read. There is no separate check step: create, update, get, and the dry-run validate all return the same per-channel verdict, so a post that says it’s ready cannot be rejected at publish time. The fit check runs the exact ladder the publish worker runs.

The Inklate composer flagging a failing channel: Instagram requires media for this format, so scheduling is blocked until it's fixed

What the fit check covers

For each channel, an ordered ladder where the first refusal wins:

  1. Reachability — is the channel connected and its grant active? A disconnected channel or expired token refuses here (code auth) and needs a reconnect, not a retry.
  2. Scopes — does the connection carry the permissions the format needs?
  3. Content — does the adapted text and media fit the platform’s rules: length, item counts, media count, aspect ratio, mixing?
  4. Org policy — banned terms and blocked links, if your organization configured them; quiet hours once a schedule time exists.
  5. Publish windows — a provider’s own daily quota, checked last: it’s about how much already went out, not whether this draft fits.

Errors carry real numbers and machine fixes

Each channel entry in the response reports ready plus errors[]. Every error names a stable code, the field to change (content, channel, media, options, or schedule), a human message with the actual numbers (“truncated at 280”, not “too long”), and machine fixes[] where a repair exists. Soft issues arrive as warnings[] — “dropped 2 images” when a story carried more than a format allows — and don’t block publishing.

The full catalog of codes, fields, and fix parameters is on Errors and fixes.

The five fix kinds

A fix is a machine-readable repair — the composer renders it as a one-click button, and the API can apply it for you:

FixWhen it appearsWhat it does
trim_to_foldText is over the format’s limitTrims the text to fit the limit.
split_to_threadAn over-length post on a provider with threadsReshapes the post into a thread, losslessly.
rebalance_threadToo many or too-long thread itemsCaps the item count and trims each item.
crop_toAn image doesn’t match a required aspect ratioCrops a derivative to the required ratio.
set_titleA video format requires a title and none is setAdds a title within the provider’s length limit.

Only a content refusal carries fixes; a policy refusal (a banned term, a blocked link) names the rule but has no automatic repair — you edit the copy yourself.

Autofix — repairs applied for you

autofix (default on for API writes) applies suggested fixes server-side during the write and reports them in fixes_applied, so an agent’s post fits on the first call. Two kinds are deliberately never auto-applied: split_to_thread changes the channel’s shape (that stays your decision, via per_channel format), and crop_to needs an explicit media decision. Pass autofix: false (the composer does) to keep manual control and apply fixes yourself.

An applied fix marks that channel copy Edited. No channel is ever re-adapted when the story changes later — Synced channels merely go Stale — so a fix is never silently discarded; see Write once, native everywhere.

ready is the only gate

Top-level ready is the AND of every channel’s verdict plus media readiness — the server’s single publishability signal. No client re-derives it. The consequences:

  • A draft with errors saves. Saving work-in-progress is always legitimate; the response tells you what’s left to fix.
  • Only arming refuses — atomically. Setting a schedule (or publishing) a post that isn’t ready is refused and the whole write rolls back, so a partially-armed post cannot exist. The refusal carries the post it refused, so the per-channel errors[] and fixes[] are on the failed call itself — nothing to re-send to find out why. Send the write again without schedule when you want the draft kept.
  • The dry run is the same verdict. POST /posts/validate (CLI: inklate posts validate) returns the identical response shape for an inline draft or a stored post id, persisting nothing.

Beside the verdict: approval and media readiness

Two gates sit next to the fit check rather than inside it, because neither is a content problem with a channel:

  • Media readiness — an attached asset still processing holds the publish until it finishes; a failed asset (upload broke, rejected, or flagged by a scan) must be removed. Both are reported on the response’s media[] entries. See Images and video.
  • Approval — when your organization requires approval, a post arms only once approved; the response’s approval block carries the state. See Approvals.

A failing fit check also blocks approval requests — a reviewer is never asked to approve a version that can’t ship.