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

> ## Agent Instructions
> Base URL: https://api.social-api.ai/v1. Send your API key in the Authorization header: Authorization: Bearer <your API key>.
> Every error response from /v1 is JSON: { "error": { "code", "message", "meta" (optional) }, "request_id" }. Branch on error.code; use error.message only for logs.
> A 429 response carries a Retry-After header, in seconds, when the limit has a known wait.
> Paginated list endpoints return next_cursor, at the top level or inside pagination (see /guides/pagination). Pass it as the cursor query parameter to get the next page. An absent or empty next_cursor means you have the last page.
> Treat every ID as an opaque string: do not parse it or assume a format.
> Support differs by platform and by operation. Check /platforms/overview before assuming an operation works on a platform. An unsupported operation returns 501 with error.code resource.not_supported.

# Schedule posts

> Schedule a post to publish at a future time on every platform, edit or cancel it, and learn how posting caps and failures affect a scheduled post.

Scheduling publishes a post at a time you choose. Send `scheduled_at` with `POST /v1/posts`, and SocialAPI holds the post and sends it to each target when the time arrives. Every platform accepts `scheduled_at`: SocialAPI does the waiting, not the platform.

A scheduled post costs 1 post credit when you create it, whatever the number of targets. Editing and cancelling cost nothing. See [Plans and usage](/guides/plans#what-counts-as-a-post-or-interaction).

## Endpoints

| Method | Path | Description |
| - | - | - |
| `POST` | `/v1/posts` | Schedule a post with `scheduled_at` |
| `GET` | `/v1/posts?status=scheduled` | List scheduled posts |
| `PATCH` | `/v1/posts/{pid}` | Change the time, content, or targets of a scheduled post |
| `POST` | `/v1/posts/{pid}/publish` | Publish a scheduled post now |
| `DELETE` | `/v1/posts/{pid}` | Cancel a scheduled post |

## Schedule a post

Set `scheduled_at` to an RFC 3339 time in the future and name at least one target:

```bash theme={null}
curl -X POST https://api.social-api.ai/v1/posts \
  -H "Authorization: Bearer $SOCAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Launching today: https://example.com/launch",
    "scheduled_at": "2026-10-20T09:00:00Z",
    "targets": [
      {"account_id": "acc_01HZ9X8B3C4D5F6G7H9J2K1M"},
      {"account_id": "acc_01HZ9X4T6B8C2D5F7G9H1J3K", "page_id": "sapi_page_01HZ9X5V7C9D3E6G8H1J4K2M"}
    ]
  }'
```

Response (HTTP 201):

```json theme={null}
{
  "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "text": "Launching today: https://example.com/launch",
  "status": "scheduled",
  "scheduled_at": "2026-10-20T09:00:00Z",
  "hidden": false,
  "retry_count": 0,
  "created_at": "2026-10-13T09:00:00Z",
  "updated_at": "2026-10-13T09:00:00Z",
  "targets": [
    {
      "account_id": "acc_01HZ9X8B3C4D5F6G7H9J2K1M",
      "platform": "threads",
      "status": "pending",
      "scheduled_at": "2026-10-20T09:00:00Z"
    },
    {
      "account_id": "acc_01HZ9X4T6B8C2D5F7G9H1J3K",
      "page_id": "sapi_page_01HZ9X5V7C9D3E6G8H1J4K2M",
      "platform": "facebook",
      "status": "pending",
      "scheduled_at": "2026-10-20T09:00:00Z"
    }
  ]
}
```

The post is `scheduled` and each target is `pending`. SocialAPI sends `post.scheduled` when the post is created.

* **Time:** with at least one target, a `scheduled_at` in the past returns `400 validation.field_invalid`. With no targets, the post is saved as a draft. A value that is not RFC 3339 returns `400 validation.field_invalid`. Include the UTC offset or `Z`.
* **One time per target:** a target can set its own `scheduled_at`, which overrides the post's. The post's `scheduled_at` is the earliest of them.
* **Without targets:** a post with no targets is saved as a draft, even with `scheduled_at`.
* **Both flags:** when you send `publish_now` and `scheduled_at` together, the post is scheduled.
* **Validation:** SocialAPI validates the post when you schedule it, so a violation returns `400 publishing.validation_failed` immediately, and validates the post again when its time arrives.
* **Allowance:** at the post allowance, scheduling returns `429 validation.post_limit_exhausted` and creates nothing.

## Stagger targets

Add `stagger` to publish the targets one after another, with a random gap between them, instead of all at the same time. Set `min_seconds` and `max_seconds` in whole seconds:

```bash theme={null}
curl -X POST https://api.social-api.ai/v1/posts \
  -H "Authorization: Bearer $SOCAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Launching today: https://example.com/launch",
    "scheduled_at": "2026-10-20T10:00:00Z",
    "stagger": {"min_seconds": 60, "max_seconds": 300},
    "targets": [
      {"account_id": "acc_01HZ9X8B3C4D5F6G7H9J2K1M"},
      {"account_id": "acc_01HZ9X4T6B8C2D5F7G9H1J3K"},
      {"account_id": "acc_01HZ9X6W8D1E4F7H9J2K5L3N"},
      {"account_id": "acc_01HZ9X7Y9F2G5H8J1K4M6P4Q"}
    ]
  }'
```

The first target publishes at `scheduled_at`. Each next target publishes a random delay between `min_seconds` and `max_seconds` after the previous one, in the order the targets are listed. With 4 targets and a 60 to 300 second gap, the times are, for example, 10:00:00, 10:02:41, 10:03:52, and 10:08:30. Read each target's planned time from `targets[].scheduled_at` with `GET /v1/posts/{pid}`.

* **Immediate start:** with `publish_now: true` and no `scheduled_at`, the first target publishes now and the others follow. The response still has `status: "scheduled"`, because the later targets are still waiting.
* **Fixed gap:** set `min_seconds` equal to `max_seconds`.
* **Explicit target times:** a target that sets its own `scheduled_at` keeps that time and is left out of the sequence. It does not move the targets after it.
* **Required:** a post that would be saved as a draft (no `scheduled_at` and no `publish_now`) cannot use `stagger`. It returns `400 validation.field_invalid` with `meta.field` set to `stagger`.
* **Bounds:** `0 <= min_seconds <= max_seconds <= 86400`. A value outside them returns `400 validation.field_invalid`.
* **Cost:** 1 post credit for the whole post.
* **Results:** the post settles through the usual `post.published`, `post.partial`, and `post.failed` events.
* **Rescheduling:** `PATCH /v1/posts/{pid}` with a post-level `scheduled_at` moves every target to that single time and removes the spread. To keep a spread, send a `scheduled_at` on each target.
* **Where it applies:** `stagger` applies only to `POST /v1/posts`. `PATCH /v1/posts/{pid}`, `POST /v1/posts/{pid}/publish`, and `POST /v1/posts/validate` ignore it, and CSV import has no column for it.

## How a scheduled post moves through statuses

```mermaid theme={null}
flowchart LR
  A[POST /posts with scheduled_at] --> B[scheduled]
  B -->|PATCH scheduled_at| B
  B -->|DELETE| D[deleted]
  B -->|scheduled time reached| C[targets publishing]
  B -->|POST /posts/pid/publish| C
  C --> E[published, partial, or failed]
  E -->|failed or partial: POST /posts/pid/retry| C
```

A scheduled post keeps the status `scheduled` while it waits for its time and while SocialAPI sends it, until every target has settled. While SocialAPI sends it, each target shows `publishing`. The post then becomes `published`, `partial`, or `failed`, and SocialAPI sends one `post.published`, `post.partial`, or `post.failed` event. The statuses and the per-target fields are in [Track post delivery](/guides/delivery#post-status).

## Edit or reschedule

`PATCH /v1/posts/{pid}` changes a `scheduled` post. A new time or target list takes effect at once.

```bash theme={null}
curl -X PATCH https://api.social-api.ai/v1/posts/7c9e6679-7425-40de-944b-e07fc1f90ae7 \
  -H "Authorization: Bearer $SOCAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{"scheduled_at": "2026-10-21T14:00:00Z"}'
```

The response is HTTP 200 with the updated post. SocialAPI sends `post.updated` with `changed_fields`. An edit to the content or targets runs validation again. A post in any status other than `draft`, `scheduled`, or `failed` returns `409 post.state_invalid`. [Publish a post](/guides/publishing#edit-a-post-before-it-publishes) lists every editable field.

## Publish now

`POST /v1/posts/{pid}/publish` sends a scheduled post immediately. It costs 1 post credit again, on top of the credit the scheduling cost. The response is HTTP 201 and the post is `publishing`. A post that is `published`, `partial`, or `failed` returns `409 post.state_invalid`.

## Cancel a scheduled post

`DELETE /v1/posts/{pid}` cancels a `scheduled` post: SocialAPI removes the post and sends nothing. The response is HTTP 200 with `{"success": true, "deleted": true}`, and SocialAPI sends `post.deleted`. The post credit is not returned. Deleting a post that is already `publishing` returns `409 post.state_invalid`. See [Delete a post](/guides/delivery#delete-a-post).

## Posting caps can delay a scheduled post

SocialAPI caps how many posts one account publishes per hour and per 24 hours, by platform. A scheduled post that reaches a cap is not failed. The target stays `pending`, and SocialAPI publishes it when the cap window clears, so the post goes out later than `scheduled_at`. The caps and their values are in [Rate limits](/guides/rate-limits#posting-velocity-caps). Immediate publishes that reach a cap return `429 publishing.velocity_limit` instead.

## When a scheduled post fails

SocialAPI makes one delivery attempt per target at the scheduled time. A failed attempt is final: the target becomes `failed` with its `error`, the post becomes `failed` or `partial`, and SocialAPI sends one `post.failed` or `post.partial` event. Nothing is re-sent automatically. A scheduled post's credit is not returned when it fails.

Common causes are a disconnected account (`publishing.delivery.account_load_failed`), an account that lost the `posts.write` [permission](/guides/permissions) (`account.permission_missing`), content that stopped passing validation (`validation.publish`), and a platform refusal (`platform.{platform}.*`). The causes are in [Track post delivery](/guides/delivery#target-errors).

To send a failed post again, fix the cause, optionally edit the post, and call `POST /v1/posts/{pid}/retry`. It re-sends only the failed targets and costs 1 post credit.

A scheduled post still publishes when your SocialAPI account is past due. See [Past-due accounts](/guides/plans#past-due-accounts).

## YouTube has 2 schedulers

On YouTube, `scheduled_at` makes SocialAPI upload the video at that time, and `platform_data.youtube.publish_at` uploads it now and lets YouTube make it public later. See [Schedule a YouTube post](/platforms/youtube/publishing#schedule-a-post).

## Read scheduling support from the API

`GET /v1/posts/validate` returns `scheduling.supported` for each platform it covers. It is `true` for each of them. See [Publish a post](/guides/publishing#validate-before-you-publish).

## Scopes

| Scope | Grants |
| - | - |
| `posts:read` | List scheduled posts |
| `posts:write` | Schedule, edit, publish now, and cancel posts |

## Use from an AI agent

| Tool | What it does |
| - | - |
| `social_api_create_post` | Schedules a post with `scheduled_at`, optionally spreading the targets with `stagger` |
| `social_api_list_posts` | Lists posts, including `status=scheduled` |
| `social_api_update_post` | Changes the time or content of a scheduled post |
| `social_api_publish_post` | Publishes a scheduled post now |
| `social_api_delete_post` | Cancels a scheduled post |

## Related

* [Publish a post](/guides/publishing): fields every platform shares
* [Track post delivery](/guides/delivery): post statuses, target errors, and retry
* [Rate limits](/guides/rate-limits): the posting caps that hold a scheduled post
* [Plans and usage](/guides/plans): what scheduling costs
* [Webhook events](/guides/webhook-events): `post.scheduled` and the settle events


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.