> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sapt.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Scheduling posts

> Put a post on the calendar, then edit, move or cancel it.

## Schedule a post

Give it a `scheduledFor` and a `timezone` instead of `publishNow`.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.sapt.ai/socials/posts/$PROJECT_ID" \
    -H "Authorization: ApiKey $SAPT_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "socialAccountId": "9f1c2f7a-4c9e-4a1d-9d0e-8a5b6c7d8e9f",
      "platform": "instagram",
      "mediaType": "REELS",
      "caption": "New drop, Friday.",
      "uploadedHandles": [{ "stagingId": "stg_01JQ…", "ext": "mp4" }],
      "scheduledFor": "2026-09-11T14:00:00Z",
      "timezone": "America/New_York"
    }'
  ```

  ```typescript TypeScript theme={null}
  const res = await fetch(`https://api.sapt.ai/socials/posts/${projectId}`, {
    method: 'POST',
    headers: {
      Authorization: `ApiKey ${process.env.SAPT_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      socialAccountId,
      platform: 'instagram',
      mediaType: 'REELS',
      caption: 'New drop, Friday.',
      uploadedHandles: [handle],
      scheduledFor: '2026-09-11T14:00:00Z',
      timezone: 'America/New_York',
    }),
  })

  const { data } = await res.json()
  console.log(data.post.id, data.post.status) // → "scheduled"
  ```
</CodeGroup>

### The scheduling window

`scheduledFor` must land **between 10 minutes and 75 days from now**. Outside
that range the API returns `400` immediately, rather than uploading your media
and letting the platform reject it afterwards.

`timezone` is an IANA name (`America/New_York`, `Europe/Berlin`). It does not
shift `scheduledFor` — that instant is absolute. It records the timezone the
post was authored in so the calendar renders the time a human meant.

<Note>
  `STORIES` cannot be scheduled. Stories must go out with `publishNow: true`.
</Note>

## List the calendar

```bash theme={null}
curl "https://api.sapt.ai/socials/posts/$PROJECT_ID?status=scheduled" \
  -H "Authorization: ApiKey $SAPT_API_KEY"
```

| Query                   | Effect                                                                          |
| ----------------------- | ------------------------------------------------------------------------------- |
| `status`                | Filter to one status — `draft`, `scheduled`, `queued`, `published`, `failed`, … |
| `startDate` / `endDate` | Restrict to a window, by `scheduledFor`.                                        |
| `accountId`             | Only posts for one connected account.                                           |

## Edit a scheduled post

```bash theme={null}
curl -X PUT "https://api.sapt.ai/socials/posts/$PROJECT_ID/$POST_ID" \
  -H "Authorization: ApiKey $SAPT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "caption": "New drop — Friday 9am.",
    "scheduledFor": "2026-09-11T13:00:00Z"
  }'
```

Editable fields are `caption`, `scheduledFor`, `timezone` and `status` (between
`draft` and `scheduled`). Media is changed through the
[media endpoints](/docs/mintlify/social/media), not here.

A post can be edited while its status is `draft`, `scheduled`, `queued` or
`failed`. `queued` still counts — the publish queue re-reads the row at delivery
and drops a message whose time no longer matches, so moving a queued post is
safe. Once it is `uploading` or `publishing`, the platform owns it and edits are
rejected.

## Drafts

Create a post with neither `publishNow` nor `scheduledFor` and it lands as a
`draft` — on the calendar, not going anywhere. Promote it later by setting a
time:

```json theme={null}
{ "status": "scheduled", "scheduledFor": "2026-09-12T16:00:00Z" }
```

## Cancel

```bash theme={null}
curl -X DELETE "https://api.sapt.ai/socials/posts/$PROJECT_ID/$POST_ID" \
  -H "Authorization: ApiKey $SAPT_API_KEY"
```

Deleting removes the post and its staged media. It does **not** retract anything
already published — for that, use
[Delete published Facebook post](/api-reference/socials/delete-published-facebook-post).
