---
title: Bulk scheduling
description: Schedule hundreds of posts safely, with idempotent retries.
sidebar:
  icon: layers
---

The bulk endpoint creates up to 100 drafts or scheduled posts per call. Each call is idempotent, so a timeout never creates duplicates: send the same request again.

| | |
| --- | --- |
| REST | `POST`, `GET`, `PATCH` on `https://www.brainyshorts.com/api/cli/posts/bulk` |
| MCP | `brainy_create_posts_bulk`, `brainy_get_post_batch`, `brainy_update_posts_bulk` |
| Auth | API key with `cli:access`, or an MCP token with `brainy:write` (`brainy:read` for status) |

## How idempotency works

- Pick one UUID `batch_id` for the whole import.
- Give every item a stable `item_key` (letters, digits, `.`, `_`, `:`, `-`, up to 100 characters), such as `2027-01-01-tip-001`.
- Send at most 100 items per call. A year of 1,000 posts is ten calls that share one `batch_id`.
- Resending an identical item is a no-op. Resending a **different** item under an existing key returns `409`, because that is almost always a bug.

Bulk accepts only `draft` and `schedule`. It never publishes immediately.

## Create a batch

Media comes from completed managed uploads, referenced by `asset_id`. See the [Quickstart](/quickstart) for the upload steps.

```bash
curl -s -X POST "https://www.brainyshorts.com/api/cli/posts/bulk" \
  -H "Authorization: Bearer $BRAINY_API_KEY" \
  -H "Content-Type: application/json" \
  -d @batch.json
```

```json
{
  "batch_id": "11111111-1111-4111-8111-111111111111",
  "items": [
    {
      "item_key": "2027-01-01-tip-001",
      "title": "One precise tip",
      "caption": "Ask for the verification evidence you care about.",
      "media_type": "video",
      "media": [{ "asset_id": "22222222-2222-4222-8222-222222222222" }],
      "targets": [
        { "social_account_id": "33333333-3333-4333-8333-333333333333", "platform": "instagram" }
      ],
      "action": "schedule",
      "scheduled_at": "2027-01-01T18:00:00Z"
    }
  ]
}
```

| Item field | Rules |
| --- | --- |
| `item_key` | Unique within the batch |
| `title` | 1–120 characters |
| `caption` | 1–2,200 characters |
| `media_type` | `image` (1 asset), `carousel` (2–10), or `video` (1) |
| `media` | `[{ asset_id, text?, aspect_ratio? }]` |
| `targets` | Up to 12; each account at most once per item |
| `action` | `draft` or `schedule` |
| `scheduled_at` | Required for `schedule`; not allowed for `draft` |

The response is `201` and includes `warnings` and a `next` hint. When posts are scheduled less than five minutes apart, a warning says so. They stay scheduled, but delivery can queue behind earlier posts, so leave five minutes or more between them where you can.

## Check a batch

```bash
curl -s "https://www.brainyshorts.com/api/cli/posts/bulk?batch_id=$BATCH&offset=0&limit=100" \
  -H "Authorization: Bearer $BRAINY_API_KEY"
```

The response has `total`, `has_more`, and one entry per item. Page with `offset` until `has_more` is `false`.

## Update scheduled posts

`PATCH /posts/bulk` takes `{ "updates": [...] }` with up to 100 entries. Each entry has a `post_id` and the same fields as a single [`PATCH /posts`](/api#editing-and-deleting): `caption`, `scheduled_at`, `add_targets`, or `status: "draft"`.

The response reports `updated_count`, `failed_count`, and a per-post `results` list. Updates aren't all-or-nothing, so retry only the `post_id` values that failed.
