Reference · 149 codes
Errors
Every failed request answers with the same body. Switch on code; the message is for people and can change.
Error body
{
"code": "idempotency_conflict",
"message": "This Idempotency-Key was already used for a different request.",
"request_id": "0192f1e0-4c2a-7f8e-9a1b-3c4d5e6f7a8b",
"retryable": false
}| Field | Meaning |
|---|---|
| code | A stable, machine-readable string. New codes can appear in any 1.x version, so always keep a default branch. |
| message | A sentence safe to show to a person. Do not parse it. |
| request_id | The same value as the X-Request-ID response header. Quote it when you contact support. |
| retryable | True when the same request may succeed later without a change. The SDKs retry these for you. |
Handling errors
- Branch on
code, then onretryablefor the codes you do not know. - Retry a
retryableerror with the sameIdempotency-Key, after theRetry-Afterdelay when there is one, with exponential backoff and a limit on attempts. - Never retry a non-retryable error unchanged. Fix the request or tell the person.
- Log
request_idwith every failure.
curl
# No amount and no price: 400 amount_required.
curl -sS -i "$RAVELO_API/v1/payment-intents" \
-H "Authorization: Bearer $RAVELO_TEST_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{ "order_ref": "order-1", "asset_id": "usdt-tron" }'TypeScript
import { Ravelo, RaveloError } from "@ravelo/sdk";
const ravelo = new Ravelo({ apiKey: process.env.RAVELO_TEST_KEY!, baseUrl: process.env.RAVELO_API! });
try {
await ravelo.paymentIntents.create({ order_ref: "order-1", asset_id: "usdt-tron" }); // neither amount nor price
} catch (err) {
if (!(err instanceof RaveloError)) throw err;
switch (err.code) {
case "amount_required":
console.log("send amount or price");
break;
case "address_pool_empty":
case "operation_paused":
console.log("try again shortly"); // both are retryable; err.retryable says so
break;
default:
// The API may add codes without a new version. Log the request id: support can find the call with it.
console.error(err.status, err.code, err.message, err.requestId);
}
}Python
import os
from ravelo import ErrorCode, Ravelo, RaveloError
ravelo = Ravelo(os.environ["RAVELO_TEST_KEY"], os.environ["RAVELO_API"])
try:
ravelo.payment_intents.create(order_ref="order-1", asset_id="usdt-tron") # neither amount nor price
except RaveloError as err:
if err.code == ErrorCode.AMOUNT_REQUIRED:
print("send amount or price")
elif err.retryable:
print("try again shortly")
else:
# The API may add codes without a new version. Log the request id: support can find the call with it.
print(err.status, err.code, err.message, err.request_id)HTTP statuses
| Status | Meaning |
|---|---|
| 400 | The request is malformed or a field is invalid. Fix the request; repeating it unchanged fails again. |
| 401 | No valid API key. Check the Authorization header and that the key is not revoked or expired. |
| 403 | The key is valid but not allowed: a missing scope (insufficient_scope), a live key on a test-only call, or a frozen account. |
| 404 | No such resource in this account. Test and live objects are separate accounts. |
| 409 | The request conflicts with the current state, or an Idempotency-Key was reused with a different body. |
| 422 | The request is well formed but a business rule refused it: below the minimum, over a limit, an address still cooling off. |
| 423 | Money out is paused for a while after a security change on the account. |
| 429 | Rate limit reached. Wait Retry-After seconds. |
| 5xx | Something failed on our side or a dependency is unavailable. Retry with the same Idempotency-Key. |
All codes
This table is generated from the API's error catalogue when the site is built. Codes used only by the staff console are not listed.
149 of 149 codes
| Code | HTTP | Retryable | Meaning |
|---|---|---|---|
| above_ceiling | 422 | no | A fee above its operation's hard ceiling is blocked. |
| account_changed | 409 | no | The session now works in a different account than the client believes; reload and retry. |
| account_inactive | 403 | no | The account is frozen, suspended or closed, so the action is refused. |
| address_cooling_off | 422 | no | A saved address cannot receive payouts until its 24-hour cooling-off ends. |
| address_exists | 409 | no | The address is already in the address book. |
| address_not_found | 422 | no | The address is not in this account's address book. |
| address_pool_empty | 503 | yes | No deposit address is free right now; retry shortly. |
| already_fulfilled | 409 | no | The payment is already fulfilled. |
| already_handled | 409 | no | The payout approval was already approved or rejected. |
| already_invited | 409 | no | This address already has a pending invitation to the account; resend it from the team page. |
| already_member | 409 | no | This address already belongs to an active member of the account. |
| amount_and_price | 400 | no | Both amount and price were given; send one. |
| amount_required | 400 | no | Neither amount nor price was given. |
| approval_expired | 409 | no | The payout or refund waited too long for approval and was cancelled; its funds are back in the available balance. |
| approver_must_differ | 403 | no | A different team member must approve a payout or refund the caller prepared. |
| asset_id_required | 400 | no | asset_id is required. |
| below_minimum | 422 | no | The amount is below the minimum for this asset and operation. |
| body_too_large | 400 | no | The request body exceeds the size limit. |
| callback_invalid | 400 | no | The provider callback body could not be parsed. |
| ceremony_invalid | 400 | no | The passkey ceremony is invalid or expired; start again. |
| 409 | no | Conversion is not available right now; nothing was quoted or converted. | |
| country_already_set | 409 | no | PUT /v1/me/country only fills a missing country; one is already on record (declared at sign-up or confirmed by staff) and only staff correct it. |
| country_required | 403 | no | The merchant has not given a country yet, so payment intents and checkout sessions are refused until they do (PUT /v1/me/country, or staff confirm it during verification). Payouts, refunds and returns are not affected. Read GET /v1/capabilities, eligibility.country_required. |
| csrf_invalid | 403 | no | The CSRF token is missing or invalid. Session requests only; API keys are not affected. |
| deletion_owner_blocked | 409 | no | You are the only owner of an open account; hand ownership over or close the account before asking for deletion. |
| deletion_request_exists | 409 | no | A deletion request is already waiting for review. |
| deposits_disabled | 422 | no | Payments are disabled for this asset. |
| email_taken | 409 | no | Another user already signs in with this email. |
| email_unverified | 403 | no | The email address must be verified before signing in. |
| empty_patch | 400 | no | The update contained no fields to change. |
| endpoint_disabled | 409 | no | The webhook endpoint must be enabled first. |
| fee_exceeds_amount | 422 | no | The fee would exceed the amount; increase the amount. |
| forbidden | 403 | no | The caller's role does not allow this action. |
| idempotency_conflict | 409 | no | The Idempotency-Key was already used for a different request. |
| idempotency_key_required | 400 | no | POST requests require an Idempotency-Key header of 1-255 characters. |
| insufficient_available_balance | 422 | no | The available balance does not cover the amount plus fees. |
| insufficient_scope | 403 | no | The API key lacks the scope this endpoint needs. |
| integration_paused | 403 | no | Ravelo staff paused this API key, connected app or account integration. |
| intent_not_payable | 409 | no | The payment intent is not awaiting payment or has no active instructions. |
| internal_error | 500 | yes | An unexpected server error; retry with the same Idempotency-Key. |
| invalid_address | 422 | no | The address is not valid for the network. |
| invalid_amount | 400 | no | The amount is not a positive integer in base units. |
| invalid_asset | 400 | no | asset_id is missing or invalid. |
| invalid_country | 400 | no | country is missing, is not an ISO 3166-1 alpha-2 code, or subdivision is not an ISO 3166-2 code inside it. Sign-up requires a country. |
| invalid_credentials | 401 | no | The email, password or code is incorrect. |
| invalid_currency | 400 | no | The currency is not a supported ISO 4217 code. |
| invalid_cursor | 400 | no | The pagination cursor is not valid for this list or sort. |
| invalid_email | 400 | no | The email address is not valid. |
| invalid_event_type | 400 | no | The webhook event type is unknown. |
| invalid_expiry | 400 | no | The expiry is outside the allowed range. |
| invalid_from | 400 | no | from is not an RFC 3339 timestamp. |
| invalid_json | 400 | no | The request body is not valid JSON for this endpoint. |
| invalid_kind | 400 | no | The kind filter holds an unknown value. |
| invalid_label | 400 | no | The label must be 1-64 characters. |
| invalid_limit | 400 | no | limit is outside its allowed range. |
| invalid_locale | 400 | no | The locale is not a BCP-47 language tag. |
| invalid_max_amount | 400 | no | max_amount is not a non-negative integer in base units. |
| invalid_metadata | 400 | no | metadata must be a JSON object under 4 KB. |
| invalid_min_amount | 400 | no | min_amount is not a non-negative integer in base units. |
| invalid_mode | 400 | no | The key mode must be live or test. |
| invalid_month | 400 | no | The month must be YYYY-MM. |
| invalid_name | 400 | no | The name must be 1-64 characters. |
| invalid_offset | 400 | no | offset is not a whole number of zero or more. |
| invalid_operation | 400 | no | The operation is not one the endpoint accepts. |
| invalid_order | 400 | no | order must be asc or desc. |
| invalid_origin | 400 | no | The origin must be a normalized https origin, or http localhost in test mode, without a path, query or fragment. |
| invalid_overlap | 400 | no | overlap_seconds is outside 0 to 604800. |
| invalid_period | 400 | no | The period is malformed or too long. |
| invalid_price | 400 | no | price needs a currency and a positive amount_minor. |
| invalid_range | 400 | no | The range value is not one the endpoint accepts. |
| invalid_role | 400 | no | The role is not valid for this action. |
| invalid_schedule | 422 | no | The fee schedule is invalid. |
| invalid_scope | 400 | no | scopes must be a non-empty list of known scopes. |
| invalid_status | 400 | no | The status filter holds an unknown value. |
| invalid_text | 400 | no | A text field holds a control character such as NUL, or a formatting character an identifier does not accept. |
| invalid_time_zone | 400 | no | The time zone is not an IANA name. |
| invalid_to | 400 | no | to is not an RFC 3339 timestamp or date. |
| invalid_url | 400 | no | The URL must be a public https endpoint without credentials. |
| invalid_username | 400 | no | Usernames are 3-24 lowercase letters, digits or underscores. |
| invitation_wrong_user | 403 | no | The signed-in person is not the one the invitation was sent to; the message names the masked address. The link is not spent: sign in as the invited person. |
| key_inactive | 409 | no | The API key is revoked or expired. |
| last_owner | 409 | no | An account keeps at least one owner. |
| legal_version_stale | 409 | no | The legal text is no longer current; accept the current version. |
| login_exists | 409 | no | The invited address already has a login, so it cannot create one; sign in and accept the invitation. |
| lookalike_address | 422 | no | The address resembles a saved one but differs; check every character. |
| market_not_eligible | 403 | no | The merchant's registered market does not allow this activity: new payments are refused in a restricted market, while payouts, refunds and returns of the merchant's own funds go to staff review instead. Sign-up from a blocked market answers the same. Read GET /v1/capabilities for what the market allows. |
| method_not_allowed | 405 | no | The HTTP method is not allowed on this path. |
| mfa_required | 403 | no | A second factor is needed; set up MFA and confirm with a code. Sign-in also answers 401 when the code is missing. |
| network_mismatch | 422 | no | The address belongs to another network than the asset. |
| no_asset_price | 422 | no | The asset has no price to convert from; send amount instead. |
| no_fee_rule | 422 | no | No fee rule applies to this operation right now. |
| not_acceptable | 409 | no | Only a short payment with nothing verifying or held can be accepted. |
| not_cancellable | 409 | no | Only a payment nobody has paid yet can be cancelled. |
| not_found | 404 | no | The resource does not exist in this account. |
| not_implemented | 501 | no | The endpoint is not implemented. |
| not_succeeded | 409 | no | Only a succeeded payment can be fulfilled. |
| open_intents_cap_reached | 429 | yes | This account already has the maximum number of open payment intents; let some be paid, expire or be cancelled, then retry. |
| operation_disabled | 422 | no | The operation is not available for this asset. |
| operation_outcome_unknown | 409 | no | The provider's outcome for this operation is not proven. Do not retry; the funds stay reserved until staff resolve it, then the status changes. |
| operation_paused | 503 | yes | The platform paused this operation; retry later. |
| order_ref_required | 400 | no | order_ref is required. |
| origin_exists | 409 | no | This origin is already approved for the account. |
| origin_not_approved | 403 | no | The origin is not in this account's approved checkout origins. |
| other_browser | 403 | no | The connection must be approved in the browser that started it. |
| over_daily_limit | 422 | no | The amount exceeds the remaining daily limit. |
| over_monthly_limit | 422 | no | The amount exceeds the remaining monthly limit. |
| over_per_transaction_limit | 422 | no | The amount exceeds the per-transaction limit. |
| overpay_nothing_held | 422 | no | The payment holds no overpayment to return. |
| overpay_return_in_progress | 409 | no | A return of this overpayment is already under way. |
| overpay_window_closed | 409 | no | The window to return the overpayment has closed; staff return it. |
| passkey_failed | 422 | no | The passkey could not be verified. |
| passkey_unknown | 401 | no | The passkey is not registered. |
| password_breached | 400 | no | The password appears in a known data breach. |
| policy_restricted | 403 | no | A policy restriction applies to this account, asset or network, so the action is refused. Contact support; retrying does not help. |
| 503 | yes | No current price is available, so the operation is paused for the asset. | |
| quote_changed | 409 | no | Fees changed since the quote; get a new quote and confirm again. |
| quote_expired | 409 | no | A conversion quote expired before it was used; request a new one. |
| rate_limited | 429 | yes | Too many requests; wait for Retry-After seconds. |
| reason_required | 400 | no | A reason of at most 500 characters is required. |
| refund_destination_unverified | 422 | no | Refund to the payer's address or save the address first. |
| refund_exceeds_entitlement | 422 | no | The refund exceeds what the payer is entitled to. |
| refund_exceeds_received | 422 | no | Refunds would exceed what the payment received. |
| schedule_not_pending | 409 | no | The fee schedule is not awaiting approval. |
| scope_not_allowed | 403 | no | The role cannot grant an app one of the requested permissions. |
| security_freeze | 423 | no | Payouts are paused for 48 hours after a security change. |
| session_required | 403 | no | The endpoint needs a signed-in team member, not an API key or app. |
| signature_invalid | 401 | no | The callback signature is missing or invalid. |
| step_up_failed | 422 | no | The confirmation code is not valid. |
| test_mode_only | 403 | no | The endpoint is only available to test-mode API keys. |
| 503 | no | This deployment has no sandbox simulator, so test-mode requests are refused. | |
| token_expired | 422 | no | The link or invitation has expired. |
| token_invalid | 422 | no | The link is invalid or was already used. |
| too_long | 400 | no | A field exceeds its length limit. |
| too_many_endpoints | 409 | no | Disable an endpoint before adding another (10 active at most). |
| too_many_keys | 409 | no | Revoke an unused key before creating another. |
| too_many_origins | 409 | no | Remove an unused checkout origin before adding another (50 at most). |
| totp_enabled | 409 | no | An authenticator app is already enabled. |
| totp_not_enrolled | 409 | no | Start enrolment before confirming. |
| travel_rule_invalid | 400 | no | travel_rule is incomplete. |
| travel_rule_required | 422 | no | Transfers of this value need the beneficiary's details. |
| unauthenticated | 401 | no | No valid credential was sent. |
| unknown_asset | 400 | no | asset_id is not a listed asset. |
| unknown_currency | 400 | no | No rate is available for the currency. |
| unknown_network | 400 | no | The network is not one of the supported networks. |
| unknown_symbol | 400 | no | No asset has this symbol. |
| username_taken | 409 | no | The username is taken. |
| weak_password | 400 | no | Passwords must be 10-128 characters. |
| widget_token_expired | 401 | no | The short-lived checkout widget token has expired; request a fresh token from the merchant backend. |
| withdrawals_disabled | 422 | no | Payouts are disabled for this asset. |