Approval requests raised by checkpoints on guarded operations (refunds, wallet adjustments, scheduled changes with gate: approval, …). A gated call answers 202 with an approval_request_id; read the request here, or wait for the approval.* webhook events whose request_id is that id. Deciding, cancelling and retrying a request is a person's act in the dashboard: an API key cannot decide.
List approval checkpoints
Deprecated: use GET /approvals/checkpoints instead. Removed on 2026-11-30.
One entry per operator-configurable checkpoint the running code implements. This is a projection of the compiled registry, not a table an operator can add to: there is no create operation, and a checkpoint whose id left the code is absent here while its historical requests still read.
Each entry carries the read-only declaration (the domain permission a decider must hold, the threshold kind, the expiry policy) and the decider pool resolved under the workspace's approver role. The configuration itself — the switch, the threshold and the approver role — is the approval.<checkpoint>.* settings family: read it from GET /organization/settings and write it through PUT /organization/settings, which refuses switching a checkpoint on with fewer than two eligible deciders (422 NO_ELIGIBLE_APPROVERS) or an approver role that lacks the domain permission (422 ROLE_LACKS_PERMISSION). Render api_key_notice next to the switch BEFORE it is flipped: enabling a checkpoint makes the gated operation impossible for API-key callers, which is the one adoption consequence an operator must not discover afterwards.
include=display adds the card's text: scope, expiry_notice, api_key_notice, domain_permission_label and eligible_decider_names. Until 2026-11-30 the text is also sent without being asked; after that date it is sent only when named.
Required scope: approval.read (See the approval queue).
query Parameters
includeExtra data to add to the response: display. Send a comma-separated list or repeat the parameter. An unknown name is refused with 400. display is sent without being asked until 2026-11-30; after that date it is sent only when named here.
Headers
X-Workspace-IdSelects the workspace this request operates in, by workspace UUID or slug (e.g. a sandbox workspace for test integrations). Omitted: the organization's default live workspace. Unknown workspace: 404; workspace outside your organization: 403. Discover workspaces via GET /workspaces.
Workspace UUID or slug.
List approval checkpoints › Responses
OK
List approval requests
Cursor-paginated approval requests, newest first, in the standard list envelope. Column filters use the unified field.op=value grammar (status, checkpoint_id, subject_kind, subject_id, initiated_by, apply_state, currency, created_at, expires_at, resolved_at, updated_at).
assigned=me is the axis that makes the queue actionable: it returns only the PENDING requests this caller may actually decide — raised at a checkpoint they are eligible for, and not raised by them, because nobody decides their own request. Every row carries the headline, the subline and the amount, so the list is readable without opening each request.
A row has the same shape as get-approval. include adds facts, lines, decisions (the whole trail), process and actions. Until 2026-11-30 a row also sends decisions and process without being asked; after that date each is sent only when named.
initiated_by and decisions[].decided_by are user ids today. From 2026-11-30 each is the person as a UserRef {id, name, email}, sent with include=initiated_by and include=decisions.decided_by; read the ids from initiated_by_id and decided_by_id, which stay. The list filter initiated_by keeps its name and takes the user id.
Required scope: approval.read (See the approval queue).
query Parameters
apply_stateFilter on apply_state (enum). Operators: eq, ne, in — dot grammar, e.g. apply_state.ne=value; a bare apply_state=value means eq. A bare comma-separated value is in-sugar: apply_state=a,b means apply_state.in=a,b. Legal values: NOT_APPLICABLE, PENDING, DONE, FAILED.
checkpoint_idFilter on checkpoint_id (enum). Operators: eq, ne, in — dot grammar, e.g. checkpoint_id.ne=value; a bare checkpoint_id=value means eq. A bare comma-separated value is in-sugar: checkpoint_id=a,b means checkpoint_id.in=a,b. Legal values: quote.send, invoice.refund, wallet.adjust, change.gate.
created_atFilter on created_at (date-time). Operators: eq, gt, gte, lt, lte — dot grammar, e.g. created_at.gt=value; a bare created_at=value means eq.
currencyFilter on currency (string). Operators: eq, in — dot grammar, e.g. currency.in=value; a bare currency=value means eq. A bare comma-separated value is in-sugar: currency=a,b means currency.in=a,b.
expires_atFilter on expires_at (date-time). Operators: gt, gte, lt, lte — dot grammar, e.g. expires_at.gt=value; a bare expires_at=value means eq.
initiated_byFilter on initiated_by (string). Operators: eq, ne, in — dot grammar, e.g. initiated_by.ne=value; a bare initiated_by=value means eq. A bare comma-separated value is in-sugar: initiated_by=a,b means initiated_by.in=a,b.
resolved_atFilter on resolved_at (date-time). Operators: eq, gt, gte, lt, lte — dot grammar, e.g. resolved_at.gt=value; a bare resolved_at=value means eq.
subject_idFilter on subject_id (uuid). Operators: eq, in — dot grammar, e.g. subject_id.in=value; a bare subject_id=value means eq. A bare comma-separated value is in-sugar: subject_id=a,b means subject_id.in=a,b.
subject_kindFilter on subject_kind (enum). Operators: eq, in — dot grammar, e.g. subject_kind.in=value; a bare subject_kind=value means eq. A bare comma-separated value is in-sugar: subject_kind=a,b means subject_kind.in=a,b. Legal values: quote, invoice, wallet, change.
updated_atFilter on updated_at (date-time). Operators: eq, gt, gte, lt, lte — dot grammar, e.g. updated_at.gt=value; a bare updated_at=value means eq.
includeExtra data to add to the response: facts, lines, decisions, process, actions, initiated_by, decisions.decided_by. Send a comma-separated list or repeat the parameter. An unknown name is refused with 400. decisions is sent without being asked until 2026-11-30; after that date it is sent only when named here. process is sent without being asked until 2026-11-30; after that date it is sent only when named here. initiated_by is sent without being asked until 2026-11-30; after that date it is sent only when named here. decisions.decided_by is sent without being asked until 2026-11-30; after that date it is sent only when named here.
limitPage size. Values above the server-side cap are clamped (standard default 50, cap 200; a few document-heavy lists use larger windows). Invalid values fall back to the default.
cursorOpaque continuation token from the previous response's pagination.cursor. Omit for the first page. Cursors are stateless and do not expire, but are only valid for the list and filters that produced them.
statusFilter by status. Filterable fields (status, checkpoint_id, subject_kind, subject_id, initiated_by, apply_state, currency, created_at, expires_at, resolved_at, updated_at) accept apifilter operator suffixes in the dot grammar, e.g. status.in=APPROVED,REJECTED
assignedSet to "me" to return only the pending requests this caller may actually decide. Implies status=PENDING and excludes the caller's own requests (nobody decides their own).
searchCase-insensitive substring match over the data in the request's headline — the record's number, the customer, the amount — e.g. "QUO-2026". Not over the rendered sentence, which differs per locale.
sortOrdering: checkpoint_id, headline, amount, expires_at or status, each with an optional :asc/:desc suffix (bare means :asc). Default is created_at:desc, also accepted by name. An unknown value is rejected. amount orders by currency first, then value — amounts in different currencies are not comparable. Rows with no value for the sorted column group last under :asc and first under :desc. Cursors are bound to the ordering that issued them, so changing sort mid-walk needs a fresh first page.
Headers
X-Workspace-IdSelects the workspace this request operates in, by workspace UUID or slug (e.g. a sandbox workspace for test integrations). Omitted: the organization's default live workspace. Unknown workspace: 404; workspace outside your organization: 403. Discover workspaces via GET /workspaces.
Workspace UUID or slug.
List approval requests › Responses
OK
List approval checkpoints
One entry per operator-configurable checkpoint the running code implements. This is a projection of the compiled registry, not a table an operator can add to: there is no create operation, and a checkpoint whose id left the code is absent here while its historical requests still read.
Each entry carries the read-only declaration (the domain permission a decider must hold, the threshold kind, the expiry policy) and the decider pool resolved under the workspace's approver role. The configuration itself — the switch, the threshold and the approver role — is the approval.<checkpoint>.* settings family: read it from GET /organization/settings and write it through PUT /organization/settings, which refuses switching a checkpoint on with fewer than two eligible deciders (422 NO_ELIGIBLE_APPROVERS) or an approver role that lacks the domain permission (422 ROLE_LACKS_PERMISSION). Render api_key_notice next to the switch BEFORE it is flipped: enabling a checkpoint makes the gated operation impossible for API-key callers, which is the one adoption consequence an operator must not discover afterwards.
include=display adds the card's text: scope, expiry_notice, api_key_notice, domain_permission_label and eligible_decider_names. Until 2026-11-30 the text is also sent without being asked; after that date it is sent only when named.
Required scope: approval.read (See the approval queue).
query Parameters
includeExtra data to add to the response: display. Send a comma-separated list or repeat the parameter. An unknown name is refused with 400. display is sent without being asked until 2026-11-30; after that date it is sent only when named here.
Headers
X-Workspace-IdSelects the workspace this request operates in, by workspace UUID or slug (e.g. a sandbox workspace for test integrations). Omitted: the organization's default live workspace. Unknown workspace: 404; workspace outside your organization: 403. Discover workspaces via GET /workspaces.
Workspace UUID or slug.
List approval checkpoints › Responses
OK
Get an approval request
One approval request, in the shape list-approvals returns. include adds the typed facts the decision turns on (unusual marks the ones that should stop a fast approver), the money lines behind it, the decision trail, where the subject stands in its own process (read from the subject), and actions: what the calling user may do with it, so decision controls can be disabled with an explanation instead of failing on click. Until 2026-11-30 facts, lines, decisions and process are also sent without being asked; after that date each is sent only when named.
initiated_by and decisions[].decided_by are user ids today. From 2026-11-30 each is the person as a UserRef {id, name, email}, sent with include=initiated_by and include=decisions.decided_by; read the ids from initiated_by_id and decided_by_id, which stay. The list filter initiated_by keeps its name and takes the user id.
Required scope: approval.read (See the approval queue).
path Parameters
idApproval request UUID
query Parameters
includeExtra data to add to the response: facts, lines, decisions, process, actions, initiated_by, decisions.decided_by. Send a comma-separated list or repeat the parameter. An unknown name is refused with 400. facts is sent without being asked until 2026-11-30; after that date it is sent only when named here. lines is sent without being asked until 2026-11-30; after that date it is sent only when named here. decisions is sent without being asked until 2026-11-30; after that date it is sent only when named here. process is sent without being asked until 2026-11-30; after that date it is sent only when named here. initiated_by is sent without being asked until 2026-11-30; after that date it is sent only when named here. decisions.decided_by is sent without being asked until 2026-11-30; after that date it is sent only when named here.
Headers
X-Workspace-IdSelects the workspace this request operates in, by workspace UUID or slug (e.g. a sandbox workspace for test integrations). Omitted: the organization's default live workspace. Unknown workspace: 404; workspace outside your organization: 403. Discover workspaces via GET /workspaces.
Workspace UUID or slug.
Get an approval request › Responses
OK