HTTP status map
Every error uses the envelope{"error": {"code", "message", "request_id"}} — see Errors for the full code list.
Idempotency keys: retry without double-paying
Every POST accepts anIdempotency-Key header. If a request times out and you retry with the same key, SohoPay returns the original result instead of creating a second order or payment. Derive the key from your own stable identifier — never generate a random one per attempt:
Exponential backoff with jitter
Retry429 and 500 responses with exponential backoff plus jitter, so a fleet of agents doesn’t retry in lockstep. Always honor Retry-After when present:
The three errors that need a playbook
INSUFFICIENT_CREDIT (402)
The payment plus the 5% fee doesn’t fit in the agent’s available credit or daily limit — or, at agent creation, your vault can’t back the requested limit. Recovery: raise the agent’scredit_limit/daily_limit, deposit more collateral (Vault & Funding), or unwind outstanding balances on other agents to free capacity. Retrying without changing anything will fail identically — treat it as an alert, not a transient.
RATE_LIMITED (429)
You exceeded per-agent rate limits. The response carriesRetry-After plus X-RateLimit-Limit and X-RateLimit-Remaining headers — honor Retry-After exactly; retrying sooner extends the penalty. If you hit this in normal operation, smooth your submission rate or request higher limits — see Rate Limits.
AML_DECLINED (402)
Didit wallet screening declined the transaction. Do not retry — the decline is deterministic and repeated attempts look like structuring. The agent may also enter review (agent.aml_review webhook). Escalate to a human, and see AML Screening for the review process.
Circuit breakers
Retries handle single failures; circuit breakers handle sustained ones. If N consecutive payment submissions fail with500 (for example, the Policy Service is down and the system has failed closed), open the circuit: stop submitting, queue work locally, and probe with a single request every 30–60s until one succeeds. This keeps your agents from hammering a degraded API and gives you a clean metric (“circuit open”) to alert on instead of a wall of error logs.
Log what support needs
Every error envelope includes arequest_id (req_...), and every settled payment includes a settlement_tx hash. Log both, structured, on every API interaction. When you contact support, a request_id turns “payments are failing” into a traceable incident; a settlement_tx proves what did or didn’t land on-chain.
Next steps
Testing
Trigger these exact errors in sandbox before production does it for you.
API Errors
The complete error-code reference.
Troubleshooting
Symptom-first debugging for common integration issues.

