---
title: "Create, schedule, queue or publish a post"
method: POST
path: "/posts"
tags: ["Posts"]
---

# Create, schedule, queue or publish a post

`POST /posts`

## Request

- Base URL: `https://preflight.social/v1`
- URL: `https://preflight.social/v1/posts`
- Auth: HTTP bearer

Checked against every target network first; a refusal is 422 validation_failed with the issues. Scope posts:write for a draft, posts:publish for anything that goes out. Send an Idempotency-Key header: a retried request returns the first post instead of creating a second.

## Headers

- `Idempotency-Key` string

## Request body

- PostInput
  - `content` string: The text. On YouTube it is the description unless youtube.description is set.
  - `linkUrl` string, uri
  - `mediaIds` string[]: Files in order; they must be ready.
  - `altTexts` string[]: Alt text per file, same order as mediaIds.
  - `scheduledAt` string, date-time: One instant for every channel. Up to five minutes in the past counts as now; older is refused with 400 scheduled_in_past (send publishNow to publish at once).
  - `scheduledLocal` string: The same wall-clock time read in each channel's own zone.
  - `queue` boolean: Each channel takes its next free slot from its posting schedule.
  - `publishNow` boolean
  - `saveAsDraft` boolean: Park it without a time. Needs only posts:write.
  - `targets` TargetInput[], required
    - `platform` 'youtube' | 'tiktok' | 'instagram' | 'facebook' | 'threads' | 'twitter' | 'linkedin' | 'pinterest' | 'bluesky' | 'mastodon' | 'telegram' | 'discord' | 'tumblr', required: A network's name. twitter (X) is text-only and not offered to new accounts.
    - `accountId` string, uuid: Which connected account, when the workspace has several for one network.
    - `options` object: Per-network settings: youtube.title, tags, categoryId, privacy, playlistId, thumbnailMediaId, subtitles, firstComment; tiktok.privacy (required), allowComments, asDraft; instagram.placement (feed, reel, story), shareToFeed, collaborators; facebook.asReel, firstComment; threads.poll, thread; pinterest.boardId (required), title; bluesky/mastodon/twitter.thread; mastodon.visibility, spoilerText; discord.threadName; tumblr.tags; linkedin.firstComment; caption to override the text for this network. See /documentation#options.

## Response `200`

The Idempotency-Key matched an earlier post, which is returned instead.

- Post
  - `id` string, uuid
  - `status` 'draft' | 'scheduled' | 'publishing' | 'done' | 'canceled'
  - `content` string
  - `linkUrl` string, nullable
  - `mediaIds` string[]
  - `altTexts` string[]
  - `scheduledAt` string, date-time, nullable
  - `approvalState` string, nullable: pending, approved or changes when a client approval link exists.
  - `createdAt` string, date-time
  - `updatedAt` string, date-time
  - `targets` Target[]
    - `id` string, uuid
    - `platform` 'youtube' | 'tiktok' | 'instagram' | 'facebook' | 'threads' | 'twitter' | 'linkedin' | 'pinterest' | 'bluesky' | 'mastodon' | 'telegram' | 'discord' | 'tumblr': A network's name. twitter (X) is text-only and not offered to new accounts.
    - `accountId` string, uuid
    - `status` 'pending' | 'publishing' | 'published' | 'failed' | 'skipped'
    - `remoteId` string, nullable
    - `remoteUrl` string, uri, nullable
    - `publishedAt` string, date-time, nullable
    - `error` string, nullable
    - `errorCode` string, nullable
    - `errorPermanent` boolean: Retrying cannot succeed without changing something.
    - `attempts` integer
    - `nextAttemptAt` string, date-time, nullable
    - `canEditRemote` boolean
    - `canDeleteRemote` boolean
    - `options` object
    - `metrics` object, nullable: The latest figures, with fetchedAt.

## Other responses

- `201`: Created.
- `400`: The body did not validate (invalid_request; field says which).
- `401`: Missing, expired or unrecognised key.
- `402`: The plan's allowance: post_limit, upload_limit, file_too_large, channel_limit, api_not_on_plan, ai_limit, ai_not_in_plan. Carries limit and upgradeTo.
- `403`: The key lacks the scope for this call.
- `404`: No such post, file or account in this workspace.
- `409`: Not possible in the current state, or the network does not allow it.
- `422`: A network would refuse it (validation_failed, with issues).

---

[API](https://skmtc.dev/preflight/apis/preflight-api.md) · [All operations](https://skmtc.dev/preflight/apis/preflight-api/llms.txt) · [OpenAPI document](https://skmtc.dev/preflight/apis/preflight-api/revisions/45ae7944ce71?raw)
