Cards API Reference
Base URLs: https://processing.mainnet.rubin.trade (mainnet), https://processing.testnet.rubin.trade (testnet). {provider} is the id from GET /v4/providers.
Auth column: public — no signature; signed — signed request for the customer address.
| Method | Path | Auth | Purpose |
|---|---|---|---|
| GET | /v4/providers | public | Providers, tariffs, limits |
| GET | /v4/{provider}/quote | signed | Price of an operation |
| POST | /v4/{provider}/orders/paid | signed | Report a payment, create the order |
| POST | /v4/{provider}/orders | signed | Withdraw; order-first issue or top-up |
| GET | /v4/{provider}/orders | signed | List orders |
| GET | /v4/{provider}/orders/{orderId} | signed | One order |
| GET | /v4/{provider}/account | signed | Money in progress at the provider |
| GET | /v4/{provider}/cards | signed | List cards |
| GET | /v4/{provider}/cards/{cardId} | signed | One card |
| POST | /v4/{provider}/cards/{cardId}/reveal | signed | Card number, CVC, PIN |
| POST | /v4/{provider}/cards/{cardId}/password | signed | Set or change the PIN |
| POST | /v4/{provider}/cards/{cardId}/rename | signed | Rename a card |
| POST | /v4/{provider}/cards/{cardId}/deactivate | signed | Close a card permanently |
| GET | /v4/{provider}/operations | signed | Payment history |
| GET | /v4/{provider}/cards/{cardId}/operations | signed | Payment history of one card |
| GET | /v4/{provider}/operations/recent | signed | Latest operations |
| GET | /v4/{provider}/operations/summary | signed | Monthly totals |
| GET | /v4/{provider}/operations/export | signed | History as CSV |
| GET | /v4/{provider}/verification-codes | signed | 3-D Secure and wallet codes |
| GET | /v4/{provider}/events/channel | signed | Key of the change-signal channel |
Testnet also has simulation endpoints.
An unknown {provider} answers 404. Identifiers are UUIDs (400 otherwise). Amounts are decimal strings. Computed amounts have a fixed scale: USDC 6 decimals, USD 2; tariffs and limits can be shorter, e.g. "10". Timestamps are ISO 8601. Only GET and POST are used. Responses may contain fields not listed here; do not rely on them.
Errors
Every error has the same shape:
{ "errors": [{ "code": "AMOUNT_BELOW_MIN", "msg": "Amount is below minimum of 10 USD", "min": "10" }] }code, min, max and retryAfterSeconds are present only where they apply. Request validation errors (400) are a list of { "value", "msg", "param", "location" } without code. A card or order that does not exist or belongs to another address answers 404 with msg only; a card missing at the card provider answers 404 CARD_NOT_FOUND.
| Code | HTTP | Meaning |
|---|---|---|
FEE_NOT_FOUND | 422 | No such tariff, or it is not on sale |
ISSUE_DISABLED | 422 | The provider does not issue cards now |
TOO_MANY_CARDS | 422 | The address reached limits.maxCards (max), counting cards being issued |
TOO_MANY_OPEN_ORDERS | 422 | The address reached limits.maxOpenOrders (max) |
ORDER_IN_PROGRESS | 422 | The card already has an order running |
CARD_INACTIVE | 422 | The card is not active |
AMOUNT_BELOW_MIN | 422 | Below the minimum (min) |
AMOUNT_ABOVE_MAX | 422 | Above the maximum (max) |
INSUFFICIENT_CARD_BALANCE | 422 | The withdrawal exceeds the card balance (max), or the balance is unknown |
WITHDRAW_NOT_SUPPORTED | 422 | The card does not allow withdrawals |
PASSWORD_NOT_SUPPORTED | 422 | The card does not support a PIN of your choice |
CARD_BALANCE_NOT_ZERO | 422 | Closing a card needs a balance below 1 USD |
QUOTE_EXPIRED | 409 | expectedTotalUsdc differs from the current price; get a new quote |
PAYMENT_NOT_FOUND | 404 | The payment is not on chain yet, or another address made it; retry |
REVEAL_RATE_LIMITED | 429 | Too many card detail requests; wait retryAfterSeconds |
WALLET_SIGNATURE_REQUIRED | 403 | This action does not accept a session signature |
CHAIN_UNAVAILABLE | 503 | The chain cannot be read right now; retry |
PROVIDER_UNAVAILABLE | 503 / 502 | The card provider is down or this operation is closed for now; retry later |
PROVIDER_RATE_LIMITED | 503 | The card provider is throttling; wait retryAfterSeconds |
PROVIDER_ERROR | 422 / 502 | The card provider rejected the request (msg has its text) or answered with something unreadable |
CARD_NOT_FOUND | 404 | The card is missing at the card provider |
Authentication errors are listed on the Keys & Authentication page.
Providers
GET /v4/providers
Public. Cards providers with their tariffs and limits; cached for 30 seconds.
{
"providers": [
{
"id": "mock",
"displayName": "Mock Card (testnet)",
"flow": {
"issue": true,
"topup": true,
"withdraw": "per_card",
"password": "per_tariff",
"verificationCodes": true,
"rename": true,
"freeze": false,
"reveal": "live"
},
"fees": [
{
"feeId": 905,
"active": true,
"name": "Premium",
"userPriceUsdc": "39.000000",
"startBalanceUsd": "0",
"lifespanDays": 1095,
"depositFeePercent": 1.9,
"withdrawalFeePercent": 0,
"txFeeUsd": "0",
"txFeeRate": 0,
"txInUsaFeeUsd": "0",
"minDepositUsd": "10",
"canWithdraw": false,
"canSetPassword": true,
"options": ["E_PAYMENTS_ENABLED", "APPLE_PAY_ENABLED"],
"brand": "visa"
}
],
"limits": {
"maxCards": 3,
"maxOpenOrders": 3,
"topupMinUsd": "10",
"topupMaxUsd": "5000",
"withdrawMinUsd": "0",
"withdrawMaxUsd": "5000"
},
"payment": { "quoteTtlSeconds": 120, "driftTolerancePercent": "1", "paymentTtlSeconds": 600 },
"chain": { "providerId": "mock", "assetId": 0, "denom": "uusdc", "decimals": 6, "enabled": true, "maxOrderUsdc": "15500.000000" },
"providerAvailable": true,
"simulateOperations": true,
"feesFetchedAt": "2026-11-06T12:00:00.000Z"
}
]
}| Field | Type | Description |
|---|---|---|
id | string | The {provider} path segment |
displayName | string | Provider name |
flow | object | What the provider supports, see below |
fees | array | Tariffs, see below. May be empty if the tariffs cannot be read now |
limits | object | Per-address limits and USD bounds for top-ups and withdrawals |
payment | object | Quote lifetime, price tolerance and order-first payment window |
chain | object | null | On-chain settings; null while they cannot be read |
providerAvailable | boolean | The card provider responds. If false, POST /orders answers 503, and an on-chain payment waits in paid until the provider returns |
simulateOperations | boolean | Simulation endpoints are available |
feesFetchedAt | string | null | When the tariffs were read |
flow
| Field | Values | Meaning |
|---|---|---|
issue, topup | boolean | New cards and top-ups are available |
withdraw | per_card, none | Depends on the card's canWithdraw, or not available |
password | per_tariff, none | Depends on the tariff's canSetPassword, or not available |
verificationCodes | boolean | One-time codes are delivered through the API |
rename | boolean | Cards can be renamed |
freeze | boolean | Temporary freeze; currently always false |
reveal | live, none | Card details are read live from the provider, or not available |
fees[])
| Field | Type | Description |
|---|---|---|
feeId | number | Tariff id |
active | boolean | On sale. false — only for showing the terms of cards issued earlier |
name | string? | Tariff name |
userPriceUsdc | string | Price of issuing a card, USDC, all fees included |
startBalanceUsd | string | Balance on the card right after issue, included in the price |
lifespanDays | number | How long the card lives |
depositFeePercent | number | Top-up fee, percent (1.9 = 1.9 %) |
withdrawalFeePercent | number | Withdrawal fee, percent |
txFeeUsd | string | Fixed fee per purchase, USD |
txFeeRate | number | Fee per purchase as a fraction (0.004 = 0.4 %) |
txInUsaFeeUsd | string | Fixed fee per purchase in the USA, USD |
minDepositUsd | string | Minimum top-up, USD |
canWithdraw | boolean | Cards of this tariff allow withdrawals |
canSetPassword | boolean | Cards of this tariff support a PIN of your choice |
options | string[] | E_PAYMENTS_ENABLED, APPLE_PAY_ENABLED |
brand | string | visa, mastercard or unknown |
limits
| Field | Description |
|---|---|
maxCards | Active cards per address, counting cards being issued |
maxOpenOrders | Open orders per address |
topupMinUsd, topupMaxUsd | Bounds of one top-up, USD on the card |
withdrawMinUsd, withdrawMaxUsd | Bounds of one withdrawal, USD off the card |
payment
| Field | Description |
|---|---|
quoteTtlSeconds | How long to treat a quote as fresh |
driftTolerancePercent | How far the card provider's price may move from the order. Beyond it an issue or top-up is refunded and a withdrawal fails; within it the order completes, so the card or the credit can come in slightly below the quote |
paymentTtlSeconds | Order-first variant: how long an order waits for its payment |
chain
| Field | Description |
|---|---|
providerId | provider_id for MsgOrder |
assetId, denom, decimals | The payment asset: USDC, uusdc, 6 decimals |
enabled | The provider accepts payments on chain |
maxOrderUsdc | The largest single payment, null — no cap |
Quote and orders
GET /v4/{provider}/quote
The price of an operation, after checking the tariff, the card, the amount bounds and running orders on the card. It does not check everything a payment needs.
| Parameter | Required | Description |
|---|---|---|
type | always | issue, topup or withdraw |
feeId | issue | Tariff |
cardId | topup, withdraw | Card |
amountUsd | topup, withdraw | USD to put on or take off the card, up to 2 decimals |
{
"type": "issue",
"amountUserUsdc": "39.000000",
"amountCardUsd": "0.00",
"providerFeeUsdt": "39.000000",
"markupUsdc": "0.000000",
"feePercent": "0",
"feeId": 905,
"cardId": null,
"driftTolerancePercent": "1",
"quoteTtlSeconds": 120
}| Field | Type | Description |
|---|---|---|
amountUserUsdc | string | USDC the customer pays (issue, topup) or should receive (withdraw) |
amountCardUsd | string | USD that should land on the card (issue, topup) or leaves it (withdraw) |
providerFeeUsdt | string | Tariff fee inside this amount |
markupUsdc | string | Service fee inside this amount |
feePercent | string | Tariff fee in percent; 0 for issue |
feeId, cardId | number, string | null | Tariff and card of the operation |
The price is checked again when the payment arrives: a payment that differs from the current price returns in full.
Errors: FEE_NOT_FOUND, CARD_INACTIVE, AMOUNT_BELOW_MIN, AMOUNT_ABOVE_MAX, WITHDRAW_NOT_SUPPORTED, INSUFFICIENT_CARD_BALANCE, ORDER_IN_PROGRESS. A withdrawal quote can read the balance from the card provider, so it can also answer PROVIDER_UNAVAILABLE, PROVIDER_RATE_LIMITED and PROVIDER_ERROR.
POST /v4/{provider}/orders/paid
Reports an on-chain MsgOrder and creates the order from it. See Integration flow.
{ "ref": "o1:i:905:0123456789abcdef" }Answers 201 with { "order": … } if the order was created, 200 if it already existed. The order is created from what is on chain: the payer is whoever signed MsgOrder, the amount is what arrived. If the rules no longer allow the operation or the amount differs from the price, the order is created in refund_submitted, and the payment returns.
Errors: 400 — ref is not in the o1:… format, PAYMENT_NOT_FOUND, CHAIN_UNAVAILABLE.
POST /v4/{provider}/orders
Creates a withdrawal, or an issue or top-up order in the order-first variant.
| Field | Required | Description |
|---|---|---|
type | always | withdraw, issue or topup |
feeId | issue | Tariff |
cardId | topup, withdraw | Card |
amountUsd | topup, withdraw | USD, up to 2 decimals |
clientId | no | Your unique id, up to 64 characters. A repeat returns the same order before any other check, even with other parameters |
expectedTotalUsdc | no | The price you showed; if it differs, answers 409 QUOTE_EXPIRED |
Answers 201 with { "order": … }, or 200 if clientId matched an existing order. A withdrawal is checked against the card's live balance.
Errors: everything from the quote, ISSUE_DISABLED, TOO_MANY_CARDS, TOO_MANY_OPEN_ORDERS, QUOTE_EXPIRED, PROVIDER_UNAVAILABLE.
GET /v4/{provider}/orders/{orderId}
{
"order": {
"orderId": "2f6c1d7e-8a3b-4c55-9f10-6d2e7a1b3c44",
"provider": "mock",
"type": "issue",
"status": "completed",
"cardId": "7b1e4f60-2d9a-4e11-8c3f-1a2b3c4d5e6f",
"feeId": 905,
"amountUserUsdc": "39.000000",
"amountCardUsd": "0.00",
"providerFeeUsdt": "39.000000",
"markupUsdc": "0.000000",
"chain": {
"paymentTxHash": "8F3A…",
"paymentAmountUsdc": "39.000000",
"paidAt": "2026-11-06T12:00:04.000Z",
"refundTxHash": null,
"refundAmountUsdc": null,
"refundedAt": null,
"creditTxHash": null,
"creditAmountUsdc": null,
"creditedAt": null
},
"payment": null,
"failReason": null,
"createdAt": "2026-11-06T12:00:05.000Z",
"updatedAt": "2026-11-06T12:00:09.000Z",
"completedAt": "2026-11-06T12:00:09.000Z"
}
}| Field | Type | Description |
|---|---|---|
orderId | string (UUID) | Order id |
type | string | issue, topup, withdraw |
status | string | See statuses |
cardId | string | null | The card of the order. On issue, set when the card is issued |
feeId | number | null | The tariff of an issue order |
amountUserUsdc | string | USDC the customer pays or receives |
amountCardUsd | string | null | USD on the card |
providerFeeUsdt | string | Tariff fee inside the amount |
markupUsdc | string | Service fee inside the amount |
chain | object | On-chain transactions: payment, refund, credit. *AmountUsdc appears when the transaction is sent, *TxHash and *At when it passes. paymentTxHash can stay null: keep the hash of your own transaction |
payment | object | null | What to sign, only in awaiting_payment: providerId, ref, amountUsdc, amountQuantums, expiresAt |
failReason | string | null | See reasons. Always null in manual_review |
createdAt, updatedAt, completedAt | string | null | Timestamps |
GET /v4/{provider}/orders
| Parameter | Description |
|---|---|
status | open — not finished; all (default) |
type | issue, topup, withdraw |
cardId | Orders of one card |
page | From 1 |
limit | 1–100, default 20 |
{ "orders": [ … ], "total": 3, "page": 1, "limit": 20 }
GET /v4/{provider}/account
The money the address has in progress with the provider. USDC stays in the wallet until an order is paid, so this is for reconciliation, not a balance.
{
"address": "rit1…",
"assetId": 0,
"denom": "uusdc",
"positions": [{ "provider": "mock", "amount": "139.000000" }],
"inFlight": [{ "orderId": "2f6c…", "type": "topup", "status": "paid", "amountUsdc": "100.000000" }],
"source": "chain",
"updatedAtHeight": null
}| Field | Description |
|---|---|
positions | Paid to the provider and not returned: payments minus refunds minus credits. Caps how much a withdrawal can credit |
inFlight | Orders whose payment has left the wallet and which are not closed yet |
source, updatedAtHeight | chain — read live; indexer — from a snapshot at that height |
Errors: CHAIN_UNAVAILABLE.
Cards
GET /v4/{provider}/cards
| Parameter | Description |
|---|---|
includeInactive | 1 — include closed and expired cards. Default: active only |
{
"cards": [
{
"cardId": "7b1e4f60-2d9a-4e11-8c3f-1a2b3c4d5e6f",
"provider": "mock",
"status": "active",
"name": "Travel",
"cardholderName": "RUBIN CARD",
"brand": "visa",
"last4": "4821",
"expirationMonth": 11,
"expirationYear": 2029,
"billingAddress": "…",
"balanceUsd": "125.40",
"balanceSyncedAt": "2026-11-06T12:00:00.000Z",
"canWithdraw": false,
"canSetPassword": true,
"activeUntil": "2029-11-06T00:00:00.000Z",
"feeId": 905,
"hasOpenOrder": false,
"createdAt": "2026-11-06T11:00:00.000Z",
"deactivatedAt": null
}
]
}| Field | Type | Description |
|---|---|---|
cardId | string (UUID) | Card id |
status | string | active, deactivated, expired, unknown |
name | string | null | Name given to the card |
cardholderName, billingAddress | string | null | As for an online payment form |
brand | string | null | visa, mastercard, unknown |
last4, expirationMonth, expirationYear | string, number | Safe to show without reveal |
balanceUsd | string | null | Snapshot of the balance; null — not known |
balanceSyncedAt | string | null | When the snapshot was taken; null — a refresh is due |
canWithdraw, canSetPassword | boolean | What this card allows |
activeUntil | string | null | End of the card's life. After it the card is expired, and the balance cannot be withdrawn through the API |
feeId | number | Tariff; GET /v4/providers has its terms even when it is off sale |
hasOpenOrder | boolean | An order on this card is not finished. Blocks closing |
createdAt, deactivatedAt | string | null | Timestamps |
GET /v4/{provider}/cards/{cardId}
{ "card": { … } }. With ?refresh=1, the balance and flags are read from the card provider first, so it can also answer PROVIDER_UNAVAILABLE, PROVIDER_RATE_LIMITED and PROVIDER_ERROR.
POST /v4/{provider}/cards/{cardId}/reveal
No body. Card details, read live from the card provider and not cached (Cache-Control: no-store). See the warning on card data.
{
"number": "4000123412341234",
"cvc": "123",
"pin": "123456",
"expirationMonth": 11,
"expirationYear": 2029,
"cardholderName": "RUBIN CARD",
"billingAddress": "…",
"ttlSeconds": 60
}pin can be null; on the testnet simulator it has 4 digits. ttlSeconds is how long to keep the details on screen.
Errors: CARD_INACTIVE, CARD_NOT_FOUND, REVEAL_RATE_LIMITED, PROVIDER_ERROR, PROVIDER_UNAVAILABLE, PROVIDER_RATE_LIMITED.
POST /v4/{provider}/cards/{cardId}/password
Sets or changes the PIN.
{ "password": "123456" }| Field | Description |
|---|---|
password | Exactly 6 digits |
{ "ok": true }. Answers 404 if the provider has flow.password: "none".
Errors: CARD_INACTIVE, PASSWORD_NOT_SUPPORTED, PROVIDER_ERROR, PROVIDER_UNAVAILABLE, PROVIDER_RATE_LIMITED.
POST /v4/{provider}/cards/{cardId}/rename
{ "name": "Travel" }1–32 characters: letters, digits, space, ., ', -. { "card": { … } }.
Errors: PROVIDER_ERROR, PROVIDER_UNAVAILABLE, PROVIDER_RATE_LIMITED.
POST /v4/{provider}/cards/{cardId}/deactivate
Closes the card permanently. Not available with a session signature.
{ "confirm": true }{ "card": { … } } with status: "deactivated".
A remainder below 1 USD is not returned. The balance check uses the stored snapshot; read ?refresh=1 first.
Errors: CARD_INACTIVE, ORDER_IN_PROGRESS, CARD_BALANCE_NOT_ZERO, WALLET_SIGNATURE_REQUIRED, PROVIDER_ERROR, PROVIDER_UNAVAILABLE, PROVIDER_RATE_LIMITED.
Payment history
GET /v4/{provider}/operations
GET /v4/{provider}/cards/{cardId}/operations is the same for one card.
| Parameter | Description |
|---|---|
cardId | One card |
types | Comma-separated: purchase, refund, deposit, withdrawal |
month | YYYY-MM, UTC. Cannot be combined with from and to |
from, to | ISO 8601 range |
merchant | Merchant name filter, up to 64 characters |
page | From 1 |
limit | 1–100, default 20 |
{
"operations": [
{
"operationId": "c41d7a90-5b2e-4f3a-9e81-7d6c5b4a3f21",
"cardId": "7b1e4f60-2d9a-4e11-8c3f-1a2b3c4d5e6f",
"type": "purchase",
"status": "approved",
"amountUsd": "12.99",
"currency": "USD",
"localAmount": "11.99",
"localCurrency": "EUR",
"feeUsd": "0",
"merchant": "NETFLIX.COM",
"country": "NL",
"declineReason": null,
"orderId": null,
"occurredAt": "2026-11-05T18:21:00.000Z",
"updatedAt": "2026-11-05T18:21:30.000Z"
}
],
"total": 1,
"page": 1,
"limit": 20
}| Field | Type | Description |
|---|---|---|
operationId, cardId | string (UUID) | Operation and card |
type | string | purchase, refund (by a merchant), deposit (top-up), withdrawal |
status | string | purchase: on_hold, approved, declined. refund: approved. deposit, withdrawal: inited, confirmed, rollbacked |
amountUsd, currency | string | Amount and card currency |
localAmount, localCurrency | string | null | Amount in the merchant's currency |
feeUsd | string | null | Fee of this operation |
merchant, country | string | null | Merchant name and country |
declineReason | string | null | Why the purchase was declined |
orderId | string | null | The order behind a top-up or withdrawal |
occurredAt, updatedAt | string | null | Timestamps |
GET /v4/{provider}/operations/recent
| Parameter | Description |
|---|---|
cardId | One card |
limit | 1–20, default 10 |
{ "operations": [ … ] }
GET /v4/{provider}/operations/summary
| Parameter | Description |
|---|---|
month | YYYY-MM, UTC. Default: the current month |
cardId | One card |
{
"month": "2026-11",
"spentUsd": "412.50",
"topupUsd": "500.00",
"withdrawUsd": "0.00",
"refundUsd": "12.99",
"declinedCount": 1,
"byMerchant": [{ "merchant": "NETFLIX.COM", "amountUsd": "12.99", "count": 1 }]
}byMerchant holds the top 5 merchants, then __other for the rest.
GET /v4/{provider}/operations/export
The filters of GET /operations without page and limit. Answers a UTF-8 CSV file of up to 5,000 rows with the columns date, card_last4, type, status, merchant, country, amount_usd, local_amount, local_currency, fee_usd, decline_reason, operation_id.
One-time codes
GET /v4/{provider}/verification-codes
Codes for 3-D Secure and for adding the card to a wallet that have not expired yet (Cache-Control: no-store). See One-time codes.
| Parameter | Description |
|---|---|
cardId | One card |
limit | 1–50, default 20 |
{
"codes": [
{
"codeId": "a90b1c2d-3e4f-4a5b-8c6d-7e8f9a0b1c2d",
"cardId": "7b1e4f60-2d9a-4e11-8c3f-1a2b3c4d5e6f",
"kind": "three_ds",
"paymentServiceName": null,
"otp": "482915",
"amount": "12.99",
"currency": "USD",
"merchant": "NETFLIX.COM",
"createdAt": "2026-11-06T12:00:00.000Z",
"expiresAt": "2026-11-06T12:03:00.000Z"
}
]
}| Field | Description |
|---|---|
kind | three_ds — a purchase; payment_service — adding the card to a wallet |
paymentServiceName | The wallet for payment_service, e.g. Apple Pay |
otp | The code to show |
amount, currency, merchant | What the code confirms; can be null |
expiresAt | When the code stops being valid |
Change signals
GET /v4/{provider}/events/channel
{ "channel": "v4_card", "channelId": "6604983f…222f" }channelId is the id to subscribe with on the indexer WebSocket; null — signals are off.
Service
GET /health
{ "ok": true, "service": "processing" }. Public.