antworkDOCS

Editing a post

Change a draft, scheduled or failed post the way the composer and the MCP tools change it.

PATCHhttps://antwork.io/api/v1/posts/{id}Scopewrite · publish

Request

PATCH /api/v1/posts/{id} changes only the fields you send. Text and hashtags are set and the post's media and tags stay; options are merged one setting at a time. A published post cannot be edited (409 post_already_published): the change would not reach the live post.

curl -X PATCH https://antwork.io/api/v1/posts/pQ7x... \
  -H "Authorization: Bearer $ANTWORK_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "text": "Shipping the new editor today",
    "options": {
      "privacyStatus": "unlisted"
    },
    "scheduledFor": "2026-11-05T10:00:00Z"
  }'
textstring
The new text. Hashtags already in it stay.
hashtagsstring[]
Added to the text where the platform publishes them, as on create; YouTube keeps them as video tags.
accountIdstring
Move the post to another account in its workspace. Its platform follows, and options are checked against the new one.
optionsobject | null
The post's platform settings, unkeyed ({"privacyStatus": "unlisted"}; Pinterest {"boardId": "..."}). A setting given null is removed, and "options": null removes them all. TikTok's are the owner's to choose (tiktok_settings_need_the_creator).
newBoardNamestring
Pinterest: create a board with this name on the account and pin to it, as the composer's Create board does. Created only once every other check passed; pinterest_board_create_failed if Pinterest refuses.
scheduledForISO 8601
On a scheduled post, moves it to this time (at most 30 days ahead) and needs the publish scope. On a draft or a failed post it only proposes a time; schedule it with POST /api/v1/posts/{id}/schedule.
status'draft'
Only "draft": moves a scheduled post back to draft and cancels its queued publish.

Needs the write scope, and publish as well when the edit moves a scheduled post to a new time, because that commits it again against your plan, the daily cap and the posting guards. The same rule as the MCP update_post tool. Send an Idempotency-Key: a retried request with a newBoardName must not create a second board.

Response

200 with the post as saved: the same shape as GET /api/v1/posts/{id}, with readiness and the composer links, plus pinterestBoardCreated when a board was made. A refused argument or a platform rule (text_too_long, media_required…) is a 400 and nothing is written. When the plan or the account has no room at the new time (quota_exceeded, daily_cap_reached, duplicate_post…), the answer is a 409, the edit IS saved and the post keeps its old time; post carries it as it now stands.

409 Conflict
{
  "error": {
    "type": "invalid_request_error",
    "code": "daily_cap_reached",
    "message": "This account has reached its daily cap ... The edit is saved; the post keeps its old time."
  },
  "post": { "object": "post", "id": "pQ7x...", "status": "scheduled", ... }
}
The reasons are the ones POST /api/v1/posts gives per target, so one handler covers both. See Errors for the full list.

Setting the media

PUT /api/v1/posts/{id}/media with {"media": [...]} makes the post's media exactly that list, in that order: reorder it, trim it, or send [] to clear it. Each file must be in the workspace's media library (media_not_in_library otherwise); a file already on the post is always accepted. Needs the media scope. Sending the same list twice changes nothing, so no Idempotency-Key is needed.

curl -X PUT https://antwork.io/api/v1/posts/pQ7x.../media \
  -H "Authorization: Bearer $ANTWORK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "media": [
      "https://firebasestorage.googleapis.com/v0/b/.../o/workspaces%2Fws_...%2Fmedia%2Fcover.jpg?alt=media"
    ]
  }'

200 with the post, its readiness saying whether the platform's media rule is now met. On Instagram, originalityWarning lists the account's other posts that already carried the same file: Instagram shows reposted media to fewer people.