POST /v1/content/:containerId/reject
Reject a container. A reason is required.
/v1/content/:containerId/reject- Auth
- Bearer
Flips approvalStatus to rejected and stamps the reviewer. Rejected containers can't be scheduled. To produce a new take, call POST /v1/projects/:projectId/content with a fresh hook.
Path parameters
containerIdstring (uuid)requiredThe container to reject.
Body
reasonstringrequiredRejection note, 1–1024 chars. Stored on the container for audit.
Request
curl -X POST https://api.layers.com/v1/content/{containerId}/reject \
-H "Authorization: Bearer $LAYERS_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "reason": "Hook is off-brand; want something punchier." }'const res = await fetch(
`https://api.layers.com/v1/content/${containerId}/reject`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.LAYERS_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ reason: 'Needs a new angle.' }),
},
);
const result = await res.json();import os, httpx
r = httpx.post(
f"https://api.layers.com/v1/content/{container_id}/reject",
headers={
"Authorization": f"Bearer {os.environ[\'LAYERS_API_KEY\']}",
"Content-Type": "application/json",
},
json={"reason": "Off-brand hook."},
)
result = r.json()Responses
{
"id": "cnt_7d18b9a1...",
"approvalStatus": "rejected",
"rejectedAt": "2026-04-18T09:44:50Z",
"rejectedBy": "api_key_c2037bb9...",
"reason": "Hook is off-brand; want something punchier."
}{
"error": {
"code": "CONFLICT",
"message": "Container is already rejected.",
"requestId": "req_...",
"details": { "approvalStatus": "rejected" }
}
}{
"error": {
"code": "CONFLICT",
"message": "Container does not require approval.",
"requestId": "req_...",
"details": { "approvalStatus": "not_required" }
}
}approvalStatus: "not_required" means the container was never gated — there is nothing to reject. If you want to suppress an ungated container, skip schedule entirely or cancel it after the fact.
{
"error": {
"code": "VALIDATION",
"message": "Invalid body.",
"requestId": "req_...",
"details": { "issues": [{ "path": ["reason"], "message": "Required" }] }
}
}{
"error": {
"code": "VALIDATION",
"message": "Container status must be completed to reject.",
"requestId": "req_...",
"details": { "status": "processing" }
}
}The VALIDATION 422 has two distinct shapes: body-level (missing/empty reason — the schema rejects it before any DB read; details.issues[] carries Zod paths) and state-level (container exists and is approval-eligible but status !== "completed"; details.status carries the live status). Both share the same code; differentiate via details.
Notes
- Approved → rejected isn't supported. Once a container is
approved, rejecting it is aCONFLICT. If approved content is wrong, cancel any scheduled posts and call generate again with a freshhook. - Rejection counts toward the first-N threshold same as approval. Both are "this container moved out of pending". The counter measures throughput of human review, not net positive verdicts — so once
firstNcontainers have hit any terminal state (approved or rejected), the gate self-disables and subsequent generations land atnot_required. - To produce a new take, call
POST /v1/projects/:projectId/contentwith a freshhook.
Errors
| Code | When |
|---|---|
CONFLICT | Container is already rejected or approved. |
VALIDATION | Container isn't completed; or missing reason. |
NOT_FOUND | Container id not in this org. |