---
title: "Edit a draft post"
method: PATCH
path: "/posts/{postId}"
tags: ["Posts"]
---

# Edit a draft post

`PATCH /posts/{postId}`

## Request

- Base URL: `https://www.juzpost.com/api/cli/v1`
- URL: `https://www.juzpost.com/api/cli/v1/posts/{postId}`
- Auth: HTTP bearer

Updates a post that is still in `draft` status; once scheduled or published it can no
longer be edited and this returns `409`. Every field is optional and omitted fields are
left untouched. Send `null` for `mediaUrls` or `coverR2Key` to clear them. `title`,
`description` and `hashtags` are merged into the post's metadata rather than replacing
it wholesale. Changing `mediaUrls` clears the Bluesky alt text on accounts that publish
the post's files, since each entry describes a file by its position; labels stay.

## Path parameters

- `postId` string, uuid, required

## Request body

- UpdatePostRequest: Fields to change on a draft. Omit a field to leave it alone. Only `mediaUrls` and `coverR2Key` accept `null`, which clears them.
  - `content` string: Replacement post body or caption, up to 2200 characters.
  - `mediaUrls` string[], nullable: Replacement list of storage keys, or `null` to remove all media. Replaces the existing list entirely rather than appending to it.
  - `title` string: Replacement title, merged into the post's metadata.
  - `description` string: Replacement description, merged into the post's metadata.
  - `hashtags` string[]: Replacement hashtag list, merged into the post's metadata. Replaces the previous list entirely. Do not include the leading `#`.
  - `type` 'text' | 'image' | 'video' | 'story' | 'blog': What kind of content the post carries. Anything other than `text` and `blog` must have at least one media key before it can be scheduled. `blog` is a WordPress blog post: `title` is required and `description` is the body, HTML sent as written (plain text works, blank lines become paragraphs). The first image is the featured image and any others are added under the body. Images only.
  - `coverR2Key` string, nullable: Replacement cover image storage key, or `null` to clear the cover.

## Response `200`

Draft updated.

- CreatedPost: The id of the post that was created or updated. Fetch `GET /posts/{postId}` if you need the full record.
  - `id` string, uuid, required: The post id.

## Other responses

- `400`: The request body or query string failed validation. `error.message` names the first problem found.
- `401`: No bearer token was sent, or the token is unknown, revoked or malformed. Run the device login again to obtain a new token.
- `402`: The plan behind this token does not include the capability this operation needs. `error.details.requiredPlan` names the tier that does. This is never a token problem, so do not retry without changing the plan.
- `404`: No such resource. A resource that belongs to someone else is also reported here, so this never confirms whether another tenant's id exists.
- `409`: The resource is not in a state that allows this operation, typically a post that has already left `draft` status. Re-read the resource before retrying.

---

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