A draft is a Post with the draft state. Publishing changes the same Post.
Create a draft
Store the returned Post id and version.
Repeat --body to create an ordered self-reply chain for X, Bluesky, Mastodon,
or Threads. Repeat --media-item <body-index>:<asset-id> to attach media to a
specific body item. The first body index is 0. The other channels accept one
body item. On X, Bluesky, Mastodon, and Threads, any body item can contain media
without text. Keep an empty --body '' at that thread position and attach at
least one Asset to the same index.
For X, every body item uses the selected Destination’s effective limit.
Read it with openpmm destinations show <destination-id> --json.
Run that command before you write or schedule long copy.
Refresh Destinations after an X subscription change.
For a direct or scheduled Post, use --destination instead of --channel.
Put provider-specific settings in --destination-options. For example:
OpenPMM checks these settings during the create request. If a required setting
is missing, the CLI reports a non-retryable 422 validation error.
Attach one video to make a Facebook Reel. OpenPMM selects the reel placement
automatically. Do not send a facebook member in --destination-options.
For a Bluesky video, attach one video Asset to one body item:
Bluesky accepts one MP4 video without other media.
For YouTube, set thumbnail_timestamp_ms to select a frame from the video.
This example selects the frame at 1 second:
The command can return while OpenPMM or the provider processes the Post. Add
--wait for bounded CLI polling on an immediate publication.
Use --when queue to select the next Destination queue slot.
OpenPMM uses the Workspace time zone.
Edit a Post
You can change the copy and publishing options on a draft or scheduled Post.
The CLI gets the current ETag before it changes the Post.
Use --etag to change the version that you reviewed.
Use --destination-options with JSON to change the Destination publishing options.
The scheduled Post keeps its current time and assets.
Cancel the schedule before you change assets or thread structure.
Publish a Post
Publishing can create external posts. Pass --yes to send the request.
Use --at 2026-08-13T12:00:00Z to schedule the Post at an exact time.
Use --at queue to select the next queue slot.
If a group contains multiple draft Posts, publish all Posts with --file request.json.
posts publish returns after OpenPMM accepts the state change. It does not
wait for provider completion unless you add --wait. Exit code 0 means that
OpenPMM accepted or completed the requested transition. Exit code 11 means
that one or more Posts need action. Both exits preserve the JSON result and
available receipts.
For immediate publication, inspect meta.publication:
- If
complete is true, stop. The returned Posts include available receipts.
- If
complete is false, use the returned next_command, or run
openpmm posts wait <post-id> --json.
- If
action_required_post_ids is not empty, stop and inspect each Post’s
available_actions. The CLI exits with code 11. Do not keep polling.
- Read top-level
outcome: success, partial_failure, or failure.
- Do not send
posts publish again.
--wait polls through the CLI for up to 300 seconds by default. Set
--wait-timeout to change the bound. The final JSON includes wait_complete.
The CLI stops when each Post is terminal or needs action. Scheduled and queued
Posts are accepted work and do not use --wait.
Move a queued Post
Get the Post and copy its current scheduled_at value.
Select a local date in the Workspace time zone.
Use --file request.json to move multiple Posts in one atomic request.
OpenPMM moves all requested Posts or does not move any Post.
When background work continues, the command returns a nonterminal Post and a
next command in JSON output. Use posts wait for immediate publication. You
can use posts show for one read. OpenPMM continues the accepted work. Do not
run posts publish again.
List Posts by state
Use --view to filter posts list by state:
The views are all, drafts, scheduled, published, attention, and
failed. failed returns the Posts that need attention — the same set the
Failed tab shows in the web app.
The list can include Posts that OpenPMM imports from a connected provider.
Read publication_source in JSON output to identify them.
The value is provider for an imported Post.
The value is openpmm for a Post that OpenPMM publishes.
Use exact filters when you reconcile a workflow:
If retry_safety is may_duplicate, verify the provider first. Then add
--acknowledge-duplicate-risk to posts retry.
Recover an uncertain request
The CLI safely retries a request that has an idempotency key.
Reuse --idempotency-key after a timeout.
If a provider stops after it publishes part of a thread, OpenPMM keeps the
published receipts. A retry resumes at the first missing reply instead of
publishing the opening posts again.