Errors and retries
Versioned error bodies have this shape:
{
"apiVersion": "1",
"error": "external_prepare_failed",
"code": "intent_session_expired",
"message": "Safe human-readable text",
"path": "optional.field.path"
}error is the stable failure family. code is the stable detail where one is
defined; clients must tolerate new detail codes. Several authentication and
transport failures return only apiVersion and error, so treat code,
message and path as optional. message, when present, is safe to render;
do not parse it.
Retry rules
| Condition | Required behavior |
|---|---|
| Timeout or unexpected 5xx on a mutating endpoint | Retry the identical bytes with the same idempotency key |
429 external_rate_limited | Honor the RateLimit-* headers and retry later |
| Expired quote or non-executable committed plan | Create a new quote with a new idempotency key |
| User rejection in the wallet | Stop; do not retry silently |
| New or additive execution evidence | Send the new body with a new idempotency key |
| Same evidence is being retried | Reuse the original body and idempotency key |
Never reuse an idempotency key for a different body or resource. Treat an
unknown error or code as non-success and preserve it for diagnostics.
Authentication and transport
| HTTP | error | Action |
|---|---|---|
| 400 | external_idempotency_key_required | Supply a valid key on the mutating request |
| 401 | external_auth_headers_required | Fix missing partner authentication headers |
| 401 | external_auth_timestamp_invalid | Send a decimal Unix timestamp in milliseconds |
| 401 | external_auth_timestamp_expired | Correct clock skew and sign a fresh request |
| 401 | external_auth_signature_invalid | Verify canonical bytes, secret and protected headers |
| 401 | external_auth_version_mismatch | Use the authentication version configured for the partner |
| 401 | external_auth_nonce_invalid / external_auth_request_invalid | Rebuild the canonical v2 request correctly |
| 403 | external_partner_not_allowed | Contact Sweep; the partner id is unknown or disabled |
| 409 | external_auth_nonce_conflict | Use a new nonce for the new canonical request |
| 429 | external_rate_limited | Back off according to rate-limit headers |
| 503 | external_auth_replay_unavailable | Retry later; replay protection failed closed |
Unexpected endpoint failures use external_quote_failed,
external_prepare_failed, external_submit_failed or
external_status_failed. Retry an identical mutating request with the same
idempotency key.
Quote
Request validation returns 400 invalid_intent_request. Common codes:
invalid_sources, invalid_source, duplicate_source, invalid_chain_id,
invalid_address, invalid_wallet_address, invalid_recipient_address,
invalid_source_amount, invalid_decimals, invalid_usd_value,
invalid_target, invalid_allowed_provider, invalid_callback_url,
invalid_slippage_bps, invalid_allow_partial, invalid_max_wait_ms,
invalid_idempotency_key.
Invalid allocation returns 400 invalid_intent_allocation with no_targets or
no_sources.
Route failures are not HTTP errors. A quote may return HTTP 200 with
failedSources[].reasonCode equal to no_allowed_provider,
provider_unavailable, route_unavailable, same_chain_unsupported,
provider_timeout or app_fee_exceeds_provider_cap. This set may grow; the
quote’s quoteStatus and coverageMode remain authoritative.
Prepare
| HTTP | code under external_prepare_failed | Action |
|---|---|---|
| 400 | callback_url_not_allowed | Use the exact callback URL configured for the partner |
| 404 | intent_session_not_found | Check partner/session identity; otherwise start a new quote |
| 409 | intent_session_expired | Start a new quote |
| 409 | intent_session_not_preparable | Do not prepare a non-ready quote |
| 409 | idempotency_key_conflict | Do not rebind a prepare key to another session |
| 409 | quote_not_executable | Start a new quote |
| 409 | prepared_payload_mismatch | Start a new quote; the executable plan did not match the commitment |
| 502 | allowance_unavailable | Retry the identical request; re-quote if the quote expires |
Submitted evidence
| HTTP | code under external_submit_failed | Action |
|---|---|---|
| 400 | invalid_submission | Fix the evidence shape, bounds or hash format |
| 400 | invalid_wallet_authorization | Re-prepare if needed and collect a valid signature from the executing wallet |
| 400 | contract_wallet_unsupported | Use an EOA/EIP-7702 wallet; ERC-1271 is outside v1 |
| 404 | execution_attempt_not_found | Check partner/attempt identity |
| 409 | execution_attempt_expired | Stop reporting; the evidence deadline passed without accepted evidence |
| 409 | submit_in_progress | Retry the identical request with the same key |
| 409 | idempotency_key_conflict | Do not reuse a key across attempts |
| 409 | source_tx_hash_conflict | Stop and reconcile ownership of the transaction evidence |
| 409 | bundle_id_conflict | Stop and reconcile the wallet bundle for that chain |
| 500 | attempt_snapshot_invalid | Preserve evidence and escalate to Sweep |
Status
404 external_status_failed with execution_attempt_not_found when the
attempt does not exist for the partner.