# Schedule a post

Drafts, scheduling to several platforms, choosing accounts, editing and deleting.


## Draft or scheduled

`POST /posts` without `scheduledDatetime` saves a **draft**. With a future `scheduledDatetime` (ISO 8601, ideally with a `Z` or offset) it is **scheduled**: one row per platform is queued and published at that time. Nothing is ever published immediately by the API.

```json
{
  "caption": "New feature: scheduled posts from your terminal.",
  "platforms": ["x", "bluesky", { "platform": "linkedin", "accountId": "0b5f2c1a-..." }],
  "scheduledDatetime": "2030-01-15T09:00:00Z",
  "tags": ["launch"]
}
```

A platform given as a plain string uses the most recently connected account of that platform. Pass an object with `accountId` (from `GET /accounts`) to choose a specific one.

## Rules worth knowing

- The caption must fit each platform ([limits](/docs/platforms)). A platform that rejects a post reports a plain-language error in `GET /posts/:id/results`.
- Instagram, YouTube and Pinterest need an image or video: attach one with `mediaId` ([upload media](/docs/guides/upload-media)).
- Blog platforms (Dev.to, Hashnode, WordPress) take articles, not short posts: pass `options.blog.title` and a markdown caption. Do not mix blog and social platforms in one post.
- Accounts that need reconnecting are rejected with `needs_reconnect` rather than failing later.
- Your plan's monthly scheduling limit applies. `GET /usage` shows how much is left.

## Edit, reschedule, schedule a draft

`PATCH /posts/:id` changes the caption, title, tags or time. Sending `scheduledDatetime` for a **draft** schedules it (optionally with `platforms`). A scheduled post can be edited until about 90 seconds before it publishes; after that, or once any platform has started, the API answers `409 not_editable`.

## Delete

`DELETE /posts/:id` removes a draft or a scheduled post that has not started publishing. Published posts must be deleted on the platform itself.

## First comment

`options.first_comment` posts a reply right after the post goes live (for example the link, so the post itself stays clean). It works on X, Mastodon, Bluesky and Reddit; on other platforms it is skipped. The outcome is in `GET /posts/:id/results` as `first_comment` (`posted`, `failed` or `unsupported`). A failed first comment never affects the post itself.

