# Publish posts

> Drafts and schedules, one post to many accounts, approvals, per-network settings and TikTok consent.

A post is one piece of content with one or more **targets**: the accounts it publishes to. Each target has its own status, and can have its own time and settings.

## Create a draft

```bash
curl https://api.nowscale.com/v1/posts \
  -H "Authorization: Bearer $NOWSCALE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 6f1c2e0a-2f6b-4b55-9d3f-0c6c1a6c9f11" \
  -d '{
    "project_id": "PROJECT_ID",
    "title": "Behind the scenes",
    "caption": "How we shot the new collection.",
    "media_ids": ["MEDIA_ID"],
    "targets": [{ "account_id": "YOUTUBE_ACCOUNT_ID" }, { "account_id": "INSTAGRAM_ACCOUNT_ID" }]
  }'
```

Without `scheduled_at` the post stays a draft. `media_ids` come from [media uploads](/media); the first item leads. `alt_text` sets alt text per media id.

## Schedule

Add `scheduled_at` for every target, or set it per target:

```json
{
  "project_id": "PROJECT_ID",
  "media_ids": ["MEDIA_ID"],
  "scheduled_at": "2026-12-01T15:00:00Z",
  "targets": [
    { "account_id": "YOUTUBE_ACCOUNT_ID" },
    { "account_id": "TIKTOK_ACCOUNT_ID", "scheduled_at": "2026-12-01T18:00:00Z" }
  ]
}
```

Scheduling checks everything the app checks: each network's rules for the media, your plan's publication limit for that month, and the time. Schedules work in whole minutes, like the app's picker: a time before the start of the next minute (UTC) keeps the post as a draft when it has content. `draft: true` keeps a dated post as a draft.

When a dated post is saved as a draft instead, the create or update response says why in `draft_reason`: `schedule_passed` for a time that came too soon, `publication_limit` when the plan's publication limit is reached, `project_restricted` for an archived Project or one over the plan, `network_locked`, `network_feature_locked` or `network_account_limit` when the plan does not include that network, feature or account, and `limit_reached` for any other limit. It is `null` when the post was saved as you asked, and it appears only in that response.

To publish at once, create the post and call `POST /v1/posts/{post_id}/publish`.

## Approvals

Posts follow the Project's approval policy, as in the app. A key without the `posts:publish` permission never schedules directly: its dated posts wait for review, whoever owns the key. With `posts:publish`, the policy decides (owners and admins never need review).

Send a draft for review with `POST /v1/posts/{post_id}/review`, and decide with `/review/approve` or `/review/reject` (the `reviews:write` permission). Send `expected_revision` to make sure you approve the version you checked.

## Change, unschedule, delete

- `PATCH /v1/posts/{post_id}` changes only the fields you send. `targets` and `media_ids` replace the whole list.
- `POST /v1/posts/{post_id}/unschedule` moves a scheduled post back to drafts.
- `POST /v1/posts/{post_id}/duplicate` copies a post into a new draft.
- `DELETE /v1/posts/{post_id}` deletes it. Copies already on networks are removed where the network allows; the post shows `deleting` until that is done.

## Network settings

`network_settings` applies settings to every target on a network; a target's `settings` override them for that account. Names are the composer's options in snake_case. For example:

```json
{
  "network_settings": {
    "youtube": { "category_id": "22", "made_for_kids": false, "tags": ["tutorial"], "visibility": "public" },
    "tiktok": { "privacy_level": "PUBLIC_TO_EVERYONE", "disable_comment": false, "consent": true },
    "instagram": { "surface": "reel", "share_to_feed": true }
  }
}
```

`GET /v1/networks` lists each network's rules: media kinds, file types and sizes, duration, visibility choices and placements.

## TikTok

TikTok requires the creator to choose a privacy level from their own account's options and to consent before each post. When your product schedules TikTok posts:

1. Show the creator's TikTok account and let them pick `privacy_level` from the options TikTok gives that account. There is no default.
2. Show TikTok's consent text and only then send `"consent": true` in the TikTok settings (for the network or the target).

A scheduled TikTok target without consent answers `400 tiktok_consent_required`. Integrators are bound by the TikTok terms in the API Terms.

## Follow a post

Each target in `targets` has a `status` (`pending`, `uploading`, `uploaded`, `published`, `failed`), the network's `external_id` once known, and an `error_code` when it failed. The post's own `status` sums them up: `published`, `partial` or `failed` once every target is done. [Webhooks](/webhooks) tell you when that happens.
