Error codes
Every Velarum API failure returns a stable, semantic error.code. Codes are grouped by domain below; each row gives the HTTP status, what it means, a recovery hint, and whether the call was idempotency-safe (i.e. no state was created, so a clean retry is safe). This catalogue mirrors the canonical OpenAPI · DTO · Error-Code Spec §9; the Python SDK raises a typed exception per code (see Python SDK).
“Idempotency-safe = yes” means the request did not create or advance a payment/withdrawal, so retrying with the same
Idempotency-Keyis safe.n/amarks idempotency-mechanism errors themselves.
Error envelope
{ "success": false, "error": { "code": "PAYMENT_POLICY_VIOLATION", "message": "Daily limit exceeded", "details": {} }, "request_id": "req_123", "timestamp": "2026-06-01T10:00:00Z" }Authentication & access
| Code | HTTP | Meaning | Recovery hint | Idempotency-safe? |
|---|---|---|---|---|
AUTH_INVALID_API_KEY | 401 | API key missing or invalid | Check x-velarum-api-key; rotate if revoked | yes |
AUTH_EXPIRED_TOKEN | 401 | Bearer / agent token expired | Re-authenticate for a fresh token | yes |
AUTH_FORBIDDEN | 403 | Authenticated but not permitted | Check the principal role / scope | yes |
RBAC_ROLE_MUTEX_VIOLATION | 409 | TreasuryAdmin + SecurityAdmin on one user | Split the two duties across members | yes |
AUTHORIZATION_NOT_ACTIVE | 403 | Authorization grant not active | Activate or recreate the grant | yes |
AUTHORIZATION_REVOKED | 403 | Authorization grant revoked | Create a new authorization | yes |
AUTHORIZATION_EXPIRED | 403 | Authorization grant expired | Renew or recreate the grant | yes |
Agent payments
| Code | HTTP | Meaning | Recovery hint | Idempotency-safe? |
|---|---|---|---|---|
PAYMENT_POLICY_VIOLATION | 400 | Intent breaks a policy rule | Adjust the intent or the policy | yes (no state) |
PAYMENT_INSUFFICIENT_FUNDS | 422 | On-chain balance too low | Fund the wallet and retry | yes |
PAYMENT_SLIPPAGE_EXCEEDED | 400 | Quote moved past max_slippage | Re-quote and retry | yes |
PAYMENT_ROUTE_UNAVAILABLE | 502 | No viable chain route / chain error | Retry later or pick another chain | yes |
PAYMENT_IDEMPOTENCY_CONFLICT | 409 | Same idempotency key, different body | Reuse original key or a new one | n/a |
PAYMENT_ABANDON_NOT_ALLOWED | 409 | Abandon attempted past intent_created | Use wallet replace-by-fee instead | yes |
Automation (HC-NC-5)
| Code | HTTP | Meaning | Recovery hint | Idempotency-safe? |
|---|---|---|---|---|
HC_NC_5_HITL_REQUIRED | 403 | Agent intent exceeded a threshold | Confirm in client; resubmit as human | yes (no state) |
AUTOMATION_CONSENT_MISSING | 403 | Missing / invalid / expired consent | Re-authorize the agent before retry | yes |
AUTOMATION_POLICY_THRESHOLD_INVALID | 422 | A policy threshold missing / invalid | Fill all four thresholds | yes |
IDEMPOTENCY_KEY_MISMATCH | 400 | Header & body idempotency_key differ | Make them byte-equal | n/a |
ABANDON_RECEIPT_INVALID | 400 | Abandon receipt failed validation | Re-sign with the required payload | yes |
BROADCAST_HINT_REJECTED | 409 | tx_hash not found / not yours | Verify the tx and resend the hint | yes |
Policies & resources
| Code | HTTP | Meaning | Recovery hint | Idempotency-safe? |
|---|---|---|---|---|
POLICY_NOT_FOUND | 404 | Policy id not found | Check the id | yes |
POLICY_NOT_ALLOWED | 403 | Caller may not use this policy | Check ownership / role | yes |
POLICY_INVALID_RULE | 422 | Policy rule invalid | Fix the rule values | yes |
AGENT_NOT_FOUND | 404 | Agent id not found | Check the id | yes |
PROJECT_NOT_FOUND | 404 | Project id not found | Check the id | yes |
Subjects
| Code | HTTP | Meaning | Recovery hint | Idempotency-safe? |
|---|---|---|---|---|
SUBJECT_NOT_ACTIVE | 409 | Subject is not in active state | Verify / activate the subject first | yes |
Notifications
| Code | HTTP | Meaning | Recovery hint | Idempotency-safe? |
|---|---|---|---|---|
NOTIFICATION_PREFERENCE_LOCKED | 422 | Tried to disable a safety-critical email | Cannot disable (HC-NC-5) | yes |
NOTIFICATION_SUPPRESSED | 409 | Recipient suppressed (bounce/complaint) | Use a different verified address | yes |
NOTIFICATION_NOT_FOUND | 404 | Notification not visible / found | Check id / recipient | yes |
Platform & webhooks
| Code | HTTP | Meaning | Recovery hint | Idempotency-safe? |
|---|---|---|---|---|
VALIDATION_ERROR | 400 | Request failed schema validation | Fix the offending field | yes |
RATE_LIMITED | 429 | Too many requests | Back off and retry | yes |
KYB_PROVIDER_ERROR | 502 | Third-party KYB provider error | Retry later | yes |
AUDIT_EXPORT_FAILED | 500 | Export job failed | Retry the export | yes |
WEBHOOK_SIGNATURE_INVALID | 401 | Inbound webhook signature failed | Check signing secret / payload | yes |
WEBHOOK_DELIVERY_FAILED | 500 | Outbound delivery failed (will retry) | None — worker retries w/ backoff | n/a |
SERVER_INTERNAL_ERROR | 500 | Unexpected server error | Retry; contact support with request_id | yes |
Sovereign withdrawals
| Code | HTTP | Meaning | Recovery hint | Idempotency-safe? |
|---|---|---|---|---|
WITHDRAWAL_REQUEST_NOT_FOUND | 404 | Withdrawal id not found | Check the id | yes |
WITHDRAWAL_REQUEST_INVALID_STATE_TRANSITION | 409 | Action illegal in current state | Re-read state; act from a legal state | yes |
WITHDRAWAL_REQUEST_PASSKEY_REQUIRED | 401 | WebAuthn / Passkey assertion required | Provide a Passkey assertion | yes |
WITHDRAWAL_REQUEST_PASSKEY_ASSERTION_INVALID | 401 | Passkey assertion invalid | Re-assert with a valid Passkey | yes |
WITHDRAWAL_REQUEST_PASSKEY_REPLAY_DETECTED | 409 | Passkey assertion replayed | Generate a fresh assertion | yes |
WITHDRAWAL_REQUEST_SAME_APPROVER_FORBIDDEN | 403 | Initiator == approver (4-eyes) | Use a different SecurityAdmin | yes |
WITHDRAWAL_REQUEST_DESTINATION_NOT_ACTIVE | 409 | Destination not active on allowlist | Activate the allowlist entry first | yes |
WITHDRAWAL_REQUEST_DESTINATION_REVOKED | 409 | Destination allowlist entry revoked | Re-add the destination | yes |
WITHDRAWAL_REQUEST_INSUFFICIENT_BALANCE | 422 | Source balance too low | Fund the source wallet | yes |
SOVEREIGN_ADDRESS_NOT_FOUND | 404 | Allowlist address not found | Check the id | yes |
SOVEREIGN_ADDRESS_INVALID_STATE_TRANSITION | 409 | Allowlist action illegal in state | Re-read state and retry | yes |
SOVEREIGN_ADDRESS_COOLDOWN_NOT_ELAPSED | 409 | 24h cooldown not elapsed | Wait for cooldown to end | yes |
SOVEREIGN_ADDRESS_SCREENING_FAILED | 422 | Address screening hard-block | Choose a different destination | yes |
SOVEREIGN_ADDRESS_SAME_APPROVER_FORBIDDEN | 403 | Same approver on allowlist 4-eyes | Use a different approver | yes |
RBAC_DENIED_SOVEREIGN_WITHDRAW_INITIATE | 403 | Role may not initiate withdrawal | Use a TreasuryAdmin | yes |
RBAC_DENIED_SOVEREIGN_WITHDRAW_SECOND_APPROVE | 403 | Role may not second-approve | Use a SecurityAdmin | yes |
RBAC_DENIED_SOVEREIGN_ADDRESS_WHITELIST_ADD | 403 | Role may not add allowlist | Use a TreasuryAdmin | yes |
RBAC_DENIED_SOVEREIGN_ADDRESS_WHITELIST_REVOKE | 403 | Role may not revoke allowlist | Use an authorized role | yes |