TuCOPRamp

Authentication

API keys, environments, permissions, IP allowlists, expiry and rate limits.

Send the key on every request

Put your consumer API key in the X-TuCOPRamp-Key header, or send it as a Bearer token. Both work the same way.

bash
curl https://api.ramp.tucop.xyz/consumer \
  --header "X-TuCOPRamp-Key: $TUCOPRAMP_API_KEY"

curl https://api.ramp.tucop.xyz/consumer \
  --header "Authorization: Bearer $TUCOPRAMP_API_KEY"
  • Only a Bearer token that starts with tcr_ is read as an API key. Other Bearer tokens (the session tokens some endpoints use) are left alone.
  • If you send both headers, they must carry the same key. Two different keys get 400 api_key_conflict.
  • On an endpoint that also needs a session token in Authorization, put the key in X-TuCOPRamp-Key.

The health probes (/health/live, /health/ready) do not need a key. Every other endpoint in these docs does. Platform endpoints that act for a person (/parties, /destinations, /quotes, /payments, /limits, /withdrawals, /deposits) also need a party session in X-TuCOPRamp-Party-Session, next to the key; see Parties and sessions. When TuCOP linked your integrator's own payments provider account, all of them except POST /parties also accept the key alone; see Pay from your own payments provider account.

Key format

text
tcr_live_sk_AbCdEfGhIjKlMnOp.<secret><checksum>
|   |    |  |                |       |
|   |    |  |                |       6 characters (base62): CRC-32 of everything before it
|   |    |  |                secret, 43 characters (base64url)
|   |    |  public id, 16 characters (base64url)
|   |    key type: sk (secret key)
|   environment: live or test
prefix
  • The public id is not secret. TuCOP uses it to find your key, and GET /consumer returns it as api_key.public_id.
  • The full key is shown once, when TuCOP issues it. TuCOP stores only a hash of the secret and cannot show it again. A lost key is revoked and replaced.
  • The last 6 characters are a checksum: the CRC-32 (the zlib one) of the key text before them, written in base62 (0-9A-Za-z) and padded with 0 to 6 characters. Secret scanners use it to tell a real key from a random string without calling TuCOP. A key with a wrong checksum gets 401 invalid_api_key, like any other malformed key.
  • To find keys in your code or logs, match tcr_(live|test)_(sk|rk|pk)_[A-Za-z0-9_-]{16}\.[A-Za-z0-9_-]{43}[0-9A-Za-z]{6}. The rk (restricted) and pk (publishable) types are reserved and not issued yet.

Older keys

  • Keys issued before the checksum format have the form tcr_<env>_pk_<public id>.<secret>, with no checksum. They keep working until revoked; GET /consumer reports them as kind: "pk_legacy". Create an sk key in the console and revoke the old one.
  • Keys issued before October 2026 have the form tcr_ followed by 64 hex characters. They keep working. GET /consumer returns api_key: null for them.

Live and test environments

EnvironmentBase URLKeys accepted
Productionhttps://api.ramp.tucop.xyztcr_live_sk_...
Sandboxhttps://sandbox.api.ramp.tucop.xyztcr_test_sk_...

Each environment accepts only its own keys. A test key sent to production, or a live key sent to the sandbox, gets 401 invalid_api_key with a WWW-Authenticate header. The response does not say which part was wrong, so check the prefix first.

Expiry

TuCOP can give a key an expiry time. After it, the key gets 401 invalid_api_key, the same as a revoked key. GET /consumer returns it as api_key.expires_at (null when the key does not expire). Issue the replacement before that time.

Permissions

Every key works only for the products TuCOP enabled for your consumer. A request for another product gets 403 product_not_enabled, whatever key you use.

Within those products, a key is either full access or read-only:

KeyScopesCan do
Full access (default)Your consumer's scopesEverything your products allow
Read-onlywallet.read, webhook.receiveGET requests only

A read-only key that sends a POST, PATCH, PUT or DELETE gets 403 api_key_scope_missing, before anything is changed. Use read-only keys for reporting, reconciliation and monitoring, so a leak of one cannot move money. A read-only key cannot open party sessions either (POST /sessions/*).

Choose the permissions when you create the key in the console (Llaves or Sandbox, field Permisos). They cannot be changed afterwards: create a new key and revoke the old one. GET /consumer returns the scopes the calling key has; a key without wallet.write is read-only.

IP allowlist

TuCOP can limit a key to IP addresses or ranges (CIDR), such as 203.0.113.0/24. Requests from any other address get 403 api_key_ip_not_allowed. We recommend it for live keys that can move money: give TuCOP the egress addresses of your servers.

  • The address checked is the public address your request reaches TuCOP from.
  • The docs playground sends requests from your browser, so the address checked is your own. The playground only calls the sandbox.

No browser-origin protection

Secret keys (sk) cannot be limited to browser origins. The Origin header is set by whoever makes the request, so a check on it would not stop anyone holding the key. A key that is in a browser or a mobile app is public.

Older tcr_<env>_pk_ keys that TuCOP limited to browser origins keep that limit until revoked: requests from another origin, or without an Origin header, get 403 api_key_origin_not_allowed.

Rate limits

Limits are counted per integrator (your consumer), per key, per wallet, per email or per IP, never shared with other integrators. Every limit is a rolling window. The platform budget of 1,000 requests per minute is shared by all your keys: adding keys does not raise it.

LimitApplies toBudgetError
Per consumer, platformAll your keys together, on /consumer, /events, /document-types, /sessions, /parties, /destinations, /quotes, /payments, /limits, /rates, /withdrawals and /deposits1,000 requests per minute429 rate_limited_consumer
Per consumer, ratesGET /rates, on top of the platform budget120 requests per minute429 rate_limited_consumer
Per consumer, P2PAll your keys together, on /p2p/* (TuCOP's own apps only)1,000 requests per minute429 rate_limited_consumer
Per consumer, codesEmail codes, wallet nonces and Google nonces issued by /sessions for all your users together300 per 15 minutes429 rate_limited_consumer
Per consumer, sign-in attemptsCode checks and wallet and Google sign-ins on /sessions for all your users together1,200 per 15 minutes429 rate_limited_consumer
Per emailCodes sent to one email address, across all integrators3 per 15 minutes429 rate_limited_email
Per party sessionPOST /parties with one party session10 per 15 minutes429 rate_limited_party_session
Per keyKeys that TuCOP gave a per-minute limit, counted across all TuCOP serversSet per key429 rate_limited_api_key
Per wallet, sessionsPOST /sessions/wallet/nonce, per address in the body, across all integrators10 nonces per minute429 rate_limited_wallet
Per wallet, P2PWallet-signed P2P endpoints, per X-Wallet-Address (TuCOP's own apps only)60 requests per minute429 rate_limited_wallet
Per IPRequests without a valid key60 requests per minute429 rate_limited_ip
Per end user, trusted relay/sessions, per address in X-TuCOPRamp-Client-IP (see below)10 email codes per 15 minutes, 10 sign-in attempts per minute, 60 nonces per minute429 rate_limited_ip

If you need a higher budget, write to support@tucop.org with the volume you expect.

Calling from your own server

If your server relays requests for your users, every request reaches TuCOP Ramp from one address. TuCOP can mark your consumer as a trusted relay. You then send each end user's IP address in the X-TuCOPRamp-Client-IP header, and per-IP limits count that address instead of your server's:

bash
curl https://api.ramp.tucop.xyz/sessions/email-otp \
  --request POST \
  --header "X-TuCOPRamp-Key: $TUCOPRAMP_API_KEY" \
  --header "X-TuCOPRamp-Client-IP: 203.0.113.7" \
  --header "Content-Type: application/json" \
  --data '{ "email": "ana@example.com" }'

Send one IPv4 or IPv6 address, the one your server saw the user connect from. Do not forward a user-supplied X-Forwarded-For as is. With a trusted address, /sessions applies these limits per end user, besides the per-email and per-consumer ones: 10 email codes per 15 minutes, 10 verify or sign-in attempts per minute and 60 wallet nonces per minute. TuCOP ignores the header from consumers that are not trusted relays.

Every 429 carries a Retry-After header in seconds. Wait at least that long before the next request. Poll order status every 15 to 30 seconds rather than faster.

The console's Monitor page shows your own requests per route, with response times (p50, p95, p99), error rates and how many got a 429, for the last hour up to the last 30 days. The sandbox has its own (Monitor de sandbox).

Rotation and revocation

You can hold several keys: one per backend, one per environment. To rotate, or before a key expires:

  1. Create a new key in the console: Llaves for production, Sandbox for test keys.
  2. Deploy it.
  3. Revoke the old one in the same page.

Revocation takes effect on the next request. If a key may have leaked, revoke it in the console at once; if you cannot sign in, write to support@tucop.org.