Layers
Partner APIAPI referenceApproval

POST /v1/content/:containerId/approve

Flip a container's approval status to approved so it can be scheduled.

View as Markdown
POST/v1/content/:containerId/approve
Phase 1stable
Auth
Bearer

Flips approvalStatus from pending to approved and stamps the reviewer. From the moment this call returns, the container is schedulable. There's no per-container counter to decrement — the first-N gate is a re-evaluated COUNT() of how many containers on the project have moved out of pending; approving (or rejecting) is what nudges that count.

This call is what unblocks schedule-content when the project's approval policy requires review. Without approval, scheduling returns APPROVAL_REQUIRED.

Path parameters

  • containerId
    string (uuid)required
    The container to approve.

Body

Body (all optional)
  • note
    stringoptional
    Free-text note, max 1024 chars. Stored on the container for audit.

Request

terminal
curl -X POST https://api.layers.com/v1/content/{containerId}/approve \
  -H "Authorization: Bearer $LAYERS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "note": "Looks good. Shipping tomorrow 7am." }'
approve.ts
const res = await fetch(
  `https://api.layers.com/v1/content/${containerId}/approve`,
  {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.LAYERS_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ note: 'Approved by agent.' }),
  },
);
const result = await res.json();
approve.py
import os, httpx

r = httpx.post(
    f"https://api.layers.com/v1/content/{container_id}/approve",
    headers={
        "Authorization": f"Bearer {os.environ[\'LAYERS_API_KEY\']}",
        "Content-Type": "application/json",
    },
    json={"note": "Approved."},
)
result = r.json()

Responses

200Approved. The container is ready to schedule.
{
  "id": "cnt_7d18b9a1...",
  "approvalStatus": "approved",
  "approvedAt": "2026-04-18T09:40:12Z",
  "approvedBy": "api_key_c2037bb9..."
}
200Approved AND a previously-blocked schedule was promoted to live scheduled_posts.
{
  "id": "cnt_7d18b9a1...",
  "approvalStatus": "approved",
  "approvedAt": "2026-04-18T09:40:12Z",
  "approvedBy": "api_key_c2037bb9...",
  "pendingSchedulePromotion": {
    "status": "ok",
    "scheduledPostIds": [
      "sp_b9b66cde-7c8e-43dc-a9d2-3f4e5a6b7c8d"
    ]
  }
}

If a pendingSchedulePromotion block is present with status: "failed", approval still flipped - but the queued schedule did not promote (e.g. the original target social account was removed). Re-issue schedule to re-create the rows.

409Container is already approved, rejected, or not in a reviewable state.
{
  "error": {
    "code": "CONFLICT",
    "message": "Container is already approved.",
    "requestId": "req_...",
    "details": { "approvalStatus": "approved" }
  }
}
409Container does not require approval (e.g. project policy is `auto_approve`, or the first-N gate self-disabled before this container was generated).
{
  "error": {
    "code": "CONFLICT",
    "message": "Container does not require approval.",
    "requestId": "req_...",
    "details": { "approvalStatus": "not_required" }
  }
}

approvalStatus: "not_required" means the container was never gated — it is already schedulable. There is nothing to approve. Skip this call and go straight to schedule or publish.

Notes

Approval is idempotent at the state level: if the container is already approved, we return 409 CONFLICT rather than a silent no-op. That way your logic knows whether this call flipped the bit or a prior one did.

  • Who can approve. Any org-scoped API key. Scope enforcement is forthcoming; until then any partner key with org access can call this endpoint.
  • First-N gate. When the project's content-review policy is review_first_n, the gate self-disables once firstN containers have moved out of pending (approved + rejected count). Subsequent generations land at approvalStatus: "not_required" automatically — no further approvals needed.
  • Publishing consequence. Approving doesn't publish. It just removes the gate. Schedule or publish now to actually put it on a surface.
  • Pending-schedule promotion. If schedule was called before approval, those targets were stashed on the container as pendingSchedule metadata and returned with gateStatus: "blocked_on_approval". This call promotes them to live scheduled_posts rows atomically - the scheduledPostIds you already received from schedule become the ids of the new rows. The response surfaces the outcome under pendingSchedulePromotion.

Errors

CodeWhen
CONFLICTContainer is already approved, rejected, or not reviewable.
VALIDATIONContainer isn't completed yet.
NOT_FOUNDContainer id not in this org.

See also

On this page