Browse documentation
Validate a destination, publish with confirmation, and verify results.
The flow is preview → publish → poll.
POST /v1/brands/{brand_id}/publishing/previews (publishing:preview, beta)
Headers: Idempotency-Key (required). Costs 1 credit. Never publishes.
options.destination_status defaults to publish. options.include_tracking may only be true or omitted (tracking is always applied).
Checks: write capability (api.publishing.enabled) → brand → content in brand → destination in brand, channel not frozen (403), healthy (409 integration_not_ready).
Produces warnings, which make status: "invalid":
Warning code | When |
|---|---|
| Channel cannot take this content type |
| Status not |
|
|
Response: publishing_preview with changed_fields (title, body, excerpt, slug, tags, plus featured_media if a cover exists), preserved_fields (product_references for self-hosted WordPress with a content profile), warnings, would_publish, a content_fingerprint (SHA-256 of title, slug, excerpt, body and tags) and expires_at (1 hour). Invalid previews are stored and charged too.
POST /v1/brands/{brand_id}/publishing/operations (publishing:write, beta)
Headers: Idempotency-Key (required). Costs 3 credits. External side effect.
Body | Rules |
|---|---|
| UUID in the brand |
|
|
| UUID; required when the flag |
|
|
| must be |
|
|
The server re-validates everything: scope, brand, destination health and freeze, content-type compatibility (422), draft support (422), content readiness (409 invalid_state). If a preview is used, it must belong to this owner and brand, match the content and integration, be valid, be unexpired, and its fingerprint must equal the current content (409 invalid_state, so create a new preview). Then: atomic admission including the per-channel in-flight cap → content_publications row (pending) → api_publishing_operations row → enqueue with attempts: 1.
Response 202: publishing_operation (accepted) with operation_id and job_id.
Duplicate protection: the same idempotency key never creates a second operation. API publish jobs never auto-retry. WordPress adapters do a slug read-before-write for API jobs.
GET /v1/brands/{brand_id}/publishing/operations/{operation_id}
Scopes (any): jobs:read, publishing:write. Derives and persists the current state from the publication row and the queue:
|
| Meaning |
|---|---|---|
| null | Waiting |
| null | Worker is publishing |
|
| Provider accepted but no URL to verify yet |
|
| Published; |
|
| See |
| null | Queue job failed or is missing without a publication outcome — needs operator triage |
| null | Cancelled before publishing |
awaiting_verification is true until verified, failed or cancelled.