Reference
Preflight API
The Preflight API is a REST API for publishing to social networks from your own code: upload a video, write a post, schedule it for every network at once — YouTube, TikTok, Instagram, Facebook, Threads, X, LinkedIn, Pinterest, Bluesky, Mastodon, Telegram, Discord and Tumblr — read its figures and take it down again, over HTTP, from your own server. Every post is checked against each network's rules before it is accepted. The same workspace is open to AI assistants through an MCP server.
https://preflight.social/v1
The same API as a schema: openapi.json (OpenAPI 3.1), for client generators and anything that reads a schema before prose. For assistants, the MCP server.
The reference
- AuthenticationHow a Preflight API key is created, what its scopes allow, how long it lasts, and the one endpoint that needs no key.
- Media uploadsUpload a picture or video for a post: hand over a URL the server fetches, or PUT the bytes to signed links, single or multipart. Limits, retention and the media object.
- PostsCreate a post for several networks in one call, schedule it, queue it or publish now; read what happened on each network; change or delete it. Every post endpoint.
- Network optionsEvery field a target's options can carry: YouTube, TikTok, Instagram, Facebook, Pinterest, Threads, Mastodon, Telegram, Discord, X, LinkedIn, Bluesky and Tumblr.
- WebhooksSubscribe an https address to post.published, post.failed and account.needs_reconnect, send a test delivery, verify the signature, handle retries.
- Errors and limitsEvery error code the Preflight API returns, by status, what a 402 carries, and the rate limits per address and per key.
- MCP serverA hosted MCP server for Claude, ChatGPT, Cursor and Claude Code: tools to validate, schedule and publish posts to twelve networks. OAuth or an API key.
Quickstart: a first post in five calls
Everything below is one curl each. The full bodies, every option and every error are on the pages above.
1Create an API key
Under Settings → API keys, on any plan. Pick the scopes it needs — publishing a post needs
posts:publishand uploading a filemedia:write— and send it as a bearer token on every call.curl https://preflight.social/v1/oauth/accounts \ -H "Authorization: Bearer sk_live_…" → 200 { "data": [ { "id": "b4b5…", "platform": "youtube", "displayName": "Weekly Mix", "timezone": "Europe/Prague" }, … ] }2Upload the file
Hand over a public URL and the server fetches it, or declare the size and type and PUT the bytes to the signed link it returns. Poll
GET /v1/media/{id}untilstatusisready.curl https://preflight.social/v1/media \ -H "Authorization: Bearer sk_live_…" \ -H "Content-Type: application/json" \ -d '{ "kind": "video", "sourceUrl": "https://your-generator.example/render/abc.mp4", "filename": "weekly-mix.mp4", "durationSeconds": 3600, "width": 1920, "height": 1080 }' → 202 { "id": "9f3c…", "status": "ingesting", … }3Check it against every network
POST /v1/platforms/validatetakes the same body as creating a post and returns the issues each network would raise — a caption too long for X, a video TikTok refuses — without creating anything. Errors block publishing; warnings do not.curl https://preflight.social/v1/platforms/validate \ -H "Authorization: Bearer sk_live_…" \ -H "Content-Type: application/json" \ -d '{ "content": "Weekly Mix #14 is up.", "mediaIds": ["9f3c…"], "targets": [ { "platform": "youtube", "options": { "title": "Weekly Mix #14" } }, { "platform": "facebook" } ] }' → 200 { "ok": true, "issues": [] }4Create the post
One call, as many networks as you name, with an
Idempotency-Keyso a retried request cannot publish twice.scheduledAtschedules it;publishNowsends it straight out;queuetakes each channel's next free slot.curl https://preflight.social/v1/posts \ -H "Authorization: Bearer sk_live_…" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: 7d0c2c9e-…" \ -d '{ "content": "Weekly Mix #14 is up.", "mediaIds": ["9f3c…"], "scheduledAt": "2026-10-12T09:00:00Z", "targets": [ { "platform": "youtube", "options": { "title": "Weekly Mix #14", "privacy": "public" } }, { "platform": "facebook" } ] }' → 201 { "id": "a1c0…", "status": "scheduled", "targets": [ … ], "issues": [] }5Read what happened
A created post is not a published post: the call returns as soon as the work is queued. Read
targets[].status,remoteUrlandmetricson the post, or subscribe a webhook topost.publishedandpost.failed.account.needs_reconnectsays when a channel has to be connected again.curl https://preflight.social/v1/posts/a1c0… \ -H "Authorization: Bearer sk_live_…" → 200 { "id": "a1c0…", "status": "done", "targets": [ { "platform": "youtube", "status": "published", "remoteUrl": "https://youtu.be/…", "metrics": { "views": 1200, … } }, … ] }
Authentication
Every request carries an API key as a bearer token. A key belongs to one workspace, is shown once, and carries scopes — posts:read, posts:write, posts:publish, media:read, media:write, webhooks:read, webhooks:write or *. Call it from a server, never from a browser. GET /v1/platforms, the capability sheet, needs no key.
Files
A file is uploaded first and named in a post by its id: hand over a URL the server fetches, or PUT the bytes to signed links — one for a file up to 16 MB, 16 MB parts above that. Send the duration and dimensions of a video so a network's refusal is predicted before the upload. Limits by plan, how long files are kept, Google Drive, and the media object.
Creating a post
POST /v1/posts with content, mediaIds and a list of targets; when it goes out is scheduledAt, scheduledLocal, queue, publishNow or saveAsDraft. Several accounts on one network, a different caption per network, carousels and alt text, threads, AI captions and the dry run.
Per-network options
What goes in a target's options: YouTube's title, privacy, tags, thumbnail, playlist, subtitles and native scheduling; TikTok's privacy level and photo posts; Instagram and Facebook placements, reels and first comments; Pinterest boards; Threads, Mastodon, Telegram, Discord, X, LinkedIn, Bluesky and Tumblr.
Reading posts
GET /v1/posts pages through every post with its per-network status, link and figures; PATCH changes a post that has not started and DELETE removes it here. A created post is not a published post — read targets[].status to find out what happened.
Endpoints
Every address, grouped by what it touches: posts and one network's copy of a post (metrics, comments, editing and deleting the live post) on the posts page; files on the media page; webhooks on theirs. The whole list as a schema is openapi.json.
Webhooks
Subscribe an https address to post.published (once per target, when it is live), post.failed (once retrying has stopped) and account.needs_reconnect (once when a channel stops working). Each delivery is signed with HMAC-SHA256 over the timestamp and the raw body in x-preflight-signature-v2, and retried five times unless answered with a 2xx within 10 seconds. POST /v1/workspace/webhooks/{id}/test sends a signed sample on demand.
MCP server
The same workspace is available to AI assistants over the Model Context Protocol at https://preflight.social/mcp. Claude and other clients connect with the address alone and sign in through OAuth; anything else can send an API key as a bearer token. A key sees only the tools its scopes allow. How to connect Claude, ChatGPT, Cursor and Claude Code, and every tool with what it does, is on the MCP server page.
Reading (posts:read): list_channels, list_posts (filters and a cursor), get_post, validate_post, next_queue_times, post_performance, post_insights, analytics_summary, audience, list_comments, list_pinterest_boards, list_youtube_playlists, tiktok_creator_info and get_usage (the plan and what is left of it this month). Files: create_media_upload, complete_media_upload (media:write) and get_media (media:read).
Drafts (posts:write): draft_post, update_post on a draft, and delete_post. Everything that decides what goes out or what is live also needs posts:publish: create_post, update_post on a scheduled post or to give a draft a time, retry_post, edit_published_post, delete_published_post, act_on_comment, create_youtube_playlist and create_pinterest_board.
create_post needs an idempotencyKey, and a reply through act_on_comment one too. Publishing at once needs confirmPublishNow; deleting a post or taking it down from a network needs confirmDelete. A TikTok post that is not a draft needs tiktok.privacy. Settings a network does not take come back as warnings rather than being dropped silently, and a refusal for a plan limit keeps its limit and upgradeTo.
Errors and limits
Failures return a stable code and a message meant to be read by a person; a 402 carries the plan's limit and the plan that would allow it in upgradeTo. Requests are limited to 600 a minute per address, with tighter limits per key on creating files, AI, account lookups, webhooks and MCP.
POST /v1/posts returns as soon as the work is queued. Read targets[].status, or subscribe to a webhook, to find out what actually happened.Questions: info@preflight.social. The same API as a schema: openapi.json (OpenAPI 3.1).
Write it once. Let the rules be our problem.
Preflight checks every post against each network's rules before it leaves, then publishes it to twelve networks. Free plan, no card.