---
title: "Update a post"
method: PATCH
path: "/posts/{id}"
tags: ["Posts"]
---

# Update a post

`PATCH /posts/{id}`

## Path parameters

- `id` string, required

## Request body

- object
  - `content` object
  - `accounts` string[]
  - `type` 'post' | 'story' | 'reel' — Change post type (draft only)
  - `media` Media — unresolved $ref
  - `media_ids` Media — unresolved $ref
  - `media_urls` MediaUrls — unresolved $ref
  - `schedule_at` string, date-time — New publish time (ISO 8601, must be in the future). A draft becomes `scheduled`. A post that is waiting for approval keeps its `in_approval` status and only its time moves. Send `null` to unschedule back to `draft`.
  - `location_id` LocationId — unresolved $ref
  - `collaborators` Collaborators — unresolved $ref
  - `user_tags` UserTags — unresolved $ref
  - `pinterest` Pinterest — unresolved $ref
  - `youtube` Youtube — unresolved $ref
  - `instagram` Instagram — unresolved $ref
  - `tiktok` Tiktok — unresolved $ref
  - `x` X — unresolved $ref
  - `bluesky` Bluesky — unresolved $ref
  - `mastodon` Mastodon — unresolved $ref
  - `threads` Threads — unresolved $ref
  - `google_business` GoogleBusiness — unresolved $ref
  - `linkedin` Linkedin — unresolved $ref
  - `linkedin_page` LinkedinPage — unresolved $ref
  - `linkedin_poll` LinkedinPoll — unresolved $ref

## Response `200`

Post updated

- object
  - `data` Post
    - `id` string — Post ID
    - `status` 'draft' | 'in_approval' | 'scheduled' | 'posting' | 'published' | 'failed' | 'warning' | 'rejected' — `in_approval` = waiting for a reviewer in an approval workflow; PATCH /posts/{id} can still move its `schedule_at` without changing this status. `rejected` = an approver declined the post via POST /posts/{id}/reject; it will not be published. `posting` = a publish is in flight. `warning` = some platforms published and some failed (see `errors` for the failures, `published_urls` for the successes); retry the failures with POST /posts/{id}/retry. `failed` = every platform failed. NOTE: a failed post whose dashboard 'retry as new post' succeeded flips to `published` even though it has no `published_urls` of its own — check `retries` for the post that actually carries the live URLs.
    - `type` 'post' | 'story' | 'reel' — Post type. 'reel' media must be a video (MP4/MOV) — an image is rejected with 400 validation_error at schedule/publish; use 'post' to share an image. A 'story' carries 1 to 10 media items; every item is one slide and publishes as its own story, in order.
    - `story_slides` object — Stories only, after publishing. Per-platform list of the published slides in publish order. `published_urls` keeps the first slide's URL per platform; this field has every slide.
    - `content` object — Post content per platform
    - `accounts` string[] — Account IDs to post to
    - `media` object — Per-platform media object. Keys: default, instagram, facebook, etc. Each value is an array of {url, id, channel, alt?}.
    - `location_id` string — Instagram location tag (Facebook Place/Page ID), echoed back from the create/update request. Omitted when not set.
    - `collaborators` string[] — Instagram co-author usernames (the 'Collab' feature), echoed back from the create/update request. Omitted when none set.
    - `user_tags` object[] — Instagram photo user tags, echoed back from the create/update request. Omitted when none set.
      - `username` string
      - `x` number
      - `y` number
      - `image_index` integer
    - `schedule_at` string, date-time — Scheduled publish time (ISO 8601)
    - `app_url` string, uri — Deep link to open this post inside the OmniSocials app, correct for the environment (staging vs production). Draft, scheduled, and failed posts open in the composer; published posts open in the details view. Hand this to the user so they can click straight through to review a draft you just created.
    - `published_urls` object — Live URLs of the post on each platform after publishing. Keys are platform identifiers (`facebook`, `instagram`, `linkedin`, `linkedin_page`, `youtube`, `tiktok`, `pinterest`, `x`, `threads`, `bluesky`, `mastodon`, `google_business`). Only platforms that successfully published appear; failed platforms are omitted (see `errors`). Empty object `{}` while the post is still draft, scheduled, or processing.
    - `retry_of` string — Present when this post was created by the dashboard 'retry as new post' flow: the ID of the original failed post it retries. The live platform URLs are on THIS post's `published_urls`.
    - `retries` string[] — Present on a post that has been retried as a new post: the IDs of its retry posts (newest last). A `published` post with empty `published_urls` and `retries` set is a resolved failure — the actual publish lives on the retry post, so don't double-count it.
    - `created_at` string, date-time
    - `approval_status` 'none' | 'pending' | 'approved' | 'rejected', nullable — Approval workflow status. `none` = no approval workflow attached. `pending` = waiting on an approver (post `status` is `in_approval`); act on it with POST /posts/{id}/approve or /reject. `approved` / `rejected` = the workflow finished.
    - `errors` object, nullable — Per-platform user-friendly error messages, keyed by platform identifier (`facebook`, `instagram`, `linkedin`, `linkedin_page`, `youtube`, `tiktok`, `pinterest`, `x`, `threads`, `bluesky`, `mastodon`, `google_business`). Populated when `status` is `failed` or `warning`. Only platforms that failed appear; successful platforms are omitted (see `published_urls`). `null` while the post is still draft/scheduled/processing or every platform succeeded. A platform's entry is removed once a retry of it succeeds (via POST /posts/{id}/retry or the dashboard). Mirrors the per-platform error a user sees in the dashboard with a Retry button.
    - `source` string, nullable — Origin of post creation: web, api, mcp, workflow, zapier, make, n8n, etc.
    - `updated_at` string, date-time
    - `x` object, nullable — X (Twitter) options on the post. Includes per-publish settings (reply_settings, made_with_ai, paid_partnership) plus the canonical thread shape. Present when the post has X-specific data; omitted otherwise.
      - `reply_settings` '' | 'following' | 'mentionedUsers'
      - `paid_partnership` boolean
      - `made_with_ai` boolean
      - `thread_parts` object[] — When the post is a chained X thread (2–25 parts), this returns the canonical tweet text in publish order. For single-tweet posts the array is omitted and the text lives in `content.x` (or `content.default`). Each part also includes any per-tweet `media_urls`.
        - `id` string — Stable client-side id for the part
        - `text` string — 280 chars for standard accounts, 25,000 for X Premium/Premium+.
        - `media_urls` union[]
          - union
            - string, uri
            - object
              - …
    - `bluesky` object, nullable — Bluesky options on the post. Present when the post is a Bluesky thread; omitted otherwise.
      - `thread_parts` object[] — When the post is a chained Bluesky thread (2–25 parts), this returns the canonical post text in publish order. For single posts the array is omitted and the text lives in `content.bluesky` (or `content.default`). Each part also includes any per-post `media_urls`.
        - `id` string — Stable client-side id for the part
        - `text` string
        - `media_urls` union[]
          - union
            - string, uri
            - object
              - …
    - `mastodon` object, nullable — Mastodon options on the post. Present when the post is a Mastodon thread; omitted otherwise.
      - `thread_parts` object[] — When the post is a chained Mastodon thread (2–25 parts), this returns the canonical status text in publish order. For single posts the array is omitted and the text lives in `content.mastodon` (or `content.default`). Each part also includes any per-status `media_urls`.
        - `id` string — Stable client-side id for the part
        - `text` string
        - `media_urls` union[]
          - union
            - string, uri
            - object
              - …
    - `threads` object, nullable — Threads options on the post. Present when the post is a Threads thread (multi-post chain) or carries a location tag; omitted otherwise.
      - `location` object, nullable — Location tagged on the Threads post (sent as `location_id` to Threads at publish; on a multi-post thread it is tagged on the first post). Present only when set. `name`/`address`/`city`/`country` are whatever the caller stored alongside the id (the dashboard stores the search result; the API stores what you pass in `threads.location`).
        - `id` string
        - `name` string, nullable
        - `address` string, nullable
        - `city` string, nullable
        - `country` string, nullable
      - `thread_parts` object[] — When the post is a chained Threads thread (2 to 25 parts), this returns the canonical post text in publish order. For single posts the array is omitted and the text lives in `content.threads` (or `content.default`). Each part also includes any per-post `media_urls`.
        - `id` string — Stable client-side id for the part
        - `text` string
        - `media_urls` union[]
          - union
            - string, uri
            - object
              - …
    - `instagram` object, nullable — Instagram options on the post. Present when set; includes `first_comment` (the configured auto first comment) and, after publish, `first_comment_result` describing the outcome.
      - `first_comment` string — The configured first-comment text.
      - `first_comment_result` FirstCommentResult — Outcome of an auto first-comment attempt, written after the main post publishes.
        - `status` 'posted' | 'failed' | 'skipped' — `posted` = comment is live; `failed` = the main post published but the comment did not (see `error`; retry via POST /posts/retry-first-comment); `skipped` = the main post did not publish so the comment was never attempted.
        - `pending` boolean, nullable — TikTok only. `true` while the comment waits for TikTok to return the final video id (status is `failed` with an explanatory error meanwhile); the comment is posted automatically once the id resolves, usually within minutes.
        - `comment_id` string, nullable
        - `url` string, nullable
        - `error` string, nullable
        - `posted_at` string, date-time, nullable
    - `facebook` object, nullable — Facebook options on the post — `first_comment` and its post-publish `first_comment_result`.
      - `first_comment` string
      - `first_comment_result` FirstCommentResult — Outcome of an auto first-comment attempt, written after the main post publishes.
        - `status` 'posted' | 'failed' | 'skipped' — `posted` = comment is live; `failed` = the main post published but the comment did not (see `error`; retry via POST /posts/retry-first-comment); `skipped` = the main post did not publish so the comment was never attempted.
        - `pending` boolean, nullable — TikTok only. `true` while the comment waits for TikTok to return the final video id (status is `failed` with an explanatory error meanwhile); the comment is posted automatically once the id resolves, usually within minutes.
        - `comment_id` string, nullable
        - `url` string, nullable
        - `error` string, nullable
        - `posted_at` string, date-time, nullable
    - `linkedin` object, nullable — LinkedIn Profile options on the post — `first_comment`, its post-publish `first_comment_result`, and `carousel_as_images` (present when the post opts out of the default PDF document carousel).
      - `first_comment` string
      - `first_comment_result` FirstCommentResult — Outcome of an auto first-comment attempt, written after the main post publishes.
        - `status` 'posted' | 'failed' | 'skipped' — `posted` = comment is live; `failed` = the main post published but the comment did not (see `error`; retry via POST /posts/retry-first-comment); `skipped` = the main post did not publish so the comment was never attempted.
        - `pending` boolean, nullable — TikTok only. `true` while the comment waits for TikTok to return the final video id (status is `failed` with an explanatory error meanwhile); the comment is posted automatically once the id resolves, usually within minutes.
        - `comment_id` string, nullable
        - `url` string, nullable
        - `error` string, nullable
        - `posted_at` string, date-time, nullable
      - `carousel_as_images` boolean
    - `linkedin_page` object, nullable — LinkedIn Company Page options on the post — `first_comment`, its post-publish `first_comment_result`, and `carousel_as_images` (present when the post opts out of the default PDF document carousel).
      - `first_comment` string
      - `first_comment_result` FirstCommentResult — Outcome of an auto first-comment attempt, written after the main post publishes.
        - `status` 'posted' | 'failed' | 'skipped' — `posted` = comment is live; `failed` = the main post published but the comment did not (see `error`; retry via POST /posts/retry-first-comment); `skipped` = the main post did not publish so the comment was never attempted.
        - `pending` boolean, nullable — TikTok only. `true` while the comment waits for TikTok to return the final video id (status is `failed` with an explanatory error meanwhile); the comment is posted automatically once the id resolves, usually within minutes.
        - `comment_id` string, nullable
        - `url` string, nullable
        - `error` string, nullable
        - `posted_at` string, date-time, nullable
      - `carousel_as_images` boolean
    - `youtube` object, nullable — YouTube options on the post. After publish, `first_comment` and its `first_comment_result` are nested here alongside the Shorts metadata.
      - `first_comment` string
      - `first_comment_result` FirstCommentResult — Outcome of an auto first-comment attempt, written after the main post publishes.
        - `status` 'posted' | 'failed' | 'skipped' — `posted` = comment is live; `failed` = the main post published but the comment did not (see `error`; retry via POST /posts/retry-first-comment); `skipped` = the main post did not publish so the comment was never attempted.
        - `pending` boolean, nullable — TikTok only. `true` while the comment waits for TikTok to return the final video id (status is `failed` with an explanatory error meanwhile); the comment is posted automatically once the id resolves, usually within minutes.
        - `comment_id` string, nullable
        - `url` string, nullable
        - `error` string, nullable
        - `posted_at` string, date-time, nullable
    - `tiktok` object, nullable — TikTok options on the post. After publish, `first_comment` and its `first_comment_result` are nested here alongside the TikTok publish options. First comments need the workspace's TikTok comments authorization.
      - `title` string, nullable — Photo Mode title (photo carousels only, max 90 characters). Absent when no title was set.
      - `first_comment` string
      - `first_comment_result` FirstCommentResult — Outcome of an auto first-comment attempt, written after the main post publishes.
        - `status` 'posted' | 'failed' | 'skipped' — `posted` = comment is live; `failed` = the main post published but the comment did not (see `error`; retry via POST /posts/retry-first-comment); `skipped` = the main post did not publish so the comment was never attempted.
        - `pending` boolean, nullable — TikTok only. `true` while the comment waits for TikTok to return the final video id (status is `failed` with an explanatory error meanwhile); the comment is posted automatically once the id resolves, usually within minutes.
        - `comment_id` string, nullable
        - `url` string, nullable
        - `error` string, nullable
        - `posted_at` string, date-time, nullable

## Other responses

- `400` — Common cases: - Cannot update posted/failed posts - Per-platform media cap exceeded after the update (Bluesky/X/Mastodon ≤4, Instagram/Threads ≤10, TikTok ≤35), or mixed image+video on a platform that doesn't support it (Facebook, LinkedIn, X, Bluesky, Mastodon, TikTok — Instagram/Threads mixed carousels are fine) - Pinterest carousel aspect ratios don't all match - Character-limit exceeded for one or more selected platforms Same `validation_error` code + message shape as `POST /v1/posts/create`.
- `404` — Post not found

---

[API](https://skmtc.dev/omnisocials/apis/omnisocials-api.md) · [All operations](https://skmtc.dev/omnisocials/apis/omnisocials-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/omnisocials/omnisocials-api/revisions/e53b89af0b98/schema)
