> ## Documentation Index
> Fetch the complete documentation index at: https://www.openpmm.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Create posts

> Create an OpenPMM draft Post, publish it, and check its final status safely.

Publishing creates content on a provider. Review the draft before you publish it.

<Steps>
  <Step title="Create a draft Post">
    Create one Post for each channel. A draft uses a channel instead of a destination.

    ```json theme={null}
    {
      "when": "draft",
      "group": "launch-2026-08",
      "posts": [
        {
          "channel": "x",
          "headline": null,
          "body": ["A release update from OpenPMM."],
          "media": [],
          "destination_options": null
        }
      ]
    }
    ```

    Send this body to `POST /workspaces/{workspace_id}/posts`.

    Before you write X copy, get the selected Destination.
    Inspect `capabilities.body_text_limit` in the response.
    Each X thread item uses that Destination's effective limit.
    Refresh Destinations after an X subscription change.
  </Step>

  <Step title="Store the Post version">
    Store the returned Post `id` and `version`. Use them when you publish the draft.
  </Step>

  <Step title="Publish the same Post">
    Send the draft Post and its destination to `POST /workspaces/{workspace_id}/posts/publish`.
    If the group contains multiple draft Posts, include every Post in this request.

    ```json theme={null}
    {
      "confirmed": true,
      "when": "now",
      "time_zone": "UTC",
      "posts": [
        {
          "id": "send_01JABCDEF",
          "version": 1,
          "destination_id": "dest_01JABCDEF"
        }
      ]
    }
    ```

    Add a unique `Idempotency-Key` header.

    OpenPMM returns after it accepts the state change. It does not wait for the
    provider. Immediate, nonterminal publication returns `202 Accepted` and a
    `Retry-After` header. The response contains every Post ID and all stored
    receipts. OpenPMM returns status `422` when a file needs your decision.
  </Step>

  <Step title="Check the Post status">
    Use `GET /workspaces/{workspace_id}/posts/{post}`. The response includes
    lifecycle fields, receipts, and `available_actions`. Use `include=attempts`
    to get sanitized provider attempt diagnostics. A queued Post can include `deferred` and
    a future next-attempt time. The reason is `publishing_velocity` for a local
    dispatch delay or `provider_cooldown` when OpenPMM is waiting before it
    contacts that destination again. A failed Post stays failed while the
    deferral reports when OpenPMM can try it again.

    Poll only while `terminal` and `action_required` are both `false`. Stop
    when the Post is terminal or needs action. Do not send Publish Posts again.
    Use `retry_safety` before you retry a failed Post.
  </Step>
</Steps>

<Warning>
  A timeout does not prove that publishing failed. Retry with the same idempotency key.
</Warning>

<Note>
  A direct or scheduled Post uses `destination_id` instead of `channel`. Put
  destination-specific settings in `destination_options`. For example, an
  Instagram Post needs `{ "instagram": { "placement": "post" } }`. OpenPMM checks these
  settings during Create Post and Publish Post. If a required setting is
  missing, the API returns `publisher_validation_failed` with status `422`.
</Note>

For Facebook, one attached video uses the `reel` placement automatically.
Do not send a `facebook` member in `destination_options`. The API rejects this
retired input.

If one destination reaches a provider publishing limit, only that destination's
Post fails. OpenPMM continues the other destination Posts. Use confirmed manual
Retry later for the affected Post.

An X body item above the connected Destination's limit fails with
`x_character_limit_exceeded`. Shorten the item and retry. OpenPMM checks the
capability again immediately before publishing a long X item, so a scheduled
Post can fail safely before it creates provider content if the account was
downgraded.
