All public agent-spend errors use this shape:
{
"error": {
"code": "rate_limited",
"message": "Rate limit exceeded",
"details": {}
}
}
#Error catalog
These are transport-level errors: the request failed and the response body uses the error envelope above.
| Code | HTTP | Meaning | Retry? | What to do |
|---|---|---|---|---|
invalid_api_key | 401 | Missing, malformed, or unknown Dino key | No | Check the Authorization: Bearer ... header and key value |
revoked_api_key | 403 | Spending key was revoked | No | Issue a new key and rotate the runtime |
insufficient_scope | 403 | Team API key is valid but lacks a required scope | No | Add spend.read, spend.write, or the route-specific scope |
invalid_request | 400 or 409 | Bad request body, unsupported state transition, or idempotency misuse | Sometimes | Fix the payload, or retry with the same idempotency key if the original request may have succeeded |
idempotency_key_conflict | 409 | The same idempotency key was reused for a different logical request | No | Keep one key per logical operation; generate a new key only after correcting the request |
not_found | 404 | Spend request, checkout intent, payout intent, recipient, or account not found in the current scope | No | Check the identifier and owning account/team |
funding_source_budget_exceeded | 402 | Parent funding-source limit would be exceeded | No | Top up or increase the funding-source limit |
plan_spend_volume_exceeded | 402 | Workspace plan cap for monthly agent-spend volume was exceeded | No | Reduce spend volume or upgrade plan limits |
insufficient_wallet_balance | 402 | Cash wallet available balance is too low | No | Add funds; in sandbox use /v1/sandbox/faucet with a din_test_ key |
policy_declined | 402 or 409 | Policy blocked the requested action before it became an approved spend or payout | No | Show the operator the policy reason and request a corrected amount, merchant, or approval path |
rate_limited | 429 | Too many requests in a short period | Yes | Back off and retry |
internal_error | 500 | Unexpected server error | Yes | Retry with backoff while preserving the idempotency key |
#Business declines vs HTTP errors
Cash declines can appear in two different ways:
- HTTP error envelope: the API cannot create or advance the object. Example:
insufficient_wallet_balance,funding_source_budget_exceeded, or malformed input. - Successful response with declined status: the object exists and policy made a decision. Example:
POST /v1/spend-requestsreturns200withstatus: "declined"and adecision_reason.
Do not treat every decline as an exception. If a spend request, checkout intent, or payout intent is returned with a business status, persist its id, show the decision_reason / pending_reason, and reconcile by webhook or readback route.
Common cash decision fields:
| Field | Where | Meaning |
|---|---|---|
status | Spend request / checkout response | approved, declined, needs_approval, or later lifecycle state |
decision_reason | Spend request / checkout response | Human-readable policy explanation |
remaining_budget_cents | Spend request response | Budget remaining after the decision model |
approval_url | Pending approval responses | Dashboard URL for a human operator |
Common crypto decision fields:
| Field | Where | Meaning |
|---|---|---|
status | Payout intent | needs_approval, approved, awaiting_signature, submitted, completed, failed, declined, cancelled, or expired |
pending_reason | Payout intent | Why a payout is waiting |
failure_reason | Payout intent | Why a payout failed |
tx_signature | Payout intent | Chain transaction signature when submitted |
#Retry guidance
- Retry
429and500with exponential backoff. - Preserve the same idempotency key when retrying creating
POSTcalls such as/v1/spend-requests,/v1/checkout/intents, and/v1/crypto/payout-intents. - Do not blindly retry
401,403,404, or402responses. - If you receive
409 invalid_requestfrom conflicting idempotency reuse, generate a new idempotency key and send a corrected payload.
#Idempotency guidance
For creating requests, always send an Idempotency-Key header or idempotency_key field.
- Same key + same logical request: safe replay, returns the original spend request
- Reused key for a conflicting request: returns
invalid_request
Use one source of truth for retries:
- Network timeout / unknown outcome: retry with the same idempotency key.
- Confirmed conflicting payload (
409 invalid_request): fix payload, then retry with a new key.
#Funding limit details
When Dino returns funding_source_budget_exceeded, the details object can include:
limitspentremainingperiodwindowStartwindowEnd
Use those fields to explain the failure to operators or automation logs.