posts_create
One call for one or many channels (`channels` takes ids or provider names, mixed).
One call for one or many channels (channels takes ids or provider names, mixed). Copy goes in content as markdown — the only way to write it; each channel’s copy is adapted automatically, and per_channel overrides one channel’s content, format, or options without touching the others. scheduled_at decides the mode: omitted saves a draft; a future instant (ISO-8601 with offset, or relative shorthand “30m”/“2h”/“3d”/“1w”) books it; “now” publishes immediately. Arming refuses atomically when the post is not ready — nothing is saved, and the refusal ITSELF carries the post it refused as JSON below the error line, so read the per-channel errors[] and fixes[] there rather than re-sending the write without scheduled_at. The response carries per-channel validation: each channel entry’s errors[] name a code, the field to change, a human message with the real numbers, and a machine fix where one exists. ready is the server’s ONLY publishability signal — a draft with errors saves fine; only arming refuses. autofix (default true) applies suggested fixes server-side and reports them in fixes_applied.
Input
| Field | Type | Required | Description |
|---|---|---|---|
organization | string | no | Organization slug to act in (see organizations_list). Optional: API keys are bound to one organization; OAuth connections default to your active organization. |
content | string | no | The shared copy as markdown: **bold**, *italic*, [label](url), # heading, - bullet, blank lines between paragraphs. Markdown that contains no markup is posted exactly as typed — handles, URLs, and snake_case are safe — and \* shows a literal delimiter. Each channel’s copy is adapted from this unless per_channel overrides it. Optional only for a media-only post. |
channels | array | no | Target channels: channel ids from channels_list and/or provider names (“x”, “linkedin”), mixed. On update, when present it REPLACES the target set. A post response’s channels[] entries are accepted as-is. |
per_channel | object | no | Per-channel overrides keyed by channel id or provider name. A non-null value also ADDS that channel to the targets; on update, a null value ({“x”: null}) resets that channel to the shared content. Overriding one channel never touches the others. |
scheduled_at | string | no | When to publish. Omitted = save a draft. A future instant (ISO-8601 WITH a UTC offset, e.g. “2026-07-09T09:00:00+05:30”, or relative shorthand “30m”/“2h”/“3d”/“1w”) = scheduled. “now” = publish immediately. Naive local times are rejected — resolve the user’s timezone and send the offset explicitly. |
autofix | boolean | no | Apply suggested machine fixes server-side before the verdict (default true). Applied fixes are reported in fixes_applied and mark that channel’s copy authored. |
media | array | no | Ordered media to attach, in render order: file ids (file_…) from files_upload and/or public https:// URLs (fetched and stored server-side — the response echoes each url’s file id; poll files_get until ready before publishing). Each target channel must support the media (see capabilities.media). A post response’s media[] entries are accepted as-is. |
labels | array | no | Label ids to set on the post — replaces the full set when present. A post response’s labels[] entries are accepted as-is. |
campaign | any | no | Campaign id to file the post under; null detaches it. |
idempotency_key | string | no | Client-chosen dedupe key. Retrying with the same key returns the original result instead of creating/publishing twice. Pick one per logical action. |
Set idempotency_key on retries: a repeated call with the same key returns the original result instead of acting twice. Use it whenever you cannot tell whether a timed-out call landed.
Result
JSON on success. A refusal comes back as an error prefixed with its code (NOT_FOUND, FORBIDDEN, TOO_MANY_REQUESTS, …) and a message written to be acted on — read it before retrying.
The same operation elsewhere
This tool and the REST operation postsCreate and the CLI command inklate posts create run the same guarded procedure the dashboard uses — same permissions, same validation, same tenant isolation.
billing_ink
This organization's AI-credit wallet (balance + monthly grant) plus the published Ink rate card — the flat price of each AI action — so an agent can plan within the balance before acting rather than discovering the ceil…
posts_update
Re-validates and returns the same response as posts_create.