API reference · Posts
Publish a saved draft
POST /v1/posts/{id}/publish
Publish or schedule in place with the original ID and immutable sourceDraftId. Content, campaign, assetMetadata and platform options are preserved. Supply expectedSnapshot from GET to fence every stored field. Identical completed approvals return the existing result without reposting; a claimed or uncertain operation returns 409. Approval-required agents cannot approve themselves. Personal drafts remain editable after every destination fails; approved submissions retain a failed outcome for reconciliation.
Request
Authenticate with a bearer API key. Agents calling over MCP authorise with OAuth instead and never handle the key.
curl -X POST https://api.postlake.dev/v1/posts/{id}/publish \
-H "Authorization: Bearer $POSTLAKE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"scheduledAt":"…","timezone":"…","accounts":["…"],"expectedSnapshot":"…"}'Parameters
| Field | Type | Required | What it is |
|---|---|---|---|
id | string | Yes | In the URL. |
Body
| Field | Type | Required | What it is |
|---|---|---|---|
scheduledAt | string or null | No | Publish at this time instead. Omit to keep whatever time the draft was carrying (or send now if it had none). Send null to clear the draft's time and publish immediately. |
timezone | string | No | IANA timezone (e.g. Europe/London) for a naive scheduledAt. |
accounts | array of string | No | Publish to these accounts instead of the draft's own destinations. |
expectedSnapshot | string | No | Full-state snapshot from GET. Any intervening edit rejects approval with 409. |
profile | string | No | Publish to every account under this profile instead of the draft's own destinations. |
platforms | array | No | Optional filter applied to the resolved destinations. |
Response
Published or scheduled (201).
Example
"…"What it costs
One credit per network the post actually reaches. X uses dedicated rates: 8 credits for text and 90 for a post with a link. Nothing is charged for a target that fails, and a post refused by pre-flight never touches the ledger at all.
Publishing endpoints are limited to 60 requests a minute per account, inside a wider ceiling of 600 a minute across the whole API. Every response carries X-RateLimit-Remaining and X-RateLimit-Reset.
Calling this from an agent
Agents do not call REST. They call tools. Over the hosted MCP server this operation is create_post, and the agent authorises with OAuth so your API key is never pasted into a chat or seen by the model. The reply comes back in the same normalised shape you see above, which is what lets an agent reason about it without a per-network branch.
You control what any one agent may do with it: which brands it may act for, which networks it may reach, how much it may do in a day, and whether it may spend credits you bought up front. See the MCP server.
Errors
Every failure uses one shape: a stable type, a granular code, the field at fault in param, and a plain-language fix. An agent can act on it without a person reading the message. See Errors and retries.
Idempotency-Key.Common questions
Can an AI agent do this without the REST API?
Yes. Over MCP the same job is the create_post tool. The agent authorises with OAuth, so no API key is pasted into a chat or seen by the model, and the answer comes back in the same normalised shape.
Is it safe to retry this call?
Do not automatically repeat a write after a timeout unless that endpoint explicitly documents idempotency. First read the resulting state; a second request could repeat the action.
What happens when it fails?
You get one error shape: a stable type, a granular code you can branch on, the offending field in param, and a fix written so an agent can correct itself rather than stop. Full list on Errors and retries.