Skip to content

Statuses

status tracks where a content object sits in the review-and-publish pipeline.

StatusMeaningSet by
draftBeing edited. Not queued to publish. The default on create.client
pending_reviewSubmitted for approval. Visible in the review queue.client
approvedApproved. Eligible to be scheduled and published.client
scheduledHas a scheduled_for. The publish cron will claim it.client
publishingThe cron has claimed the item and is calling platform APIs.cron
publishedAt least one platform accepted the post.cron
rejectedTurned down in review. Not published, still retrievable.client
archivedSoft-deleted. Hidden from list results.DELETE

Those eight are the full set.

There is no failed status. When every targeted platform rejects a post, the cron returns the item to approved — not to a terminal failure state. Per-leg failure detail lives on the publishing-queue row and in the content.publish_failed webhook, not on the content object.

There is also no deleted status; deletion is archived.

  • POST /contentdraft (default), pending_review, approved, scheduled.
  • PATCH /content/{id} — the same four plus rejected.
  • Neither accepts publishing, published, or archived. Those belong to the cron and to DELETE.

The API does not implement a state machine. Any PATCH may move an item from any client-settable status to any other — published straight back to draft, rejected to scheduled, whatever you send. Nothing returns a 409 for an “illegal” content transition.

The practical path is still the obvious one:

draft -> pending_review -> approved -> scheduled -> publishing -> published
draft -> approved (skip review)
draft -> scheduled (skip both; set scheduled_for too)
any -> rejected (turn it down)
any -> archived (via DELETE)

Campaigns are state-checked — POST /campaigns/{id}/launch rejects anything that is not draft or paused with 409 invalid_state. Content is not.

publishing and published are written by the cron worker, never by clients. Move an item to scheduled (or call POST /content/{id}/publish) and wait.

The cron claims work by atomically flipping scheduled to publishing, so only one worker ever picks up an item. If a claim goes stale — still publishing, untouched for 15 minutes — the next run returns it to scheduled and it is retried.

POST /content/{id}/publish does not run the pipeline inline. It sets the item to approved (or scheduled, if you pass scheduled_for), returns 202, and leaves the actual posting to the cron. See Content.

To move a scheduled item, PATCH it with a new scheduled_for. The cron re-evaluates on the new slot.

Nothing stops you from patching an item that is already publishing, but the cron has claimed it by then and the edit will not stop the in-flight run.

Terminal window
curl "https://app.nativpost.com/api/v1/content?status=scheduled&limit=50" \
-H "Authorization: Bearer $NATIVPOST_API_KEY"

The filter takes a single value. Repeating ?status=scheduled&status=publishing does not union them — only the first value is read and the second is ignored. To span several statuses, make one request per status.

archived items are excluded from GET /content unconditionally, and there is no parameter to include them. Retrieving one by id with GET /content/{id} still works.