Edit a piece of content
Rename a piece of content, replace its body, or both.
Replacement, not a merge: body replaces the artifact entirely, in the same shape the kind takes on create. Send the whole thing, not just the part that changed. Media already attached to the draft is the one exception — you can't send it back, so it's carried over rather than dropped.
Scheduled pieces are locked: if a send is queued or already running for this piece, its words go out exactly as written, so an edit to body is refused with an explanation. Cancel the schedule in the app first. Renaming is always allowed — a title isn't published anywhere.
Grouping: bucketId files this piece with the post it was made from. A piece already grouped somewhere else is refused with a 409 rather than moved — ungroup it in the app first.
apiKeyAuthorizationBearer <token>API key for authenticating protected endpoints. Pass as Bearer token in Authorization header.
contentId*stringUnique identifier of the content
Body
application/json- body
title?stringNew name for this piece in your library
1 <= length <= 200body?The replacement artifact, in the shape this piece's kind uses
bucketId?stringGroup this piece with the post it was made from, so the writer sees them together in Content. Get the id from POST /v1/posts/{postId}/bucket. Omit for standalone work that isn't derived from anything.
uuidContent updated successfully
application/json- response
id*stringUnique identifier for this piece of content
kind*stringWhat this piece is: tweet, linkedin, newsletter, or x_article
title*stringWhat this piece is called in your library
excerpt*stringFirst readable line of the body, for listing views
status*stringWhether this piece has been delivered, is still a draft, or was archived
"draft""published""archived"scheduled*booleanWhether a scheduled send is queued against this piece
lockedReason*|Why this piece can't be edited right now, or null when it can. A queued or in-flight send locks the words, because they go out exactly as written.
publishedAt*|ISO 8601 timestamp of the first delivery, or null
url*|Where this piece went live, from the same delivery publishedAt came from. Null when it hasn't been delivered, and null by design for a channel that publishes no page: a custom email renders into the message itself, so there is no address to link to. Never guessed — a delivery whose id isn't shaped like its channel reports null rather than a link that would 404.
archivedAt*|ISO 8601 timestamp of when this piece was archived, or null
bucketId*|The bucket grouping this piece with the post it was made from, or null when it stands alone. Read it back with GET /v1/buckets/{bucketId}.
createdAt*stringISO 8601 timestamp of creation
updatedAt*stringISO 8601 timestamp of the last change
body*The artifact itself, in the shape its kind uses
curl -X PATCH "https://example.com/v1/content/string" \ -H "Content-Type: application/json" \ -d '{}'{ "id": "string", "kind": "string", "title": "string", "excerpt": "string", "status": "draft", "scheduled": true, "lockedReason": "string", "publishedAt": "string", "url": "string", "archivedAt": "string", "bucketId": "string", "createdAt": "string", "updatedAt": "string", "body": { "property1": null, "property2": null }}Get a piece of content GET
Retrieve one piece of drafted content with its body. Read it before editing so you rewrite what's actually saved — the draft may have changed in the app.
Archive a piece of content POST
Put a piece away without deleting it. Archived content drops out of the default list and out of the writer's Content surface, and `POST /v1/content/{contentId}/restore` brings it back. Any suggestion still proposing the piece is dismissed along with it, so nothing is left offering to send something you've filed away. A piece with a send already queued can't be archived — cancel the schedule first.