Canopy

GET /api/approvals/{id}/status

Most callers should use canopy.getApprovalStatus() or canopy.waitForApproval() instead. This page is for direct wire-protocol callers.

Returns the current state of an approval request. You get an approval_request_id from POST /api/sign when a payment exceeds the agent's approval threshold.

The endpoint is scoped to your org's API key. You can't read approval statuses for agents in other orgs.

Base URL: https://trycanopy.ai

Request

GET /api/approvals/{id}/status
Authorization: Bearer <apiKey>

Path parameters

ParamTypeDescription
idstringUUID of the approval request (the approval_request_id from /api/sign)

200 — status snapshot

{
  "status": "pending",
  "decided_at": null,
  "expires_at": "2026-04-28T11:00:00Z",
  "transaction_id": "550e8400-..."
}

After a decision:

{
  "status": "approved",
  "decided_at": "2026-04-28T10:32:11Z",
  "expires_at": "2026-04-28T11:00:00Z",
  "transaction_id": "550e8400-..."
}
FieldTypeDescription
statusstring"pending", "approved", "denied", or "expired"
decided_atstring | nullISO 8601 timestamp; null while pending
expires_atstringISO 8601 timestamp the approval window expires
transaction_idstringUUID of the associated transaction

404 — not found

Approval ID doesn't exist, or it belongs to an agent in a different org. The body has no detail to avoid leaking cross-org information.

Example

curl --request GET \
  --url "https://trycanopy.ai/api/approvals/550e8400-.../status" \
  --header "Authorization: Bearer ak_live_xxxxxxxxxxxxxxxx"

If you'd rather block until a decision arrives instead of polling, use canopy.waitForApproval(approvalId) (TS) or canopy.wait_for_approval(approval_id) (Py). Both poll this endpoint internally and throw CanopyApprovalTimeoutError if the timeout elapses (default 5 minutes).