TuCOPRamp

Errors

Error body, common codes and when to retry.

Error body

Errors are sent with Content-Type: application/problem+json (RFC 7807). Make sure your HTTP client parses that content type as JSON.

json
{
  "type": "https://errors.tucopramp.xyz/invalid-api-key",
  "title": "Invalid api key",
  "status": 401,
  "code": "invalid_api_key",
  "detail": "Invalid or unknown API key.",
  "request_id": "3b0f6c2e-1d4a-4f7e-9c8b-2a1e0d9f8c7b"
}
FieldMeaning
codeMachine-readable code in snake_case. Branch on this field only.
statusThe HTTP status.
detailA sentence for people. It can change at any time.
title, typeDerived from code. Do not fetch type; it is an identifier, not a page.
request_idInclude it when you contact TuCOP about a request.
issuesOn some validation errors: a list of { path, code } for the fields that failed.

Some errors add fields of their own: amount_below_minimum includes minimum, pay_limit_exceeded includes check, invalid_document includes reason, and product_not_enabled includes category and required.

Every platform endpoint (see API conventions) answers errors only in this shape.

This page lists the codes that any endpoint can answer. Codes specific to one product are listed on its page: Parties and sessions, Destinations, Payments (which also covers GET /rates), Withdrawals, Deposits and Pay from your own payments provider account.

Legacy error bodies

A few P2P responses predate this shape. TuCOP Wallet and other clients depend on them, so they stay as they are. New endpoints never use them.

EndpointBodyRead
POST /p2p/offramp/orders, POST /p2p/onramp/orders: business errors (consent_required, amount_limit_exceeded, ...){ "code", "error_code", "message", "details" } as application/jsoncode (error_code holds the same value)
The same two endpoints: Idempotency-Key reused with a different body409 with { "error_code": "idempotency_key_reuse", "message" } as application/jsonerror_code

These bodies are stored with the idempotency key so a retry replays the same answer, which is why they are not in the envelope. On platform endpoints the same reuse case is 422 idempotency_key_reuse in the envelope.

Common codes

Authentication and limits

CodeStatusWhen
invalid_api_key401Missing, unknown, malformed, expired or revoked key, a key with a wrong checksum, a key for the other environment, or a paused consumer.
api_key_conflict400X-TuCOPRamp-Key and Authorization: Bearer carry two different keys. Send one.
api_key_ip_not_allowed403The key is limited to IP ranges and the request comes from another address.
api_key_scope_missing403A read-only key sent a request that changes something (POST, PATCH, PUT, DELETE). Use a full-access key.
api_key_origin_not_allowed403An older tcr_<env>_pk_ key limited to browser origins, used from another origin or with none.
product_not_enabled403The route needs a service TuCOP has not enabled for your consumer. required lists the services that would open it (any one is enough) and category says which kind they are (on_off_ramp or p2p). GET /consumer lists yours. See Services.
rate_limited_api_key429Over the key's own per-minute limit. See Retry-After.
rate_limited_consumer429Over one of your consumer's budgets: 1,000 platform requests per minute shared by all your keys, 120 per minute on GET /rates, or the session code and sign-in budgets. See Rate limits and Retry-After.
rate_limited_email429Too many codes or code checks for one email address. See Retry-After.
rate_limited_party_session429Too many POST /parties with one party session. See Retry-After.
rate_limited_wallet429Over a per-wallet limit: 10 session nonces per minute for one address, or the P2P per-wallet budget. See Retry-After.
rate_limited_ip429Over a per-IP limit: requests without a valid key from one address, or, for a trusted relay, the /sessions limits for one end user's X-TuCOPRamp-Client-IP. See Retry-After.
signature_invalid401Wallet headers missing or malformed, or the signature does not match the message.
signature_expired401X-Wallet-Timestamp is more than 5 minutes from the server clock.

Requests

CodeStatusWhen
invalid_json400The body is not valid JSON.
invalid_body400The JSON body failed validation. See issues.
invalid_query400A query parameter failed validation.
invalid_api_version400A TuCOPRamp-Version header was sent with an unknown value. The header is not needed: stop sending it. See Versioning.
not_found404No such route.
payload_too_large413The body is over 256 KB.
unsupported_encoding415The body uses a content encoding or charset the API does not read.
internal_error500Unexpected server error.

Idempotency on platform endpoints

CodeStatusWhen
idempotency_key_required400POST or PATCH without an Idempotency-Key header.
idempotency_key_invalid400The key is longer than 255 characters or has spaces or non-ASCII characters.
idempotency_in_progress409A request with the same key is still running. See Retry-After.
idempotency_key_reuse422The same key was sent with a different body, method or path.

See idempotency.

Payments provider

CodeStatusWhen
provider_unavailable502The payments provider could not be reached or failed. Retry with backoff and the same Idempotency-Key.
provider_rejected422The payments provider refused to create a withdrawal address or a deposit account.
rate_unavailable502The payments provider has no exchange rate right now. Retry.
provider_error502POST /payments: the payments provider did not return deposit instructions.

Party sessions

Every endpoint that acts for a party (/parties, /destinations, /quotes, /payments, /limits, /withdrawals, /deposits) can answer these.

CodeStatusWhen
party_session_required401X-TuCOPRamp-Party-Session is missing on an endpoint that acts for a party, and TuCOP has not linked a payments provider account to your integrator. POST /parties always needs a session.
party_session_invalid401The party session is unknown, expired, revoked or was opened for another consumer.
party_required403The party session has no party linked to your app yet.
party_not_linked403The party withdrew its consent to your app.
integrator_not_linked409No session was sent, and the payments provider account TuCOP set for your integrator is not linked to it yet.

Sign-in, onboarding and identity codes (invalid_code, invalid_document, party_identity_not_proven, ...) are in Parties and sessions. Codes for first-party keys and for integrators that pay from their own payments provider account (first_party_not_available, destination_limit_reached, integrator_customer_mismatch) are in Destinations and Pay from your own payments provider account.

When to retry

  • 5xx: retry with backoff (for example 1, 2, 4 and 8 seconds). Requests with an Idempotency-Key are safe to retry with the same key.
  • 409 idempotency_in_progress: wait for Retry-After seconds, then retry with the same key.
  • 429: wait for Retry-After seconds, then retry.
  • 401 signature_expired: sign again with a fresh timestamp and retry once.
  • 401 signature_invalid: do not retry. Your message or body hash differs from what the server computed.
  • Other 4xx: do not retry. Fix the request.