Skip to content
Sign in Waitlist

Update post

PATCH /v1/posts/:id scope write

Edits the title, texts, media, tags and items, or moves the post to drafts or to the queue. Send only what changed; everything else stays. A YouTube item that is already uploaded and still scheduled can also change its time and metadata (checked live on YouTube).

HeadersAuthorization: Bearer praeko_… and X-Praeko-Contract: en. Always send both.

Parameters

Name In Description
id path Post id.
Idempotency-Key header Idempotency key (1 to 255 visible characters, for example a UUID). Repeating the SAME request with the same key within 24 h returns the stored response (with Idempotent-Replayed: true) without running it again; a different request with the same key returns 422 idempotency_key_reuse; a request still in progress returns 409 idempotency_in_progress. 5xx errors are not stored. The key is scoped per workspace and per route. See Retry a request safely.

Request body

JSON. Required fields must be sent; the others can be left out. Send only what changes. A post adopted from Buffer only accepts text, time and draft changes (anything else returns 409 post_adopted). YouTube, already uploaded: a YouTube item in the scheduled state (Praeko has already uploaded the video as private, with publishAt in the future) or private can change scheduledFor (it becomes videos.update with status.publishAt; the rest of the status is preserved), title, description (texts.youtube), videoTags, categoryId and the pinnedComment that has not been posted yet. Before acting, the server checks LIVE on YouTube (videos.list, 1 quota unit; each write costs 50). If the video was already published, the scheduled time has passed, the video was deleted or it was not uploaded by Praeko, nothing is written and the response is 409 with the reason and the Studio link (https://studio.youtube.com/video/<id>/edit). The new time must be at least 5 minutes from now (otherwise 422 time_in_past). Asking for the same time again does not call YouTube. A PATCH with several items applies each one independently and returns itemResults (one per already uploaded YouTube item: applied, changed, fields, notApplied, reason, message, publishAt, studio); if NONE of the requested items could change, the response is the 409 of the first one. Pending Instagram and TikTok items follow the usual rules.

Field Type Description
title (optional) string New title. 1 to 200 characters.
texts (optional) object Per-network texts that change. The fields you send replace the current ones; the others stay. A text cannot be empty or contain a placeholder such as [LINK_DO_LONGO].
texts.youtube (optional) object YouTube texts.
texts.youtube.title (optional) string Title.
texts.youtube.text (optional) string Description.
texts.youtube.pinnedComment (optional) string Pinned comment.
texts.instagram (optional) object Instagram texts.
texts.instagram.text (optional) string Caption.
texts.instagram.pinnedComment (optional) string Pinned comment.
texts.tiktok (optional) object TikTok texts.
texts.tiktok.text (optional) string Caption.
media (optional) object Media replacement.
media.cover (optional) string Id of the new cover (or null to remove it).
media.video (optional) string Id of the new video (only for an adopted post or one still in draft; otherwise 409 media_locked).
tags (optional) string[] Tags (replace the current ones).
items (optional) object[] Items to edit, selected by id or by network. Only items that are still pending can be edited.
items[].id (optional) string Item id.
items[].network (optional) string Network of the item (alternative to id). Values: youtube, instagram, tiktok.
items[].mode (optional) string New mode (YouTube: private, scheduled, public; TikTok: draft, direct). Values: private, scheduled, public, draft, direct, now.
items[].scheduledFor (optional) string New fixed time. ISO 8601 date and time in UTC, for example 2026-11-14T20:30:00Z.
items[].queue (optional) boolean Goes back to the channel's next free time slot.
items[].draft (optional) boolean Turns it into a draft.
items[].privacy (optional) string TikTok: who can view it. Values: PUBLIC_TO_EVERYONE, MUTUAL_FOLLOW_FRIENDS, FOLLOWER_OF_CREATOR, SELF_ONLY.
items[].coverFrameMs (optional) integer TikTok: cover frame in milliseconds. Minimum 0.
items[].videoTags (optional) string[] YouTube, only for a video already uploaded and still scheduled: video tags (replace the current ones).
items[].categoryId (optional) string YouTube, only for a video already uploaded and still scheduled: category number (e.g. 28).
moveTo (optional) string Moves ALL editable items to drafts or to the queue. Values: draft, queue.
Body example
{
  "title": "The test that only failed on Mondays (final cut)",
  "tags": [
    "behind-the-scenes",
    "testing"
  ],
  "items": [
    {
      "network": "youtube",
      "scheduledFor": "2026-11-10T20:30:00.000Z"
    }
  ]
}

Example

curl -X PATCH "https://praeko.app/v1/posts/01KA3W2Y6H1RC5ZQ8M0T4VXE7N" \
  -H "Authorization: Bearer $PRAEKO_KEY" \
  -H "X-Praeko-Contract: en" \
  -H "Content-Type: application/json" \
  -d '{
  "title": "The test that only failed on Mondays (final cut)",
  "tags": [
    "behind-the-scenes",
    "testing"
  ],
  "items": [
    {
      "network": "youtube",
      "scheduledFor": "2026-11-10T20:30:00.000Z"
    }
  ]
}'

Response

Success status When
200 Success.
Response 200
{
  "id": "01KA3W2Y6H1RC5ZQ8M0T4VXE7N",
  "title": "The test that only failed on Mondays (final cut)",
  "state": "queued",
  "type": "short",
  "kind": "video",
  "origin": "api",
  "media": {
    "video": "01KA3VQ7M2T9XE4HB8N5RZ6C0D",
    "cover": null
  },
  "texts": {
    "youtube": {
      "title": "The test that only failed on Mondays",
      "text": "A test that passed from Tuesday to Sunday. What it was hiding.\n\n#programming #testing"
    }
  },
  "tags": [
    "behind-the-scenes",
    "testing"
  ],
  "thumb": null,
  "items": [
    {
      "id": "01KA3W2Y6J9D3BNF7G2K5PQS8A",
      "network": "youtube",
      "channel": "01KA3V0R5D8M2WQ7X4HT9NZ1BF",
      "state": "scheduled",
      "scheduledFor": "2026-11-10T20:30:00.000Z",
      "custom": true,
      "mode": "scheduled",
      "runAt": "2026-11-10T19:30:00.000Z",
      "thumb": null
    }
  ],
  "createdAt": "2026-11-07T14:02:11.482Z",
  "updatedAt": "2026-11-07T15:40:03.120Z",
  "actions": []
}

Errors

Status code When
400 empty_body The request body is empty.
400 invalid_json The request body is not a JSON object.
413 body_too_large The request body is larger than 1 MB.
404 post_not_found The post does not exist.
404 item_not_found The item does not exist in this post.
409 not_editable The item has already gone out or is in progress (YouTube, already uploaded: it can only change while the video is still private and scheduled; once the scheduled time has passed, it can no longer change).
409 post_adopted Post adopted from Buffer: only text, time and draft can change.
409 media_locked The video can only be replaced in an adopted post or in a draft; the image of an image post cannot be replaced by PATCH.
409 video_not_private YouTube, already uploaded: the video is already public on YouTube, so its time and metadata can only change in Studio (details.studio has the link).
409 video_not_found YouTube, already uploaded: the video was deleted on YouTube.
422 time_in_past The new time must be at least 5 minutes from now.
502 youtube_error YouTube did not respond or rejected the check/write; nothing was changed (or itemResults says what was).
422 invalid_field A field is invalid.
422 idempotency_key_reuse The Idempotency-Key was already used with a different request (different method, path, query or body).
409 idempotency_in_progress A request with the same Idempotency-Key is still in progress (retry in a moment).
409 idempotency_response_too_large The original response was larger than 256 KB and was not stored; fetch the resource with GET instead.

Errors on any route

Status code When
401 unauthorized The Authorization: Bearer … header is missing.
401 invalid_api_key The key does not exist.
401 revoked_api_key The key has been revoked.
401 expired_api_key The key has expired.
403 forbidden The key's scope is not enough for this route (see the scope badge).
429 rate_limited The per-minute request limit was exceeded.

The body of every error is { "error": { "code", "message", "details"? } }. See all error codes.

Try it

Try it

The live test uses your key and your account. It stays off when you are not signed in.

Sign in to try it
Question or mistake on this page? contato@praeko.appView .md

Type to search pages, routes and error codes.