{
"error": {
"code": "QUOTE_NOT_FOUND",
"message": "Quote not found or expired"
}
}
details field is only present when there is extra structured context. For Zod validation failures (422), issues are in details.errors (path + message per field). Domain-specific data (for example needsSignUp) also lives under details.
Quote Errors
| Code | HTTP Status | Description | Resolution |
|---|---|---|---|
QUOTE_NOT_FOUND | 404 | Quote not found or expired | Request a new quote — quotes are valid for 5 minutes |
QUOTE_EXPIRED | 400 | Quote has expired | Request a new quote using the same parameters |
QUOTE_GENERATION_FAILED | 400 | Could not generate a quote for the specified parameters | Verify token addresses, chain names, and amount format |
QUOTE_VALIDATION_ERROR | 400 | Quote validation failed | Check that quoteId and rawQuote match the original quote response |
Swap Errors
| Code | HTTP Status | Description | Resolution |
|---|---|---|---|
NO_ROUTE_FOUND | 400 | No swap route available between the specified chains or tokens | Try a different token pair or check supported networks |
INVALID_PREFERRED_PROVIDER | 400 | Unknown preferredProvider name on GET /v2/swap/quote | Use a registered provider id (relay, mayan, lifi, cctp, 1inch, etc.) |
PREFERRED_PROVIDER_NOT_ELIGIBLE | 400 | preferredProvider does not support this chain/token route | Omit the parameter or pick a provider eligible for the route |
PREFERRED_PROVIDER_QUOTE_UNAVAILABLE | 400 | Eligible provider did not return a quote in time | Retry or omit preferredProvider to use the best available quote |
PROVIDER_NOT_FOUND | 404 | Swap provider not found for the requested route | Use a supported chain and token combination |
BYTECODE_GENERATION_FAILED | 500 | Failed to generate transaction bytecode | Retry the request — if the issue persists, contact support |
SWAP_EXECUTION_FAILED | 500 | Failed to execute the swap transaction | Verify wallet balance, allowance, and gas fees |
Validation Errors
| Code | HTTP Status | Description | Resolution |
|---|---|---|---|
INVALID_AMOUNT_PARAMS | 400 | Cannot specify both amountIn and amountOut simultaneously | Use only one of amountIn or amountOut per request |
MISSING_AMOUNT_PARAMS | 400 | Either amountIn or amountOut is required | Include at least one amount parameter in the request |
INVALID_SLIPPAGE | 400 | slippage must be between 0.0001 and 0.5 as a fraction of 1 | Use a value like 0.01 for 1% slippage |
AMOUNT_IN_TOO_LOW_OFFRAMP | 400 | Off-ramp amountIn must be greater than 1 USDC | Increase the input amount |
AMOUNT_IN_TOO_HIGH_OFFRAMP | 400 | Off-ramp amountIn must be less than 5k USDC | Reduce the input amount or contact support for higher limits |
AMOUNT_OUT_TOO_LOW_OFFRAMP | 400 | Off-ramp amountOut is below the route minimum (0.5 BRL on Pix BRLA/BRS, 5 BRLA on USDC Pix) | Increase the output amount |
AMOUNT_OUT_TOO_HIGH_OFFRAMP | 400 | Off-ramp amountOut must be less than 26k BRLA | Reduce the output amount or contact support for higher limits |
AMOUNT_IN_TOO_LOW_ONRAMP | 400 | On-ramp amountIn is below the route minimum (0.5 BRL on Pix BRLA/BRS, 1 BRLA on USDC Pix) | Increase the input amount |
AMOUNT_IN_TOO_HIGH_ONRAMP | 400 | On-ramp amountIn must be less than 75k BRLA | Reduce the input amount or contact support for higher limits |
AMOUNT_OUT_TOO_LOW_ONRAMP | 400 | On-ramp amountOut must be greater than 1 USDC | Increase the output amount |
AMOUNT_OUT_TOO_HIGH_ONRAMP | 400 | On-ramp amountOut must be less than 15k USDC | Reduce the output amount or contact support for higher limits |
Bridge Errors
| Code | HTTP Status | Description | Resolution |
|---|---|---|---|
TRANSFER_VALIDATION_FAILED | 400 | Token transfer validation failed | Verify the token address, chain, and transfer amount |
INSUFFICIENT_AMOUNT_FOR_REFUND | 400 | Transferred amount is insufficient to cover the refund fee | Increase the transfer amount to cover bridge fees |
DEPOSIT_NOT_FOUND | 404 | Bitcoin deposit not found | Wait for on-chain confirmation or check the deposit address |
KYC Evidence Errors
Returned byPOST /v1/kyc/sessions/{kycUserId}/submit before anything reaches the ramp provider. See External Evidence KYC for the flow and for the provider’s own rejection reasons, which are separate and arrive on /kyc/status.
| Code | HTTP Status | Description | Resolution |
|---|---|---|---|
INVALID_EVIDENCE_IMAGE | 422 | An image is unusable — not valid base64, or over the 8 MB limit | Re-encode or recompress the image below 8 MB |
UNSUPPORTED_EVIDENCE_IMAGE_FORMAT | 422 | The image bytes are neither JPEG nor PNG | Convert to JPEG or PNG — the format is read from the bytes, not from mimeType |
EVIDENCE_URL_NOT_ALLOWED | 422 | The image URL is not HTTPS, its host is not allowlisted, or it resolves to a private address | Use an HTTPS URL on a host Pods has allowlisted for your account |
EVIDENCE_URL_EXPIRED | 422 | The pre-signed signature had already expired when the request arrived | Re-sign the URL and submit again — size X-Amz-Expires to outlive the call |
EVIDENCE_URL_FORBIDDEN | 422 | The storage provider refused the request (403) | Check the signature, the bucket policy, and that the credential that signed it is still valid |
EVIDENCE_URL_NOT_FOUND | 422 | The object does not exist (404) | Verify the bucket and key — a deleted or renamed object cannot be fetched |
EVIDENCE_URL_UNREACHABLE | 422 | The storage provider could not be reached | Retry — if it persists, check DNS and the host’s availability from the public internet |
EVIDENCE_URL_TIMEOUT | 422 | Fetching the images exceeded 8 seconds | Serve the objects from a faster region, or send the images as base64 instead |
DOCUMENT_BACK_REQUIRED | 422 | RG and CNH submissions need a back image | Include documents.back |
DOCUMENT_BACK_NOT_ALLOWED | 422 | A PASSPORT is single sided | Omit documents.back |
INVALID_BIRTH_DATE | 422 | The extracted birth date could not be parsed | Send extracted.birthDate as YYYY-MM-DD |
LIVENESS_BELOW_THRESHOLD | 422 | The attested liveness confidence is below the minimum configured for your account | Re-run the liveness check — no upload happened, so nothing needs cleaning up |
IDENTITY_CPF_MISMATCH | 409 | The CPF read from the document is not the CPF the session was created with | Terminal for this session — one person under two records is almost always a capture mistake |
UNDER_18 | 409 | The applicant is a minor | Terminal — the ramp provider does not onboard minors |
General Errors
| Code | HTTP Status | Description | Resolution |
|---|---|---|---|
INTERNAL_SERVER_ERROR | 500 | An unexpected error occurred | Retry the request — if the issue persists, contact support |
SYMBIOSIS_API_ERROR | 502 | Error communicating with the Symbiosis bridge API | Retry after a short delay — this is usually transient |
Authentication Errors
| Code | HTTP Status | Description | Resolution |
|---|---|---|---|
AUTHENTICATION_REQUIRED | 401 | No credentials provided, or API key used on a route that requires a Bearer token with a user role | Use x-api-key for API routes, or Authorization: Bearer <token> for customer dashboard routes |
INVALID_API_KEY | 401 | API key is missing or not recognized | Verify your API key at pods.finance |
INVALID_AUTH_TOKEN | 401 | Bearer token is invalid or expired | Refresh your Supabase or Magic session token |
VALIDATION_ERROR | 422 | Request validation failed (e.g. malformed Authorization header on GET /customers/me) | Send Authorization: Bearer <token> in the correct format |
| — | 401 | No API key provided | Include x-api-key header in your request |
| — | 429 | Rate limit exceeded | Wait for the retry window — see retryAfter in the response body |
Transaction Errors
| Code | HTTP Status | Description | Resolution |
|---|---|---|---|
TX_NOT_FOUND | 404 | Transaction hash not found on the specified chain | Verify the hash is correct, mined, and on the expected chain |
TX_NOT_MINED | 422 | Transaction exists but is not yet mined | Wait for confirmation and retry |
TX_REVERTED | 422 | Transaction was mined but reverted on-chain | Inspect the transaction on a block explorer |
Rate Limit Response
When you hit a rate limit, the body matches the same envelope, for example:{
"error": {
"code": "RATE_LIMITED",
"message": "Too many requests"
}
}
Retry-After response header (seconds). Prefer that header when present. See Authentication for rate limit details.