Agents run unattended, so your integration’s error handling is your operations team at 3 a.m. This page gives you the status map, safe-retry patterns with code, and specific recovery playbooks for the errors you’ll actually hit in production.

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 an Idempotency-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:
One order should map to one idempotency key for its payment. pay-{order_id} is a good default — it makes double-payment structurally impossible.

Exponential backoff with jitter

Retry 429 and 500 responses with exponential backoff plus jitter, so a fleet of agents doesn’t retry in lockstep. Always honor Retry-After when present:
Orders expire after 10 minutes. Cap total retry time well under the TTL, and on ORDER_EXPIRED create a new order (with a new idempotency key) instead of retrying the old payment.

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’s credit_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 carries Retry-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 with 500 (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 a request_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.