Approvals
Generated HTTP reference for the 3 operations the published OpenAPI document describes under approvals.
Approvals
This page is generated from the published OpenAPI document. It is complete with respect to that document and says nothing about surfaces the document does not describe yet. See what is generated here for what that means.
Base URL: https://api.codespar.dev
Every operation below requires a Bearer token. See Authentication.
These three reads follow a held call: a policy rule or a non-overridable guard stopped a spend before dispatch and wrote an approval row with an expiry. Poll GET /v1/approvals/{id}/status until it leaves pending. The write that decides it, POST /v1/orgs/{orgId}/approvals/{id}/decide, is not in this document and refuses API keys on purpose: the key that asked for a spend must not be the key that approves it. Who decides, where, and the pattern for confirming a one-off spend in your own channel before dispatch are on the concept page, Mandates, receipts and approvals, and in Guardrails.
Every operation, from the spec
Generated from the published OpenAPI document, so it never drifts from what the API actually serves. The section above is written by hand and carries what a schema cannot: the object model, field rules, and the order to call things in.
GET /v1/approvals/health
https://api.codespar.dev/v1/approvals/healthApproval queue health
Responses
| Status | Body | Description |
|---|---|---|
200 | object | OK |
Response 200
| Field | Type | Required | Description |
|---|---|---|---|
last_sweep_at | string,null (date-time) | yes | Deployment-wide, not per-organization. See the description. |
oldest_pending_age_seconds | integer,null | yes | Age of the oldest pending hold, in seconds. Null when none is pending. |
pending_count | integer | yes | — |
status | "ok" | yes | — |
curl -X GET https://api.codespar.dev/v1/approvals/health \
-H "Authorization: Bearer $CODESPAR_API_KEY"const res = await fetch("https://api.codespar.dev/v1/approvals/health", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.CODESPAR_API_KEY}`,
},
});
const data = await res.json();const result = await cs.api.get("/v1/approvals/health");{
"status": "ok",
"pending_count": 1
}GET /v1/approvals/{id}
https://api.codespar.dev/v1/approvals/{id}Read one approval
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | string | yes | — |
Responses
| Status | Body | Description |
|---|---|---|
200 | object | OK |
404 | object | Not Found |
Response 200
| Field | Type | Required | Description |
|---|---|---|---|
agent_id | string | yes | — |
created_at | string (date-time) | yes | — |
decided_at | string,null (date-time) | yes | — |
decided_by | string,null | yes | The approver, null while pending. |
decision_reason | string,null | yes | — |
executed_at | string,null (date-time) | yes | — |
execution_result | object,null | yes | Null until an approved call has been replayed. Open shape, passed through verbatim. |
expires_at | string (date-time) | yes | When the hold stops being decidable. |
id | string | yes | apv_ + nanoid(16). |
matched_rule_id | string | yes | The policy rule that held the call. |
matched_rule_name | string | yes | — |
org_id | string | yes | — |
project_id | string,null | yes | Null for a hold raised outside any project. |
session_id | string,null | yes | — |
status | "pending" | "approved" | "denied" | "expired" | "execution_failed" | yes | — |
tool_input | object | yes | The arguments as RECORDED, which is not always the arguments as sent. Empty for a hold raised on the session execute path, and header-stripped on the proxy path. |
tool_name | string | yes | The held call, in whatever form the lane that raised the hold writes. There is no single format: see the operation description before matching on it. |
curl -X GET https://api.codespar.dev/v1/approvals/{id} \
-H "Authorization: Bearer $CODESPAR_API_KEY"const res = await fetch("https://api.codespar.dev/v1/approvals/{id}", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.CODESPAR_API_KEY}`,
},
});
const data = await res.json();const result = await cs.api.get("/v1/approvals/{id}", {
path: {
id: "approval_0000000000000000"
}
});{
"id": "obj_0000000000000000",
"org_id": "org_0000000000000000",
"agent_id": "agt_0000000000000000",
"matched_rule_id": "matchedrule_0000000000000000",
"matched_rule_name": "Example",
"tool_name": "Example",
"tool_input": {},
"status": "pending",
"created_at": "2026-01-15T12:00:00.000Z",
"expires_at": "2026-01-15T12:00:00.000Z"
}GET /v1/approvals/{id}/status
https://api.codespar.dev/v1/approvals/{id}/statusPoll a held call for its outcome
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | string | yes | — |
Responses
| Status | Body | Description |
|---|---|---|
200 | object | OK |
404 | object | Not Found: no approval with that id in the caller's org and project. |
Response 200
| Field | Type | Required | Description |
|---|---|---|---|
approval_id | string | yes | — |
approval_status | "pending" | "approved" | "denied" | "expired" | "execution_failed" | yes | — |
created_at | string (date-time) | yes | — |
decided_at | string,null (date-time) | yes | — |
decided_by | string,null | yes | — |
decision_reason | string,null | yes | — |
executed_at | string,null (date-time) | yes | — |
execution_result | object,null | yes | — |
expires_at | string (date-time) | yes | — |
tool_name | string | yes | — |
curl -X GET https://api.codespar.dev/v1/approvals/{id}/status \
-H "Authorization: Bearer $CODESPAR_API_KEY"const res = await fetch("https://api.codespar.dev/v1/approvals/{id}/status", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.CODESPAR_API_KEY}`,
},
});
const data = await res.json();const result = await cs.api.get("/v1/approvals/{id}/status", {
path: {
id: "approval_0000000000000000"
}
});{
"approval_id": "approval_0000000000000000",
"approval_status": "pending",
"tool_name": "Example",
"created_at": "2026-01-15T12:00:00.000Z",
"expires_at": "2026-01-15T12:00:00.000Z"
}