Skip to main content

Handling Errors

Every error response uses the same envelope:

{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Amount must be greater than zero",
"details": {
"amount": "must be a positive integer"
}
}
}

details is optional and, when present, is usually a map of field name to what's wrong with it.

Common codes

CodeTypical statusMeaning
BAD_REQUEST400The request was malformed
VALIDATION_ERROR400A field failed validation — check details
UNAUTHORIZED401Missing or invalid token
FORBIDDEN403Valid token, but it lacks the required scope, or a business/verification gate wasn't met
NOT_FOUND404The resource doesn't exist, or doesn't belong to your application
CONFLICT409e.g. a payment intent that's already in a terminal state
IDEMPOTENT_REQUEST_IN_FLIGHT409See Idempotent Requests
INTERNAL_SERVER_ERROR500Something went wrong on our end — safe to retry

This list isn't exhaustive — treat error.code as a machine-readable hint for common cases, and always fall back to the HTTP status code and error.message for anything not listed here.

One important exception

GET /oauth/authorize and POST /oauth/authorize/decision are browser-facing, not API calls your integration makes directly. Their errors are either an HTML page (if something's wrong before a redirect URI can be trusted, like an unknown client) or a redirect back to your redirect_uri with RFC 6749-style error and error_description query parameters — not this JSON envelope.