Skip to content

POST /posts

Creates a post for one or more accounts. MCP tool: create_post. Background: Approvals, Scheduling, First comments and threads.

Terminal window
curl -X POST https://botdoor.co/api/v1/posts -H "Authorization: Bearer $BOTDOOR_KEY" -H "Content-Type: application/json" \
-H "Idempotency-Key: launch-2026-10-12" \
-d '{"content": "Fresh sourdough at 7am", "accountIds": ["2ae8…"], "mediaIds": ["9b1c…"],
"scheduledFor": "2026-10-12T07:00:00+11:00", "firstComment": "Order: https://acme.example", "dryRun": true}'
Field Type Notes
accountIds string[] Required. Ids from /accounts
content string Post text
mediaIds string[] From /media. Several make a carousel. mediaId (one string) also works
dryRun boolean Validate only. Nothing is stored, sent or counted
scheduledFor string ISO 8601 with offset, under a year ahead. Omit to post now
requireApproval boolean true always waits. false can’t skip an asks-first key
firstComment string Reply from the same account about 10 s after it’s live. Put links here
thread string[] Follow-up posts (X, Threads, Bluesky). thread[0] is the first reply
firstReply string Alias for a one-item thread. Not with thread
poll object {options, durationMinutes, question}. X or LinkedIn, no media. question is LinkedIn only
cover object Video cover: {mediaId} (image upload) or {offsetMs} (frame)
tiktokAiGenerated boolean TikTok: label as AI-generated

Header Idempotency-Key: a retry with the same key never posts twice.

  • 200 dry run: {"dryRun": true, "valid": true, "warnings": [], "requireApproval": true, "wouldPost": {…}}
  • 201 created: {"post": {…}} with status needs_approval, scheduled, publishing, published or failed. Shape: GET /posts/{id}.
  • 200 with replayed: true: same Idempotency-Key as an earlier post.
Status Code Meaning
400 validation_failed A field is missing or malformed. See details.fields
400 invalid_date, scheduled_in_past, scheduled_too_far Bad scheduledFor
400 media_required Instagram, TikTok, YouTube and Pinterest need media
400 thread_unsupported, poll_unsupported, first_comment_unsupported, cover_unsupported A target can’t do that
400 tiktok_privacy_conflict, tiktok_ai_unsupported TikTok settings conflict
400 upstream_rejected The network refused the content
403 plan_feature_unavailable, post_limit_reached Plan rule (X, 30 posts a month on Free)
404 account_not_found, media_not_found An id isn’t in this workspace
409 no_accounts_connected, account_needs_reconnection Connect or reconnect first
409 media_expired Upload is over 7 days old
409 duplicate_content Same text was just posted to that account
409 tiktok_cannot_post TikTok says the creator can’t post now. Retryable
422 idempotency_key_reused Same key, different body

Common questions

How do I check a post without publishing it?
Send dryRun: true. You get valid, warnings and exactly what would be posted, and it doesn't count toward the monthly limit.
Why did my post stop at needs_approval?
Your key asks first, or you sent requireApproval: true. A signed-in person approves it in the app.
Can I post to several networks at once?
Yes. Put several accountIds in one post. Each target gets its own status.
Where should links go?
In firstComment, so the main post isn't penalised for a link and the link sits right under it.
Is scheduledFor in my timezone?
It's whatever offset you send. Always include one, such as +11:00 or Z.