Agent approval API — inspect, approve, and reject paused agent invocations
REST and MCP endpoints for the CitationBench agent approval queue. List pending approvals, approve (optionally with edits), reject (optionally with rerun config), or comment without deciding.
The endpoints for inspecting, approving, and rejecting paused agent invocations. The conceptual model — when agents pause, how to set policy, how eval gates relate — lives in Approval Workflows and Eval Gates.
Endpoints
| Method | Path | Purpose |
|---|---|---|
| GET | /v1/agent/approvals | List pending approvals |
| GET | /v1/agent/approvals/{approvalId} | Get one |
| POST | /v1/agent/invocations/{id}/approve | Approve (optionally with edits) |
| POST | /v1/agent/invocations/{id}/reject | Reject (optionally with rerun config) |
| POST | /v1/agent/approvals/{approvalId}/comment | Add a comment without deciding |
GET /v1/agent/approvals
List pending approvals across the workspace (or, for agency master keys, across the whole agency).
curl -G "https://api.citationbench.com/v1/agent/approvals" \
-H "Authorization: Bearer sk_live_***" \
--data-urlencode "scope=workspace" \
--data-urlencode "skill=link_building.serp_outreach"| Param | Notes |
|---|---|
scope | workspace (default), agency (master keys only) |
skill | Filter by skill slug |
routedTo | Filter by approver user / channel |
raisedAfter / raisedBefore | ISO timestamps |
tag | Filter by invocation tag |
limit, cursor | Pagination |
Response
{
"data": [
{
"approvalId": "appr_01HVZ...",
"invocationId": "inv_01HVZ...",
"agentId": "agt_01HVZ...",
"skill": "link_building.serp_outreach",
"step": "send_outreach_email",
"preview": {
"to": "marina@engineering-blog.com",
"subject": "Section 7 of your PM tools roundup",
"body": "Hi Marina, ...",
"scheduledAt": "2026-05-25T09:00:00-04:00"
},
"reason": "Workspace policy: outreach_send=require_approval",
"routedTo": ["raymond@acme.com"],
"raisedAt": "2026-05-24T08:14:32Z",
"timeoutAt": "2026-05-31T08:14:32Z",
"comments": []
}
],
"nextCursor": null,
"total": 14
}GET /v1/agent/approvals/{approvalId}
Returns the same single record plus the full invocation context (tree, prior steps, files written so far).
curl https://api.citationbench.com/v1/agent/approvals/appr_*** \
-H "Authorization: Bearer sk_live_***"POST /v1/agent/invocations/{id}/approve
curl -X POST https://api.citationbench.com/v1/agent/invocations/inv_***/approve \
-H "Authorization: Bearer sk_live_***" \
-H "Content-Type: application/json" \
-d '{
"approvalId": "appr_***",
"note": "Looks good, ship it."
}'With edits
curl -X POST https://api.citationbench.com/v1/agent/invocations/inv_***/approve \
-d '{
"approvalId": "appr_***",
"edits": {
"subject": "Quick thought on your PM roundup",
"body": "Hi Marina, loved your roundup. Quick note on section 7 ..."
},
"note": "Softened opener"
}'The edits object is shape-validated against the preview. Any field you can edit is also shown in the preview's editableFields.
Trust hint
curl -X POST .../v1/agent/invocations/inv_***/approve \
-d '{
"approvalId": "appr_***",
"trustHenceforth":"contact"
}'trustHenceforth values:
contact— future actions toward the same contact auto-approveaccount— future actions toward the same partner domain auto-approvestep— future invocations of the same skill step auto-approve (for this workspace)none— no trust hint (default)
Response
{
"approvalId": "appr_***",
"decision": "APPROVED",
"decidedAt": "2026-05-24T09:02:18Z",
"approver": "raymond@acme.com",
"edited": true,
"trustGranted": null,
"invocation": {
"invocationId": "inv_***",
"status": "RUNNING",
"resumeAt": "2026-05-24T09:02:18Z"
}
}POST /v1/agent/invocations/{id}/reject
Reject + skip the step
curl -X POST .../v1/agent/invocations/inv_***/reject \
-d '{
"approvalId": "appr_***",
"skipStep": true,
"note": "Wrong contact — please skip"
}'If skipStep: true, the skill may continue past the rejected step. Otherwise, the invocation transitions to FAILED.
Reject + rerun the step with different config
curl -X POST .../v1/agent/invocations/inv_***/reject \
-d '{
"approvalId": "appr_***",
"rerun": {
"step": "drafts",
"config": { "tone": "more skeptical" }
},
"note": "Re-draft with a more skeptical tone"
}'Response
{
"approvalId": "appr_***",
"decision": "REJECTED",
"decidedAt": "2026-05-24T09:02:18Z",
"approver": "raymond@acme.com",
"invocation": {
"invocationId": "inv_***",
"status": "RUNNING",
"rerunStep": "drafts"
}
}POST /v1/agent/approvals/{approvalId}/comment
Add a comment without making a decision (useful for routing back to a colleague or stalling for context).
curl -X POST .../v1/agent/approvals/appr_***/comment \
-d '{
"author": "raymond@acme.com",
"comment": "@marketing — does the offer in section 3 still hold?"
}'Comments append to the approval's comments array. They don't change the invocation's state.
MCP
> What's in my approval queue?Claude calls agent.approval.list.
> Show me the first one.Claude calls agent.approval.get and renders the preview.
> Approve it.Claude calls agent.approval.approve.
> Reject it and tell the agent to rewrite the email with a more skeptical tone.Claude calls agent.approval.reject with the rerun directive.
Errors
| Status | Code | Cause |
|---|---|---|
| 404 | approval_not_found | — |
| 409 | already_decided | Approval was already approved / rejected (race condition) |
| 410 | approval_timed_out | Approval timed out before action; the invocation was cancelled |
| 422 | invalid_edits | edits payload doesn't match the preview's editableFields |
| 422 | invalid_rerun_step | rerun.step doesn't exist on the skill |
Cost
| Action | Credits |
|---|---|
| All approval actions | free |
(The invocation continues to bill once it resumes.)
Common patterns
1. Slack-button approval
Wire agent.invocation.awaiting_approval webhook to a small Slack bot. It posts the preview with Approve / Reject buttons. Button clicks POST back to /v1/agent/invocations/{id}/approve or /reject.
2. Client-portal approval
Webhook target is a small service in your client portal. The client sees the preview in their familiar UI, clicks approve, your service POSTs to the API.
3. Bulk approval
For SERP outreach campaigns and similar bulk drafts, use the campaign-level bulk endpoints (Link Building · serp outreach § approve drafts) rather than approving N invocations individually.
4. Approval audit
curl -G .../v1/agent/approvals \
--data-urlencode "scope=agency" \
--data-urlencode "raisedAfter=2026-05-01T00:00:00Z" \
--data-urlencode "include=decisions"Returns approvals with their decision history — useful for monthly client review.
Related
- Concept: Approval Workflows
- Concept: Eval Gates
- API: Agent · invoke
- API: Webhooks
- Playbook: Client-approval gated publishing
Files
Upload PDFs, CSVs, transcripts, and briefs as agent inputs, and read back artifacts the agent wrote during a run. Files are addressed by path, scoped per workspace.
Keyword
Run agentic keyword discovery jobs, then label every keyword on the 2D intent × relevance axes and manage your full persistent keyword library with CRUD, rank tracking, and bulk operations.