# Posts

> 8 endpoints: list posts, retrieve a post, create a post, update a post, unschedule a post, publish a post now, duplicate a post, delete a post.

- [List posts](#list-posts): `GET /v1/posts`
- [Retrieve a post](#retrieve-a-post): `GET /v1/posts/{post_id}`
- [Create a post](#create-a-post): `POST /v1/posts`
- [Update a post](#update-a-post): `PATCH /v1/posts/{post_id}`
- [Unschedule a post](#unschedule-a-post): `POST /v1/posts/{post_id}/unschedule`
- [Publish a post now](#publish-a-post-now): `POST /v1/posts/{post_id}/publish`
- [Duplicate a post](#duplicate-a-post): `POST /v1/posts/{post_id}/duplicate`
- [Delete a post](#delete-a-post): `DELETE /v1/posts/{post_id}`

### List posts

`GET /v1/posts`

Lists posts, newest first, with each network target's status.

Permission: `posts:read`

#### Query parameters

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `limit` | integer | No | Items per page, 1 to 100. (1 to 100, default 25) |
| `cursor` | string | No | The next_cursor of the previous page. (up to 512 characters) |
| `project_id` | string | No |  (up to 128 characters) |
| `status` | `draft`, `scheduled`, `publishing`, `published`, `partial`, `failed` | No |  |
| `scheduled_from` | string | No | Only posts scheduled at or after this time (ISO 8601). |
| `scheduled_to` | string | No | Only posts scheduled before this time (ISO 8601). |

#### Response

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `object` | `"list"` | Yes |  |
| `data` | array of object | Yes |  |
| `data[].object` | `"post"` | Yes |  |
| `data[].id` | string | Yes |  (up to 128 characters) |
| `data[].project_id` | string or null | Yes |  |
| `data[].status` | `draft`, `scheduled`, `publishing`, `published`, `partial`, `failed`, `deleting` | Yes |  |
| `data[].review_status` | `not_required`, `draft`, `in_review`, `approved`, `rejected` | Yes |  |
| `data[].title` | string or null | Yes |  |
| `data[].caption` | string or null | Yes |  |
| `data[].visibility` | string | Yes |  |
| `data[].scheduled_at` | string or null | Yes |  |
| `data[].published_at` | string or null | Yes |  |
| `data[].created_at` | string | Yes | ISO 8601 date and time, UTC. |
| `data[].updated_at` | string | Yes | ISO 8601 date and time, UTC. |
| `data[].targets` | array of object | Yes |  |
| `has_more` | boolean | Yes |  |
| `next_cursor` | string or null | Yes |  |

```bash
curl https://api.nowscale.com/v1/posts \
  -H "Authorization: Bearer $NOWSCALE_API_KEY"
```

### Retrieve a post

`GET /v1/posts/{post_id}`

Returns one post with each network target's status.

Permission: `posts:read`

#### Path parameters

| Name | Description |
| --- | --- |
| `post_id` | The post's id. |

#### Response

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `object` | `"post"` | Yes |  |
| `id` | string | Yes |  (up to 128 characters) |
| `project_id` | string or null | Yes |  |
| `status` | `draft`, `scheduled`, `publishing`, `published`, `partial`, `failed`, `deleting` | Yes |  |
| `review_status` | `not_required`, `draft`, `in_review`, `approved`, `rejected` | Yes |  |
| `title` | string or null | Yes |  |
| `caption` | string or null | Yes |  |
| `visibility` | string | Yes |  |
| `scheduled_at` | string or null | Yes |  |
| `published_at` | string or null | Yes |  |
| `created_at` | string | Yes | ISO 8601 date and time, UTC. |
| `updated_at` | string | Yes | ISO 8601 date and time, UTC. |
| `targets` | array of object | Yes |  |
| `targets[].object` | `"post_target"` | Yes |  |
| `targets[].id` | string | Yes |  (up to 128 characters) |
| `targets[].account_id` | string | Yes |  (up to 128 characters) |
| `targets[].network` | `youtube`, `tiktok`, `instagram`, `facebook`, `threads`, `bluesky`, `mastodon`, `pinterest`, `telegram`, `twitch`, `x`, `discord` | Yes |  |
| `targets[].status` | `pending`, `uploading`, `uploaded`, `published`, `failed` | Yes |  |
| `targets[].stage` | string | Yes |  |
| `targets[].external_id` | string or null | Yes |  |
| `targets[].error_code` | string or null | Yes |  |
| `targets[].scheduled_at` | string or null | Yes |  |

```bash
curl https://api.nowscale.com/v1/posts/POST_ID \
  -H "Authorization: Bearer $NOWSCALE_API_KEY"
```

### Create a post

`POST /v1/posts`

Creates a draft or a scheduled post in a Project. Scheduling needs the posts:publish permission and follows the Project's approval policy: without it, or when the policy asks, the post waits for review. Send an Idempotency-Key so a retry never creates a second post.

Permission: `posts:write` · Accepts `Idempotency-Key` · Answers `201`

#### Body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `project_id` | string | Yes |  (up to 128 characters) |
| `title` | string | No |  (up to 150 characters) |
| `caption` | string | No |  (up to 5000 characters) |
| `media_ids` | array of string | No | Ordered media from POST /v1/media. The first item leads. |
| `alt_text` | object | No | Alt text by media id. |
| `visibility` | `public`, `unlisted`, `private` | No |  |
| `targets` | array of object | No | The accounts this post publishes to. |
| `targets[].account_id` | string | Yes |  (up to 128 characters) |
| `targets[].scheduled_at` | string or null | No | When this account publishes. Defaults to the post's scheduled_at. |
| `targets[].settings` | object | No | This account's own settings, overriding network_settings for its network. |
| `scheduled_at` | string or null | No | When every target without its own scheduled_at publishes. Null or absent keeps a draft. |
| `draft` | boolean | No | Keep the post as a draft even when it has a schedule. |
| `network_settings` | object | No | Settings per network, applied to every target on that network. |

#### Response

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `object` | `"post"` | Yes |  |
| `id` | string | Yes |  (up to 128 characters) |
| `project_id` | string or null | Yes |  |
| `status` | `draft`, `scheduled`, `publishing`, `published`, `partial`, `failed`, `deleting` | Yes |  |
| `review_status` | `not_required`, `draft`, `in_review`, `approved`, `rejected` | Yes |  |
| `title` | string or null | Yes |  |
| `caption` | string or null | Yes |  |
| `visibility` | string | Yes |  |
| `scheduled_at` | string or null | Yes |  |
| `published_at` | string or null | Yes |  |
| `created_at` | string | Yes | ISO 8601 date and time, UTC. |
| `updated_at` | string | Yes | ISO 8601 date and time, UTC. |
| `targets` | array of object | Yes |  |
| `targets[].object` | `"post_target"` | Yes |  |
| `targets[].id` | string | Yes |  (up to 128 characters) |
| `targets[].account_id` | string | Yes |  (up to 128 characters) |
| `targets[].network` | `youtube`, `tiktok`, `instagram`, `facebook`, `threads`, `bluesky`, `mastodon`, `pinterest`, `telegram`, `twitch`, `x`, `discord` | Yes |  |
| `targets[].status` | `pending`, `uploading`, `uploaded`, `published`, `failed` | Yes |  |
| `targets[].stage` | string | Yes |  |
| `targets[].external_id` | string or null | Yes |  |
| `targets[].error_code` | string or null | Yes |  |
| `targets[].scheduled_at` | string or null | Yes |  |
| `draft_reason` | `schedule_passed`, `publication_limit`, `project_restricted`, `network_locked`, `network_feature_locked`, `network_account_limit`, `limit_reached` or null | Yes | null when the post was saved as asked. Otherwise why a dated post was saved as a draft: schedule_passed (the time was before the start of the next minute), publication_limit (the plan's publication limit), project_restricted (the Project is archived or over the plan), network_locked, network_feature_locked or network_account_limit (the plan does not include that network, feature or account), limit_reached (another limit). Only in this response. |

```bash
curl -X POST https://api.nowscale.com/v1/posts \
  -H "Authorization: Bearer $NOWSCALE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{ ... }'
```

### Update a post

`PATCH /v1/posts/{post_id}`

Changes a post's text, media, targets, schedule or network settings. Fields you leave out keep their value; targets and media_ids replace the whole list.

Permission: `posts:write`

#### Path parameters

| Name | Description |
| --- | --- |
| `post_id` | The post's id. |

#### Body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `title` | string | No |  (up to 150 characters) |
| `caption` | string | No |  (up to 5000 characters) |
| `media_ids` | array of string | No | Ordered media from POST /v1/media. The first item leads. |
| `alt_text` | object | No | Alt text by media id. |
| `visibility` | `public`, `unlisted`, `private` | No |  |
| `targets` | array of object | No | The accounts this post publishes to. |
| `targets[].account_id` | string | Yes |  (up to 128 characters) |
| `targets[].scheduled_at` | string or null | No | When this account publishes. Defaults to the post's scheduled_at. |
| `targets[].settings` | object | No | This account's own settings, overriding network_settings for its network. |
| `scheduled_at` | string or null | No | When every target without its own scheduled_at publishes. Null or absent keeps a draft. |
| `draft` | boolean | No | Keep the post as a draft even when it has a schedule. |
| `network_settings` | object | No | Settings per network, applied to every target on that network. |

#### Response

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `object` | `"post"` | Yes |  |
| `id` | string | Yes |  (up to 128 characters) |
| `project_id` | string or null | Yes |  |
| `status` | `draft`, `scheduled`, `publishing`, `published`, `partial`, `failed`, `deleting` | Yes |  |
| `review_status` | `not_required`, `draft`, `in_review`, `approved`, `rejected` | Yes |  |
| `title` | string or null | Yes |  |
| `caption` | string or null | Yes |  |
| `visibility` | string | Yes |  |
| `scheduled_at` | string or null | Yes |  |
| `published_at` | string or null | Yes |  |
| `created_at` | string | Yes | ISO 8601 date and time, UTC. |
| `updated_at` | string | Yes | ISO 8601 date and time, UTC. |
| `targets` | array of object | Yes |  |
| `targets[].object` | `"post_target"` | Yes |  |
| `targets[].id` | string | Yes |  (up to 128 characters) |
| `targets[].account_id` | string | Yes |  (up to 128 characters) |
| `targets[].network` | `youtube`, `tiktok`, `instagram`, `facebook`, `threads`, `bluesky`, `mastodon`, `pinterest`, `telegram`, `twitch`, `x`, `discord` | Yes |  |
| `targets[].status` | `pending`, `uploading`, `uploaded`, `published`, `failed` | Yes |  |
| `targets[].stage` | string | Yes |  |
| `targets[].external_id` | string or null | Yes |  |
| `targets[].error_code` | string or null | Yes |  |
| `targets[].scheduled_at` | string or null | Yes |  |
| `draft_reason` | `schedule_passed`, `publication_limit`, `project_restricted`, `network_locked`, `network_feature_locked`, `network_account_limit`, `limit_reached` or null | Yes | null when the post was saved as asked. Otherwise why a dated post was saved as a draft: schedule_passed (the time was before the start of the next minute), publication_limit (the plan's publication limit), project_restricted (the Project is archived or over the plan), network_locked, network_feature_locked or network_account_limit (the plan does not include that network, feature or account), limit_reached (another limit). Only in this response. |

```bash
curl -X PATCH https://api.nowscale.com/v1/posts/POST_ID \
  -H "Authorization: Bearer $NOWSCALE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ ... }'
```

### Unschedule a post

`POST /v1/posts/{post_id}/unschedule`

Moves a scheduled post back to drafts. Targets already published stay published.

Permission: `posts:write`

#### Path parameters

| Name | Description |
| --- | --- |
| `post_id` | The post's id. |

#### Response

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `object` | `"post"` | Yes |  |
| `id` | string | Yes |  (up to 128 characters) |
| `project_id` | string or null | Yes |  |
| `status` | `draft`, `scheduled`, `publishing`, `published`, `partial`, `failed`, `deleting` | Yes |  |
| `review_status` | `not_required`, `draft`, `in_review`, `approved`, `rejected` | Yes |  |
| `title` | string or null | Yes |  |
| `caption` | string or null | Yes |  |
| `visibility` | string | Yes |  |
| `scheduled_at` | string or null | Yes |  |
| `published_at` | string or null | Yes |  |
| `created_at` | string | Yes | ISO 8601 date and time, UTC. |
| `updated_at` | string | Yes | ISO 8601 date and time, UTC. |
| `targets` | array of object | Yes |  |
| `targets[].object` | `"post_target"` | Yes |  |
| `targets[].id` | string | Yes |  (up to 128 characters) |
| `targets[].account_id` | string | Yes |  (up to 128 characters) |
| `targets[].network` | `youtube`, `tiktok`, `instagram`, `facebook`, `threads`, `bluesky`, `mastodon`, `pinterest`, `telegram`, `twitch`, `x`, `discord` | Yes |  |
| `targets[].status` | `pending`, `uploading`, `uploaded`, `published`, `failed` | Yes |  |
| `targets[].stage` | string | Yes |  |
| `targets[].external_id` | string or null | Yes |  |
| `targets[].error_code` | string or null | Yes |  |
| `targets[].scheduled_at` | string or null | Yes |  |

```bash
curl -X POST https://api.nowscale.com/v1/posts/POST_ID/unschedule \
  -H "Authorization: Bearer $NOWSCALE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ ... }'
```

### Publish a post now

`POST /v1/posts/{post_id}/publish`

Starts publishing every pending target now. The post's status reports the outcome as each network answers.

Permission: `posts:publish` · Accepts `Idempotency-Key` · Answers `202`

#### Path parameters

| Name | Description |
| --- | --- |
| `post_id` | The post's id. |

#### Response

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `object` | `"post"` | Yes |  |
| `id` | string | Yes |  (up to 128 characters) |
| `project_id` | string or null | Yes |  |
| `status` | `draft`, `scheduled`, `publishing`, `published`, `partial`, `failed`, `deleting` | Yes |  |
| `review_status` | `not_required`, `draft`, `in_review`, `approved`, `rejected` | Yes |  |
| `title` | string or null | Yes |  |
| `caption` | string or null | Yes |  |
| `visibility` | string | Yes |  |
| `scheduled_at` | string or null | Yes |  |
| `published_at` | string or null | Yes |  |
| `created_at` | string | Yes | ISO 8601 date and time, UTC. |
| `updated_at` | string | Yes | ISO 8601 date and time, UTC. |
| `targets` | array of object | Yes |  |
| `targets[].object` | `"post_target"` | Yes |  |
| `targets[].id` | string | Yes |  (up to 128 characters) |
| `targets[].account_id` | string | Yes |  (up to 128 characters) |
| `targets[].network` | `youtube`, `tiktok`, `instagram`, `facebook`, `threads`, `bluesky`, `mastodon`, `pinterest`, `telegram`, `twitch`, `x`, `discord` | Yes |  |
| `targets[].status` | `pending`, `uploading`, `uploaded`, `published`, `failed` | Yes |  |
| `targets[].stage` | string | Yes |  |
| `targets[].external_id` | string or null | Yes |  |
| `targets[].error_code` | string or null | Yes |  |
| `targets[].scheduled_at` | string or null | Yes |  |

```bash
curl -X POST https://api.nowscale.com/v1/posts/POST_ID/publish \
  -H "Authorization: Bearer $NOWSCALE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{ ... }'
```

### Duplicate a post

`POST /v1/posts/{post_id}/duplicate`

Copies a post, its media and targets into a new draft in the same Project.

Permission: `posts:write` · Counts 5 requests · Accepts `Idempotency-Key` · Answers `201`

#### Path parameters

| Name | Description |
| --- | --- |
| `post_id` | The post's id. |

#### Response

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `object` | `"post"` | Yes |  |
| `id` | string | Yes |  (up to 128 characters) |
| `project_id` | string or null | Yes |  |
| `status` | `draft`, `scheduled`, `publishing`, `published`, `partial`, `failed`, `deleting` | Yes |  |
| `review_status` | `not_required`, `draft`, `in_review`, `approved`, `rejected` | Yes |  |
| `title` | string or null | Yes |  |
| `caption` | string or null | Yes |  |
| `visibility` | string | Yes |  |
| `scheduled_at` | string or null | Yes |  |
| `published_at` | string or null | Yes |  |
| `created_at` | string | Yes | ISO 8601 date and time, UTC. |
| `updated_at` | string | Yes | ISO 8601 date and time, UTC. |
| `targets` | array of object | Yes |  |
| `targets[].object` | `"post_target"` | Yes |  |
| `targets[].id` | string | Yes |  (up to 128 characters) |
| `targets[].account_id` | string | Yes |  (up to 128 characters) |
| `targets[].network` | `youtube`, `tiktok`, `instagram`, `facebook`, `threads`, `bluesky`, `mastodon`, `pinterest`, `telegram`, `twitch`, `x`, `discord` | Yes |  |
| `targets[].status` | `pending`, `uploading`, `uploaded`, `published`, `failed` | Yes |  |
| `targets[].stage` | string | Yes |  |
| `targets[].external_id` | string or null | Yes |  |
| `targets[].error_code` | string or null | Yes |  |
| `targets[].scheduled_at` | string or null | Yes |  |

```bash
curl -X POST https://api.nowscale.com/v1/posts/POST_ID/duplicate \
  -H "Authorization: Bearer $NOWSCALE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{ ... }'
```

### Delete a post

`DELETE /v1/posts/{post_id}`

Deletes a post. Copies NOWScale already placed on networks are removed where the network allows it; the post shows status deleting until that finishes.

Permission: `posts:delete` · Answers `202`

#### Path parameters

| Name | Description |
| --- | --- |
| `post_id` | The post's id. |

#### Response

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `object` | `"post"` | Yes |  |
| `id` | string | Yes |  (up to 128 characters) |
| `status` | `"deleting"` | Yes |  |

```bash
curl -X DELETE https://api.nowscale.com/v1/posts/POST_ID \
  -H "Authorization: Bearer $NOWSCALE_API_KEY"
```
