ContoError
SDK failures use the exportedContoError class. It exposes only stable customer-facing metadata:
fieldErrors identifies recognized request fields with locally generated guidance. The pay() helper preserves allowlisted customer-facing denial reasons. The SDK does not forward arbitrary server details, workflow instructions, or provider diagnostics.
Error Codes
Authentication Errors
Payment Errors
A repeated
execute call after completion can return 400 INVALID_STATUS; a concurrent execution
can return 409 ALREADY_EXECUTED. Both require reading the original request, not sending again.
Do not rely on a single HTTP status to identify an earlier successful execution.
Validation Errors
System Errors
For the full state transition and recovery flow, see Track and recover a payment.
Handling Errors
Basic Error Handling
Handling Specific Error Codes
Decision And Error Boundaries
Policy denials frompayments.request() are normal decision responses with status: "DENIED".
Transport, authentication, validation, and execution failures throw ContoError. Use separate
request and execute calls when your application needs to handle those outcomes independently.
The pay() method throws on denial. For more control, use separate request/execute:
Handling Rate Limits
The SDK handles retryable rate limits before throwing (see Retry Strategy). If the request is still rate limited,ContoError.retryAfter may provide a server-supplied delay in
seconds. Otherwise, back off on your own schedule.
If you need an additional application-level retry after the SDK has exhausted its own, wrap the call and back off on your own schedule:
Handling Timeouts
For long-running requests, handle timeouts:Retry Strategy
Built-in Automatic Retry
The SDK automatically retries transient failures only when repeating the request cannot create an additional side effect. Built-in behavior:- Retries read-only requests up to 3 times on network failures,
429, and5xx - Retries payment authorization requests with the same stable
idempotencyKey - Treats x402 and MPP pre-authorization as retryable, non-mutating policy checks
- Respects
Retry-Afterheaders from the server - Exponential backoff: 1s → 2s → 4s (capped at 10s)
- Never automatically retries payment execution, protocol record calls, or
ContoAdminmutations - Does not retry client errors (
4xxexcept retryable429responses) or auth failures
request and execute
methods over the pay convenience method so the application retains the requestId.
Custom Retry for Application Logic
For application-level retry logic (e.g., re-requesting after a denial), use a custom wrapper:Logging Errors
Best Practices
Always Catch Errors
Always Catch Errors
Never let payment errors crash your application:
Check Specific Error Codes
Check Specific Error Codes
Don’t just catch generic errors:
Don't Retry Payment Execution
Don't Retry Payment Execution
Be careful with retries on payment execution:
Log Safe Error Fields
Log Safe Error Fields
Log the stable fields needed to investigate a failed request. Do not log request bodies,
credentials, arbitrary response objects, or payment context:
Next Steps
Examples
See complete integration examples
API Reference
View the REST API (Swagger UI)