> Discover all available Postdom documentation from the machine-readable index: https://postdom.com/llms.txt

Reference · problem details

# Errors

Postdom returns RFC-style problem details with one stable machine-readable code. Preserve the code and detail before deciding whether to correct, retry, or hand off.

application/problem+json

## Problem envelope

Every problem response contains at least `type`, `title`, `status`, `detail`, `code`, `fix` and `doc_url`. `fix` is one sentence saying what to do next; `doc_url` links its entry on this page, by code or, for a code not listed here, by HTTP status. Some carry more — a refused publish adds `reason`, `next_step`, `resolution`, `retryable` and `documentation_url`, described under Publishing refusals below. Read the seven as guaranteed and ignore fields you do not recognise rather than rejecting the response. The example detail is synthetic; runtime detail names the current failure.

Two 422s are raised because a selected destination cannot take what you sent, and both carry `destinations`, an array of `{ platform, fact }`: `media_invalid` for the video and `caption_invalid` for the text. The field is the same shape in both, so branch on it rather than parsing `detail`, and handle the two codes the same way — the question is which destination to drop. The codes stay distinct because the fix differs: re-encoding the video cannot shorten a caption. A `media_invalid` _without_ `destinations` means the asset failed reachability, immutability, type, host, or size checks.

_EXAMPLE PROBLEM RESPONSE · SYNTHETIC DETAIL_

```
{
  "type": "https://postdom.com/problems/media_invalid",
  "title": "Video source unavailable",
  "status": 422,
  "detail": "Video source could not be reached",
  "code": "media_invalid",
  "fix": "If the response carries destinations, each entry names a destination and the fact it failed, read from the video rather than guessed: publish without those destinations, or re-encode to a format and size all of them accept. Otherwise obtain an accepted media URL before making a new request.",
  "doc_url": "https://postdom.com/docs/reference/errors#media_invalid"
}
```

Agent decisions

## Handling rules

`correct`

Fix 400 or 422 input evidence before making a deliberate new call.

`stop`

Return 401, 403, 404, and 423 failures to a human when the caller cannot restore authority or context.

`read`

On `publish_in_progress`, read the existing post instead of duplicating the write.

`retry`

Use bounded backoff for 503 failures. Never convert a retry budget into an unbounded loop.

Common agent-facing failures

## Error codes

These codes are emitted by current setup, connection, brief, plan, publish, and read routes. Dashboard-only review errors remain outside the agent reference.

| Code | HTTP | Meaning | Agent action |
| --- | --- | --- | --- |
| invalid_request | 400 | The request failed schema or runtime input validation. | Correct the reported field or value before retrying. |
| idempotency_key_required | 400 | A raw API write omitted its Idempotency-Key header. | Send one stable key for the logical write. Configured adapters may generate this key. |
| unauthorized | 401 | The agent credential is missing or invalid. | Send a Postdom workspace key as "Authorization: Bearer <key>". A workspace owner, admin or member creates one in Postdom under Connected apps → For developers (https://app.postdom.com/agents); it is shown once. Ask the person to put it in your MCP or environment config, never in chat. MCP clients that support OAuth can sign in at https://api.postdom.com/mcp instead of using a key. |
| insufficient_scope | 403 | The workspace key lacks the read or write scope required by this operation. | Stop and ask an owner, admin or member to create an appropriately scoped key. Never request the raw key in chat. |
| connect_disabled | 403 | Destination connections are currently unavailable for this workspace. | Return the connection gate to a human. Do not try to unlock or route around the workspace boundary. |
| policy_blocked | 409 | Postdom refused to publish. The body carries a stable reason, what to do next, and a link to that reason's entry. | Read reason, not the sentence. Retry only when retryable is true; otherwise resolve what next_step names. |
| target_not_connected | 403 | The destination is not connected to the current workspace. | Return the destination ID and hand connection work to a human. |
| plan_target_not_l2 | 403 | A proposed plan target lacks the required trust level. | Return the target and let a human change trust or revise the plan. |
| plan_not_found | 404 | No plan with that ID exists in the workspace. | Stop plan-backed work and return the exact plan ID to a human. |
| post_not_found | 404 | No post with that ID exists in the workspace. | Stop polling and return the exact post ID to a human. |
| media_not_found | 404 | No upload with that media handle exists in the workspace. | Stop polling and return the exact media handle. Never guess or substitute another workspace's handle. |
| brief_not_found | 404 | The workspace does not have a saved Workspace Brief. | Ask a human to add the brief. Do not invent brand, voice, timing, or never-do guidance. |
| idempotency_conflict | 409 | The key was already used with a different payload. | Do not overwrite the original operation. Use a new key only for a deliberate new request. |
| publish_in_progress | 409 | The original idempotent publish is still being processed. | Read the existing post instead of creating another publish request. |
| provider_not_provisioned | 409 | The workspace has not created its isolated social-provider profile yet. | Read the workspace connection gate, then use connect_account only when that gate is unlocked. |
| supplier_spend_guard | 409 | Postdom stopped a connection before it could exceed the supplier-spend review threshold. | Return the exact detail to a human. Do not retry around the cost guard. |
| account_cap_reached | 409 | The workspace connection attempt reached the account cap for its current plan. | Return the exact detail to a human. Do not replace or disconnect another account. |
| invalid_media_handle | 400 | The supplied media handle is malformed. | Use the opaque handle returned by upload_media without modifying it. |
| media_upload_rate_limited | 429 | The workspace reached its rolling media-upload contract cap. | Wait for the reported window, then retry once. Do not rotate credentials or workspaces to bypass the cap. |
| rate_limited | 429 | The API credential or workspace reached its shared agent-request limit. | Honor Retry-After and retry with bounded backoff. Do not rotate keys or workspaces to bypass the cap. |
| media_invalid | 422 | The video source failed reachability, immutability, type, host, or size checks, or a selected destination cannot receive it. | If the response carries destinations, each entry names a destination and the fact it failed, read from the video rather than guessed: publish without those destinations, or re-encode to a format and size all of them accept. Otherwise obtain an accepted media URL before making a new request. |
| caption_invalid | 422 | A selected destination will not accept a caption this long, measured against the limit that destination publishes. | Read `destinations`: each entry names a destination and the caption fact it exceeds. Shorten the caption to that destination's limit, or publish to the destinations that accept it in a separate request. Postdom refuses only where the caption limit is marked `enforced_by_postdom` - some destinations publish a limit that is deliberately not gated here, each with a stated reason, and those are reported on the approval card rather than refused. |
| brief_version_not_found | 422 | The submitted Workspace Brief version does not exist in this workspace. | Call get_brief again and deliberately resubmit the plan with the returned current version. |
| agent_paused | 423 | The workspace-wide agent pause blocks write activity. | Stop writes and hand control to a human. Only a human can resume activity. |
| provider_down | 503 | The provider or durable publish worker is unavailable. | Retry with bounded backoff. Return the code, detail, and any already-known resource ID when the budget ends. |
| media_upload_unavailable | 503 | Postdom could not issue a private, scoped upload contract. | Do not upload elsewhere silently. Retry with bounded backoff, then return the error to a human. |
| media_unavailable | 503 | Private media status or delivery is not configured or available. | Preserve the media handle, stop publishing it, and return the exact error to a human. |
| persistence_unavailable | 503 | The required durable store is unavailable or not configured. | Do not assume the write was recorded. Retry with bounded backoff, then hand off. |
| autopilot_not_enabled | 403 | Starting posts with an agent credential is not switched on for this workspace yet. | Making posts with an agent key is not switched on for this workspace yet. Write the slides yourself with create_slideshow, or ask the person to make the posts in the Postdom app. |
| brand_brain_not_found | 404 | The workspace has not read a website yet, so there is nothing to write posts from. | This workspace has not read a website yet. Ask the person to add the website in Postdom (https://app.postdom.com), then try again. |
| plan_upgrade_required | 402 | The workspace plan does not include this action. | The workspace plan does not include this. Give the person upgrade_url from this response; do not retry until they upgrade. |

Any other code

## Fixes by HTTP status

A code not listed above gets its HTTP status's fix, and its `doc_url` links the row here.

| HTTP | Fix |
| --- | --- |
| 400 | Fix the field or value named in detail, then send the request again. |
| 401 | Send a Postdom workspace key as "Authorization: Bearer <key>". A workspace owner, admin or member creates one in Postdom under Connected apps → For developers (https://app.postdom.com/agents); it is shown once. Ask the person to put it in your MCP or environment config, never in chat. MCP clients that support OAuth can sign in at https://api.postdom.com/mcp instead of using a key. |
| 402 | The workspace plan or allowance does not cover this. Give the person upgrade_url (or topup_url) from this response; do not retry until they act. |
| 403 | This credential may not do this. Hand it to a workspace owner or admin; do not retry with another key or workspace. |
| 404 | Use only IDs that a Postdom response returned for this workspace. Do not guess or construct IDs. |
| 409 | Read the current state of the resource named in detail before deciding whether to retry. |
| 413 | Send a smaller request body. |
| 422 | Change what detail (and destinations, when present) names, then send a new request. |
| 423 | Writes are paused for this workspace. Stop and hand control to a person. |
| 429 | Wait for Retry-After (or retry_at), then retry once. |
| 500 | Retry once with the same Idempotency-Key. If it fails again, return the code and detail to a person. |
| 503 | Retry with bounded backoff and the same Idempotency-Key, then return the code and detail to a person. |

Why a publish was refused

## Publishing refusals

A refused publish returns `409` with code `policy_blocked`. The body carries a stable `reason` from the list below, a `next_step`, and a `documentation_url` pointing at that reason's entry here. Read `reason` rather than matching on the sentence — the wording may improve, the code will not.

Every reason Postdom can refuse with is listed. The list is generated from the same definition the API refuses with, so a reason cannot exist without an entry on this page.

**This list grows.** New reasons are added as Postdom learns to tell states apart that it previously reported under a nearer-but-wrong reason. Treat an unfamiliar `reason` as “refused, explanation unavailable” and read `next_step`, rather than writing an exhaustive switch that treats a future member as an error. Adding a member is an additive change:`policy_blocked` stays the code you branch on, existing reasons keep their meaning, and a new state gets a new member rather than being folded into an old one.

### `publishing_disabled`

Publishing is switched off, so Postdom accepted nothing for delivery.

**What to do:** Nothing in the request needs changing. Contact Postdom to find out when publishing is available for this workspace.

Resolved by: Postdom Something has to change first — retrying alone will not clear it

### `policy_unavailable`

Postdom could not read the publishing policy for this workspace, so it refused rather than guessed.

**What to do:** Try again shortly. If it persists, contact Postdom — this is not something the request can fix.

Resolved by: Postdom An identical retry can succeed

### `policy_invalid`

The stored publishing policy did not pass validation, so Postdom refused rather than acting on it.

**What to do:** Contact Postdom. Retrying will not help until the policy is corrected.

Resolved by: Postdom Something has to change first — retrying alone will not clear it

### `target_mismatch`

The destinations on the request were missing, repeated, or not usable as written.

**What to do:** Send one entry per destination account, each with a non-empty account ID and no duplicates, then submit again.

Resolved by: the API client or agent Something has to change first — retrying alone will not clear it

### `agents_paused`

Publishing is paused — either for the whole workspace or for this account.

**What to do:** Resume the workspace or the account from the Accounts page, then submit again.

Resolved by: a human with workspace access Something has to change first — retrying alone will not clear it

### `authorization_changed`

What was about to be published no longer matches what a human approved — the caption, the media or the request identity changed after approval.

**What to do:** Submit the post again and have it approved in its current form. Postdom will not publish an unapproved version.

Resolved by: the API client or agent Something has to change first — retrying alone will not clear it

### `prior_submission_uncertain`

An earlier attempt may already have reached the destination, and Postdom cannot confirm that it did not.

**What to do:** Check the destination before resubmitting. Postdom stops here deliberately rather than risk publishing the same video twice.

Resolved by: the API client or agent Something has to change first — retrying alone will not clear it

### `execution_interrupted`

The run stopped before Postdom could confirm an outcome, so it was recorded as stopped rather than published.

**What to do:** Check the destination, then submit again if the post did not appear.

Resolved by: the API client or agent Something has to change first — retrying alone will not clear it

### `media_invalid`

The video could not be validated when publishing began.

**What to do:** Check that the media is still reachable and matches what was approved, then submit again.

Resolved by: the API client or agent Something has to change first — retrying alone will not clear it

### `account_disconnected`

This account is no longer connected to Postdom, so nothing can be published to it.

**What to do:** Reconnect the account from the Accounts page. Its policy and any scheduled posts are kept.

Resolved by: a human with workspace access Something has to change first — retrying alone will not clear it

### `trust_level_too_low`

This account's autonomy level does not allow an agent to publish to it.

**What to do:** Raise the account's autonomy level on the Policy page, or have a human approve each post for it.

Resolved by: a human with workspace access Something has to change first — retrying alone will not clear it

### `plan_changed`

The plan this post was scheduled under was changed, cancelled or ended before it went out. The post itself did not change.

**What to do:** Approve the post in Review, or extend the plan, then publish it again.

Resolved by: a human with workspace access Something has to change first — retrying alone will not clear it

### `autonomy_lowered`

This post was queued by the account's autonomy, which was lowered before it went out. The post itself did not change.

**What to do:** Approve the post in Review, then publish it again.

Resolved by: a human with workspace access Something has to change first — retrying alone will not clear it

### `rules_changed`

This account's posting rules changed after the post was queued, and this workspace rechecks rules at publish time. The post itself did not change.

**What to do:** Publish it again under the current rules, or turn off the publish-time rules recheck on the Rules page.

Resolved by: a human with workspace access Something has to change first — retrying alone will not clear it

Safe recovery

## Retry boundary

### Preserve the operation

Reuse an idempotency key only for the same logical write. When a bounded retry window ends, return the code, detail, and any already-known resource ID.

 VERIFIED · 26 AUGUST 2026  **API problem helper · Agent-token setup, connection, brief, plan, publish, and read routes**

Titles and details vary by route. The code and HTTP status determine agent handling.
