statusCode, message, and requestId. Every error code documented
below also carries a machine-readable error.
| Field | Purpose |
|---|---|
statusCode | Mirrors the HTTP status. |
error | Stable, machine-readable code. Switch on this. Present on every documented error code (some framework-level 404s omit it). |
message | Human-readable explanation. A string for most errors; an array of path: reason strings for ValidationError. Don’t switch on this — wording may change. |
requestId | A UUID that correlates to our logs, also returned in the x-request-id response header. Include it in support requests. |
HTTP status mapping
| Status | When |
|---|---|
400 | Validation failed, business rule violated, or precondition not met. |
401 | Missing, malformed, expired, or revoked credential. |
403 | Authenticated, but the credential lacks the required scope or role. |
404 | Resource doesn’t exist or isn’t visible to your organization. |
409 | Conflict — most often IdempotencyKeyConflict or a race on a unique field. |
429 | Rate-limit exceeded. |
500 | Unexpected server error. Safe to retry with the same Idempotency-Key. |
503 | Platform maintenance or an upstream rail outage. Check status.caratuva.com. May be returned by the edge without the standard JSON envelope. |
Common error codes
The list below covers the codes you’re most likely to encounter while integrating.Auth
| Code | Status | Cause |
|---|---|---|
AuthenticationRequired | 401 | No credential presented. Send X-API-Key (or, for the dashboard, Authorization: Bearer). |
InvalidApiKeyFormat | 401 | Header isn’t pk_(test|live)_<id>.<secret>. |
InvalidApiKey | 401 | Key is unknown, revoked, or doesn’t match the stored hash. |
JwtExpired | 401 | Bearer JWT past its exp. Re-authenticate via the dashboard. |
InvalidJwt | 401 | Bearer JWT malformed, bad signature, or missing claims. |
InsufficientScope | 403 | API key lacks the scope required for this endpoint. |
Validation
| Code | Status | Cause |
|---|---|---|
ValidationError | 400 | Request body failed schema validation. message is an array of path: reason strings. |
IdempotencyKeyConflict | 409 | The Idempotency-Key was already used for a different resource. Use a fresh key. |
Lifecycle
| Code | Status | Cause |
|---|---|---|
KybNotApproved | 400 | Your organization hasn’t cleared KYB. Live operations are gated; test mode still works. |
ProductionAccessNotApproved | 400 | Live mode isn’t enabled yet. Submit a Production Access Request and wait for Caratuva approval. |
AmountBelowMinimum | 400 | The USD amount is below the US$10.00 bank-transfer funding minimum, so the buyer couldn’t pay it. Increase the amount. |
PixPayoutKeyMissing | 400 | No PIX payout key registered. Configure payouts in the dashboard first. |
InvalidInvoiceState | 400 | Tried to edit or reassign an invoice past its editable state (draft / awaiting_approval). |
InvalidTransition | 400 | Illegal state transition — e.g. cancelling an invoice or payment intent that’s already past the cancellable point. |
ValidationError, not a dedicated code.
Re-POSTing the same externalId returns the existing intent rather than an error (see
Payment intents).
Rate limiting
| Code | Status | Cause |
|---|---|---|
RateLimitExceeded | 429 | You exceeded the per-API-key limit. The JSON body includes retryAfter (seconds) — wait that long, then retry. |
Server
| Code | Status | Cause |
|---|---|---|
InternalServerError | 500 | Unexpected server-side failure. Safe to retry with the same idempotency key. |
Retry guidance
| Status | Retry? | How |
|---|---|---|
| 4xx (except 429) | No | The request will fail the same way again. Fix the input. |
| 429 | Yes | Wait retryAfter seconds (from the response body), then retry. Don’t hammer. |
| 500, 502, 503, 504 | Yes | With exponential backoff, reusing the same Idempotency-Key so a retry can’t create a duplicate resource. |
| Network error / timeout | Yes | Same as 5xx. The original may or may not have committed; reusing the idempotency key keeps it safe. |
What to log
When an API call fails, log:requestId— lets us find your exact request in our logs (also on thex-request-idresponse header).error— the stable machine code.- The endpoint and the request body with secrets redacted (never log the API key secret half or
Idempotency-Keyheaders if they encode user data).
requestId and the error code. With those two we can usually answer in minutes.