Error Handling
All CoverPay APIs return consistent error responses. This guide covers error codes, HTTP status codes, rate limits, and best practices for handling failures.
Error Response Format
Every error response includes an error code and a human-readable message.
JSON
{
"error": "RATE_LIMITED",
"message": "Rate limit exceeded. Retry after 60 seconds.",
"retryAfter": 60,
"requestId": "req_abc123def456"
}Error Codes
| Code | HTTP | Description | How to Handle |
|---|---|---|---|
INVALID_API_KEY | 401 | API key is missing, malformed, or revoked | Verify your API key in the Dashboard. Ensure the Authorization header format is correct. |
RATE_LIMITED | 429 | Too many requests in the current window | Implement exponential backoff. Check the retryAfter field for the wait time. |
AMOUNT_TOO_LOW | 400 | Amount is below the minimum for all providers | Check provider minimums in the Providers table. CoverPay min is $10. |
AMOUNT_TOO_HIGH | 400 | Amount exceeds the maximum for all providers | Check provider maximums. Affirm supports up to $17,500. |
NOT_ELIGIBLE | 403 | User failed one or more eligibility checks | Inspect the failureReasons array. Show the user an appropriate message. |
TERMS_NOT_ACCEPTED | 403 | User has not accepted the required legal terms | Present the terms acceptance UI or call the accept-terms endpoint. |
PROVIDER_UNAVAILABLE | 503 | The selected provider is temporarily unavailable | The smart router auto-fallbacks to other providers. Only returned if ALL providers are down. |
SESSION_EXPIRED | 410 | The checkout session has expired (15 min TTL) | Create a new checkout session. |
CHECKOUT_CANCELLED | 200 | User voluntarily cancelled the checkout | Show the cart again or offer to retry. This is not an error — it's a user action. |
INVALID_WEBHOOK_URL | 400 | Webhook URL is invalid, not HTTPS, or unreachable | Ensure the URL is a valid HTTPS endpoint that responds to POST requests. |
SIGNATURE_MISMATCH | 401 | Webhook signature verification failed | Check that you're using the correct signing secret from the Dashboard. |
INVALID_REQUEST | 400 | Request body is malformed or missing required fields | Check the request body against the API documentation. |
Rate Limits
Rate limits are enforced per API key. When exceeded, you'll receive a 429 response with a retryAfter value in seconds.
| Tier | Requests / min | Daily Volume |
|---|---|---|
| Starter | 60 | $100K |
| Growth | 300 | $500K |
| Scale | 1,000 | $2M |
| Enterprise | Custom | Unlimited |
Best Practices
Always check the error code, not the HTTP status
Multiple error codes can share the same HTTP status (e.g., 400). The error code provides the specific failure reason.
Implement exponential backoff for retries
When you receive a 429 or 503, wait before retrying. Start at 1 second and double each attempt, up to 60 seconds.
Log the requestId
Every response includes a requestId. Include it when contacting support for faster debugging.
Handle CHECKOUT_CANCELLED gracefully
Users cancelling is normal. Don't show an error — offer to retry or show the cart.
Show user-friendly messages for eligibility failures
Map each failure code to a message the user can understand and act on.