Update a post by ID
Update an existing post in your publication. The publication is identified by the API key provided in the Authorization header.
Behavior:
- Only provided fields are updated; omitted fields remain unchanged
- When
markdownis provided, it replaces the full content. Rich blocks (embeds, buttons, callouts) created in the editor will be lost — the markdown to editor conversion is lossy for blocks without a markdown equivalent - Set
statusto"published"to publish a draft,"draft"to unpublish, or"archived"to archive - When editing an already-live post that should remain live, include
status: "published"in the update and verify the returned post status before telling the writer it is live - Set
scheduledAt(Unix timestamp in milliseconds) to schedule a draft's first-publish for a future time. Must be in the future and at most 30 days out. Only valid for posts that haven't been published or already scheduled. PassscheduledAt: nullto cancel a previously scheduled publish (or to reschedule: cancel first, then schedule again with the new time). SetsendNewsletter: truealongsidescheduledAtto email subscribers when the post publishes. - Set
imageUrlto update the post's cover/hero image; the URL is fetched, re-hosted, and a placeholder is generated. PassclearImage: trueto remove the existing cover. - Set
imageAltto describe the cover image for screen readers. It renders everywhere the cover appears, so set it whenever you setimageUrl.
apiKeyAuthorizationBearer <token>API key for authenticating protected endpoints. Pass as Bearer token in Authorization header.
postId*stringUnique identifier of the post to update
Body
application/json- body
markdown?stringPost content in Markdown format. Replaces the FULL body. Markdown cannot represent buttons, linked images, or embedded media (videos, tweets, link cards) — replacing a post that has any of those with markdown drops them. Use bodyJson (round-tripped from get-post) to edit an existing post so nothing is lost. Provide markdown OR bodyJson, not both.
bodyJson?stringPost content as a Tiptap document, JSON-stringified (e.g. '{"type":"doc","content":[...]}'). This accepts ANY Tiptap node the editor supports — including videos, tweets, link cards, callouts, and buttons — so editing a post by round-tripping the json returned by get-post preserves everything markdown would drop. Replaces the FULL body; node-type validity is checked by the renderer and an unusable document is rejected. Provide markdown OR bodyJson, not both.
title?stringTitle of the post
length <= 200subtitle?stringOptional subtitle or brief summary
length <= 300slug?stringURL-friendly identifier for the post
1 <= length <= 256postPreview?stringPreview text for the post
length <= 500categories?array<string>|Category tags for the post. Can also be a comma-separated string.
authorIds?array<string>User ids credited as the post's authors, in byline order. Replaces the full list, so include every author you want kept — read the post's current authorIds first and start from those. Each id must be the publication's owner or an active team member; ids from outside the publication are rejected. There is no endpoint that enumerates members, so an id has to come from a post you have read (authorIds on a single post, or authors[].id on a list) or from the writer.
1 <= items <= 20status?stringSet to 'published' to publish a draft or keep an already-live post published after edits, 'draft' to unpublish, or 'archived' to archive
"draft""published""archived"scheduledAt?|Unix timestamp (milliseconds) to schedule the post's first publish at a future time. Must be in the future and at most 30 days out. Only valid for draft posts that haven't been published or already scheduled. Cannot be combined with status: 'draft' or 'archived'. Pass null to cancel a previously scheduled publish. The value 0 is treated the same as omitting the field (no scheduling request); note that on an already-scheduled post, omitting scheduledAt while setting status to 'published' or 'archived' cancels the schedule, and 'draft' keeps it.
0 <= valuesendNewsletter?|Whether to send an email newsletter to subscribers when the post publishes. Only meaningful when publishing (status: 'published') or scheduling (scheduledAt set). Default: false
canonicalUrl?|Canonical URL used in rendered metadata. Pass null to clear it. This does not change the post's Paragraph permalink.
urilength <= 2048publishOnline?booleanWhether the post should be publicly visible online when published. Set false for newsletter-only delivery.
communityId?|Subscriber segment id for newsletter delivery. Pass null for the general audience. Unavailable or cross-publication segments are rejected rather than broadened.
1 <= length <= 128publishedAt?integerUnix timestamp (milliseconds) to set as the post's publish date. Once set, the date is preserved across re-publishes.
0 <= valueimageUrl?stringURL of an image to set as the post's cover/hero image. The image is fetched, re-hosted on Paragraph's CDN, and a placeholder is generated. Pass clearImage: true instead to remove the existing cover.
uriclearImage?booleanWhen true, removes the post's existing cover/hero image. Ignored if imageUrl is also provided.
imageAlt?|Alternative text describing the cover image. Set it alongside imageUrl when replacing the image; on its own it re-describes the existing cover. Pass null or an empty string to clear it. Ignored when the post has no cover.
length <= 1000Post updated successfully
application/json- response
success*trueWhether the update succeeded
truecurl -X PUT "https://example.com/v1/posts/string" \ -H "Content-Type: application/json" \ -d '{}'{ "success": true}Delete a post DELETE
Permanently delete a post from your publication. The publication is identified by the API key provided in the Authorization header. **Warning:** This action is irreversible. The post and all related data (notifications and drafts) will be permanently deleted.
Get post by publication ID and post slug GET
Retrieve a post using its publication ID and its URL-friendly slug