Layers
Partner APIConcepts

Content review

How the content-review gate works, what its three modes do, where it's enforced, and how to read the queue.

View as Markdown

Content review is the checkpoint between "content generated" and "content leaves the building." It's a flag on each content item and a policy on each project. The API enforces the gate; you build the review UX.

The policy — three modes

Every project has a content-review policy with one of three values:

policyWhat it does
auto_approveGenerated content is publish-ready immediately. No human in the loop.
review_first_nFirst N items require human approval. Once N have cleared review, every subsequent item auto-approves. Uses firstN to pick N.
review_allEvery item requires human approval, forever.

Pick auto_approve for full autonomy, review_first_n to validate the first batch from a new project / influencer / brand brief and then let the optimizer fly, and review_all for regulated verticals where every post must be human-checked before it ships.

firstN is required when policy is review_first_n and forbidden otherwise — the API returns 422 VALIDATION on either violation.

The gate

Two things decide whether a content item can be scheduled:

  1. Project policy. Set on the project's content-review policy resource (above).
  2. Content status. Every content item has an approvalStatus of not_required | pending | approved | rejected. New containers on a review_* project start at pending; the rest default to not_required.

The gate triggers on POST /v1/content/:containerId/schedule (and on /publish, which is just "schedule with scheduledFor: now"). If the container is pending, the schedule call is refused with 403 APPROVAL_REQUIRED until the container flips to approved. If the container is rejected, the call is refused with 409 CONTENT_REJECTED permanently.

approvalStatus === 'pending'   →  403 APPROVAL_REQUIRED on schedule
approvalStatus === 'rejected'  →  409 CONTENT_REJECTED on schedule

Approval is enforced at the schedule endpoint and at the just-before-publish check. Use the schedule endpoint for any publish flow that should respect the gate.

pendingCount is the queue depth

The policy resource also reports a server-computed pendingCount — the number of containers in this project that are currently sitting in approvalStatus: "pending". Read-only, useful for rendering "N items awaiting review" in your UI.

For review_first_n, the gate self-disables once the project has seen firstN containers move out of pending (any terminal state — approved, rejected — counts). Subsequent generations land at not_required automatically. This is checked at content-creation time, not at schedule time.

Approving and rejecting

POST /v1/content/:containerId/approve
{
  "note": "On-brand, clean caption"
}

POST /v1/content/:containerId/reject
{
  "reason": "Wrong influencer for this product"
}
  • approve flips approvalStatus to approved, stamps approvedAt and approvedBy (the API key id that approved), persists the optional note (max 1024 chars).
  • reject flips approvalStatus to rejected, stamps rejectedAt and rejectedBy (API key id), persists reason (required, 1–1024 chars). Rejected containers stay in the project for audit — they don't get deleted. To produce a new take, call POST /v1/projects/:id/content again with a fresh hook.

Actor attribution: both endpoints return approvedBy / rejectedBy from the calling API key. If you're building a review UI with multiple human reviewers, persist the reviewer's identity in your own system.

Rejection is a terminal decision for that container. Calling schedule or publish against a rejected container returns 409 CONTENT_REJECTED — the gate never opens for it, even if project policy later changes.

Once scope enforcement ships, these endpoints will require content:approve. Today, org-scoped keys can call them directly.

Reading and patching the policy

GET /v1/projects/:projectId/content-review-policy
→ 200
{
  "projectId": "5e9c0b1e-...",
  "policy": "review_first_n",
  "firstN": 3,
  "pendingCount": 1,
  "updatedAt": "2026-04-25T22:55:10.996Z"
}

Patch with PATCH to change the policy. Send the new policy (and firstN if applicable):

PATCH /v1/projects/:projectId/content-review-policy
{
  "policy": "review_first_n",
  "firstN": 5
}

To switch off the gate entirely:

PATCH /v1/projects/:projectId/content-review-policy
{
  "policy": "auto_approve"
}

Sending firstN together with auto_approve or review_all returns 422 VALIDATION with a clear details.issues pointer at firstN.

On this page