---
title: "/posts/{post_id}"
method: PATCH
path: "/projects/{project_id}/posts/{post_id}"
tags: ["Posts"]
---

# /posts/{post_id}

`PATCH /projects/{project_id}/posts/{post_id}`

## Request

- Base URL: `https://api.productbyte.com/v1`
- URL: `https://api.productbyte.com/v1/projects/{project_id}/posts/{post_id}`
- Auth: HTTP bearer

Edits a post that has not published yet — a draft, a failed post, or a scheduled one.

A scheduled post can also be **moved**: send `scheduled_at` to change when it goes out, which re-arms it. Content edits work the same either way. A post that has published or is publishing can no longer be edited; retract or delete it instead.

Send `campaign_id` to reassign the post, or `null` to unassign it. Omitted fields are left unchanged.

Requires the `posts:write` scope.

## Path parameters

- `project_id` string, required: The project the post belongs to.
- `post_id` string, required: The post to edit.

## Request body

- object
  - `copy` string: Replacement text.
  - `replies` object[]: Replaces the whole comment list. Send `[]` to remove every comment.
    - `copy` string, required: The comment text. Must not be empty.
    - `delay_seconds` integer: Wait after the previous item publishes, in seconds. At most 30 days.
  - `scheduled_at` string, date-time: Move when a scheduled post publishes. Must be in the future. Only meaningful for a post that is already scheduled — a draft carries its intended time instead.
  - `campaign_id` string, nullable: Reassign the post. Pass a campaign id from `/campaigns`, or `null` to unassign it. Omit to leave the assignment alone.
  - `auto_delete_after_seconds` integer: Replacement auto-delete delay. Whole minutes, 60 seconds minimum.
  - `settings` object: How this post publishes. Merged group by group, like the fields beside it: send `meta` to change the Instagram settings and `tiktok` is left as it was. Send an empty group — `"meta": {}` — to clear one.
    - `link_url` string: Destination URL. X shows it as a call to action on media and a Pin opens it; other channels ignore it.
    - `meta` object: Instagram and Facebook Page settings. A Reel cover and per-image alt text are set in ProductByte rather than here: both are keyed by internal asset ids this API does not expose.
      - `mode` 'feed_post' | 'story_post' | 'reel_post', required: Which Instagram surface to publish to. A Facebook Page takes `feed_post` only. A single video on `feed_post` publishes as a Reel — Instagram has no other container for it.
      - `title` string: Headline for a Facebook Page video. Ignored elsewhere.
      - `share_to_feed` boolean: Reels only. `false` keeps the Reel out of your profile feed, leaving it in the Reels tab.
      - `trial_reel` boolean: Reels only. Publishes to non-followers first. Accounts Instagram finds ineligible publish an ordinary Reel instead, reported back on the post.
      - `ai_generated` boolean: Discloses AI use. Instagram requires it for photorealistic video.
      - `collaborators` string[]: Up to 3 public Instagram usernames, without the leading @, invited to co-author. Instagram does not allow these on a trial reel or a Story.
    - `tiktok` object: TikTok settings.
      - `title` string: Title for the TikTok post. At most 90 characters.
      - `direct_post` object: Publishes straight to TikTok instead of sending the video to the creator’s inbox. Only on a `draft`. TikTok requires the creator to see its consent terms — the Branded Content Policy and Music Usage Confirmation — and to choose from the privacy options their account currently offers. An API call cannot show them either, so a Direct Post is prepared here and published from ProductByte, where those screens exist. Sending this with `publish_type` of `scheduled` or `immediate` is refused.
        - `privacy_level` 'PUBLIC_TO_EVERYONE' | 'MUTUAL_FOLLOW_FRIENDS' | 'FOLLOWER_OF_CREATOR' | 'SELF_ONLY', required: Who can see the post. Required, and must be one the creator currently allows.
        - `allow_comment` boolean, required: Whether viewers may comment.
        - `allow_duet` boolean: Video only.
        - `allow_stitch` boolean: Video only.
        - `auto_add_music` boolean: Photo posts only.
        - `is_aigc` boolean: Discloses AI-generated content.
        - `your_brand` boolean: The post promotes your own brand.
        - `branded_content` boolean: The post promotes a third party. Cannot be combined with `SELF_ONLY`.
    - `pinterest` object: Pinterest settings. Required on a Pinterest channel: every Pin goes on a board.
      - `board_id` string, required: The board the Pin goes on, one of the account’s boards.
      - `title` string: The Pin title. At most 100 characters.
      - `alt_text` string: What the picture shows, for screen readers. At most 500 characters.

## Response `200`

The updated post.

- object
  - `id` string, required: Identifier for this post.
  - `channel_id` string, required: The channel it publishes to.
  - `campaign_id` string: The campaign it belongs to. Absent when the post is unassigned — posts still need a home internally, but that grouping is bookkeeping and is never reported as a campaign.
  - `status` 'draft' | 'scheduled' | 'publishing' | 'published' | 'failed' | 'deleted', required: Where the post actually got to. Poll this to learn the outcome.
  - `copy` string, required: The text published alongside the media.
  - `scheduled_at` string, date-time: When it publishes, if it is scheduled.
  - `published_at` string, date-time: When it published, once it has.
  - `permalink` string: Link to the published post, when the provider gives one.
  - `updated_at` string, date-time, required: When the post last changed. Pass the newest one back as `updated_since` to poll for what changed.
  - `replies` object[]: Comments queued under this post, in the order they publish. Absent when there are none.
    - `id` string, required: Identifier for this reply.
    - `copy` string, required: The comment text.
    - `delay_seconds` integer: Wait after the previous item published.
    - `status` 'pending' | 'publishing' | 'published' | 'failed' | 'skipped', required: Where this reply got to. `skipped` means the chain stopped before reaching it.
    - `published_at` string, date-time: When it published, once it has.
  - `settings` object: How this post publishes, as stored. Covers only what this API accepts — a post made in ProductByte may carry more, such as a Reel cover. `link_url` is the effective link: a campaign’s UTM tags are applied to it, so it can differ from the one sent.
    - `link_url` string: Destination URL. X shows it as a call to action on media and a Pin opens it; other channels ignore it.
    - `meta` object: Instagram and Facebook Page settings. A Reel cover and per-image alt text are set in ProductByte rather than here: both are keyed by internal asset ids this API does not expose.
      - `mode` 'feed_post' | 'story_post' | 'reel_post', required: Which Instagram surface to publish to. A Facebook Page takes `feed_post` only. A single video on `feed_post` publishes as a Reel — Instagram has no other container for it.
      - `title` string: Headline for a Facebook Page video. Ignored elsewhere.
      - `share_to_feed` boolean: Reels only. `false` keeps the Reel out of your profile feed, leaving it in the Reels tab.
      - `trial_reel` boolean: Reels only. Publishes to non-followers first. Accounts Instagram finds ineligible publish an ordinary Reel instead, reported back on the post.
      - `ai_generated` boolean: Discloses AI use. Instagram requires it for photorealistic video.
      - `collaborators` string[]: Up to 3 public Instagram usernames, without the leading @, invited to co-author. Instagram does not allow these on a trial reel or a Story.
    - `tiktok` object: TikTok settings.
      - `title` string: Title for the TikTok post. At most 90 characters.
      - `direct_post` object: Publishes straight to TikTok instead of sending the video to the creator’s inbox. Only on a `draft`. TikTok requires the creator to see its consent terms — the Branded Content Policy and Music Usage Confirmation — and to choose from the privacy options their account currently offers. An API call cannot show them either, so a Direct Post is prepared here and published from ProductByte, where those screens exist. Sending this with `publish_type` of `scheduled` or `immediate` is refused.
        - `privacy_level` 'PUBLIC_TO_EVERYONE' | 'MUTUAL_FOLLOW_FRIENDS' | 'FOLLOWER_OF_CREATOR' | 'SELF_ONLY', required: Who can see the post. Required, and must be one the creator currently allows.
        - `allow_comment` boolean, required: Whether viewers may comment.
        - `allow_duet` boolean: Video only.
        - `allow_stitch` boolean: Video only.
        - `auto_add_music` boolean: Photo posts only.
        - `is_aigc` boolean: Discloses AI-generated content.
        - `your_brand` boolean: The post promotes your own brand.
        - `branded_content` boolean: The post promotes a third party. Cannot be combined with `SELF_ONLY`.
    - `pinterest` object: Pinterest settings. Required on a Pinterest channel: every Pin goes on a board.
      - `board_id` string, required: The board the Pin goes on, one of the account’s boards.
      - `title` string: The Pin title. At most 100 characters.
      - `alt_text` string: What the picture shows, for screen readers. At most 500 characters.

## Other responses

- `400`: The body is invalid (`API_REQUEST_INVALID`).
- `401`: Missing, unknown, revoked, or expired key (`API_KEY_UNAUTHORIZED`).
- `403`: The key lacks `posts:write`, or the project is outside its allowlist.
- `404`: No such post in this project (`API_POST_NOT_FOUND`).
- `409`: The post has published and can no longer be edited (`API_POST_NOT_EDITABLE`), or `scheduled_at` was sent for a post that is not scheduled (`API_POST_NOT_RESCHEDULABLE`).
- `422`: The channel cannot publish comments (`API_REPLIES_UNSUPPORTED`) or auto-delete (`API_AUTO_DELETE_UNSUPPORTED`).
- `429`: Too many requests for this key (`API_RATE_LIMITED`). Back off and retry; `Retry-After` gives the window length.

---

[API](https://skmtc.dev/productbyte/apis/productbyte-api.md) · [All operations](https://skmtc.dev/productbyte/apis/productbyte-api/llms.txt) · [OpenAPI document](https://skmtc.dev/productbyte/apis/productbyte-api/revisions/e44332d6b9c6?raw)
