Cards
Issue virtual Visa and Mastercard cards to your team, your customers or your AI agents.
Monerails issues virtual cards in US dollars, through a regulated partner institution. Cards work online wherever Visa or Mastercard is accepted.
The money
Cards draw from your cards balance, in US dollars, separate from your balances in African currencies. Top it up from the dashboard with stablecoins (see Top up with crypto). Each card then has its own balance: you fund it from the cards balance and can withdraw back at any time. Read both balances with Retrieve the balance.
Top up with crypto
Top-ups are made in the dashboard only (there is no API endpoint for them), by an Owner or a Finance member, once your business is verified for live mode.
- Open Cards › Top up the card balance.
- Choose the amount in US dollars (from $10 to $10,000 per top-up) and the asset and network: USDT or USDC on TRON (TRC20), BNB Smart Chain (BEP20), Polygon, Solana or Ethereum (ERC20).
- Click Generate the deposit address. Each top-up gets its own address, the exact amount of tokens to send and an expiry time.
- Send that exact amount, only on the network you chose, in a single transfer, before the expiry time.
Once the payment is confirmed on the network, the cards balance is credited with the amount you requested, minus the top-up fee shown before you generate the address. You receive an email and a cards_balance.credited event, and the top-up appears in your transactions. A top-up is credited once only, however many notifications arrive.
If the payment does not match the request (too little, too much, another token or network, or paid after the expiry time), nothing is credited automatically: the Monerails team checks the payment and credits the value actually received, then you are notified. Never reuse an old deposit address: generate a new one for each top-up.
In test mode there is no address: enter the amount and click Credit the test balance. The test cards balance is credited at once; no crypto is involved.
1. Create the cardholder
curl https://api.monerails.com/v1/cardholders \
-H "Authorization: Bearer $MONERAIL_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "customer",
"first_name": "Awa",
"last_name": "Ndiaye",
"email": "awa@example.com",
"phone": "+237670000999",
"country": "CM",
"birth_date": "1991-02-03",
"id_document": "national_id",
"documents": { "front": "data:image/jpeg;base64,…", "back": "data:image/jpeg;base64,…" }
}'type is team for your own staff and customer for your customers. Cardholders have no access to your dashboard.
A photo of the identity document is required on creation: documents.front, and documents.back except for a passport (JPEG or PNG, base64 or data: URI, 4 MB at most, at least 600 × 400 px). Missing: 400 parameter_missing; unreadable, too large or too small: 400 document_invalid, with param naming the side. The photos are checked before the cardholder is created and reused by the verification (verification.documents_on_file: true).
The card issuer checks every field, so the API applies its rules before anything is sent (400 with param otherwise):
| Field | Rule |
|---|---|
first_name, last_name |
Exactly as on the document. 1 to 50 characters: letters (accents allowed), spaces, apostrophes, periods, hyphens. |
email |
Valid address. Unique per business. |
phone |
Mobile number in E.164 format (+237670000999). A national number gets the country code of country; the national part must have that country’s length (phone_invalid). |
country |
Country of residence: CM, GA, TD, CG, CF, CD, CI, SN, BJ, TG, BF, ML, NE, GN, NG, GH, KE, UG, TZ, RW, ZM, ZA (country_unsupported). |
birth_date |
YYYY-MM-DD, at least 18 years old (cardholder_underage). |
id_document |
national_id (Ghana Card in Ghana), passport, driver_license, voters_card. |
id_number |
Passport: 6 to 9 letters or digits. Other documents: 4 to 30 characters (letters, digits, spaces, /, -). |
2. Verify their identity
The issuer must verify every cardholder. Submit the verification with the document details. The photos sent on creation are used; include documents only to replace them:
{
"id_number": "CM12345678",
"birth_date": "1991-02-03",
"place_of_birth": "Douala",
"address": { "line1": "12 rue Joss", "city": "Douala", "state": "Littoral" },
"documents": { "front": "data:image/jpeg;base64,…", "back": "data:image/jpeg;base64,…" }
}- The first name, last name and birth date must match the document exactly.
- Photos must be sharp, uncropped and without glare, with the whole document visible. For a passport, send the front only.
place_of_birth,address.cityandaddress.state: 2 to 60 characters, no digits.address.line1(required) andaddress.line2: letters, digits, spaces and, . -only.address.postal_codeis optional (1 to 10 characters): leave it out where there is none.- Images: JPEG or PNG, 4 MB at most, at least 600 × 400 px.
documents.backis required except for a passport. Otherwise400 document_invalidorparameter_missing, withparamnaming the side. - If the issuer declines the submission itself, you get
402 verification_declined(oridentity_already_registered) with a neutral message: check the details and photos, then submit again.
verification.status moves to in_review, then verified or rejected, announced by cardholder.kyc_updated. After a rejection, read verification.reason (for example “Name/dob mismatch”), fix the cause and submit again. Typical causes: blurry photo, expired document, unreadable document, face mismatch, cropped document. You can submit 5 times per cardholder per 24 hours.
Verification is per business: a person already verified by another business is verified again for yours. Within your business, a verified identity can be reused. In test mode, decide yourself with the test helper.
3. Issue the card
curl https://api.monerails.com/v1/cards \
-H "Authorization: Bearer $MONERAIL_KEY" \
-H "Idempotency-Key: card-awa-1" \
-H "Content-Type: application/json" \
-d '{
"cardholder": "5df6acd9-4bac-4e19-869c-fcde6b79f389",
"type": "customer",
"label": "Subscriptions",
"amount": 1000,
"spending_limit": { "amount": 20000, "interval": "daily" }
}'amount (US cents) is taken from the cards balance. It pays the issuing fee and the rest becomes the card balance; at least $1 must remain. The card usually comes back active (201). If the issuer takes longer, or its answer is not final yet, you get 202 with status: "pending", then card.issued or card.issue_failed. The money returns to the cards balance only once a failure is final.
The full card number and CVC never go through the API. An Owner or Finance member can display them for 60 seconds in the dashboard, with Show card details, to pass them on to the cardholder.
4. Manage the card
| Action | Endpoint |
|---|---|
| Add money | POST /v1/cards/{id}/fund |
| Take money back (at least $1 stays) | POST /v1/cards/{id}/withdraw |
| Block payments | POST /v1/cards/{id}/freeze |
| Unblock | POST /v1/cards/{id}/unfreeze |
| Close for good, balance back to the cards balance | POST /v1/cards/{id}/terminate |
Each action answers 200 with the card, or 202 when the issuer’s answer is not final yet: the action has not failed, and its result arrives by webhook (card.funded, card.withdrawn, card.frozen, card.unfrozen, card.terminated).
Spending appears as card_payment transactions with the card ID, and as card.transaction events. Declined attempts send card.authorization_declined.
Single-use cards
Create a card with "single_use": true for a one-off purchase:
- The card can be paid once. Later payments are declined and nothing is charged.
- It cannot be funded or withdrawn from (
400 card_single_use). spending_limitdoes not apply: the card amount is the limit. Sending both returns400 parameter_invalid.- Its remaining balance returns to the cards balance when it is terminated: automatically 30 days after issue, or earlier with terminate.
What the issuer can do
- Terminate a card after repeated declines for insufficient funds. You receive
card.terminated. Keep enough money on cards that pay subscriptions. - Settle a pre-authorization for more than the authorized amount. Hotels and car rentals often do. Keep a margin on the card.
- Take international or contactless fees later, if the card balance was too low at the time of the payment.
Card fees
Every card fee is taken from the card itself. Your current prices are shown in the dashboard (Settings › Pricing › Cards, with the monthly fee statement) and in Annex 1 of your contract.
Fee (fee.type) |
When | Linked to |
|---|---|---|
issuance |
At issuance, from the initial funding | The card |
withdrawal |
Withdrawal from a card to the cards balance; funding a card is free | The withdrawal |
maintenance |
Every month, on the card’s anniversary date (active or frozen) | The card |
processing |
Processing fee (2.50% + USD 0.50): charged only on successful payments, at settlement | The payment (fee.payment) |
issuer_cross_border |
Possible international fees (+ 2.30% + USD 0.50): only when a payment is subject to the issuer’s cross-border fees. Passed through at exact cost, with no Monerails margin (fee.pass_through: true) |
The payment, when it can be identified |
decline |
Declined payment, or authorization that expired unsettled | The card |
chargeback, network_fine |
Chargeback, and card network fines passed through at cost | The card |
To get the fees of a payment, list card_fee transactions and keep those whose fee.payment is the payment ID. In the dashboard they are shown under the payment, and the monthly fee statement can be downloaded as CSV or PDF from Settings › Pricing › Cards.
- Balance too low: the fee is recorded as pending and collected automatically on the next funding. For monthly maintenance, a new attempt is made automatically on the 15th day after the due date ("Maintenance pending — next attempt on …" on the card); if the balance is still too low, it stays pending until the next funding. A card is never terminated for unpaid maintenance.
- Month end: anything still due is taken from the cards balance. If that is not enough, card issuance and funding are suspended until the next deposit to the cards balance, which settles the debt.
- Repeated declines: after 3 declined payments within 24 hours, the card is frozen automatically (
card.frozen). Unfreeze it whenever you want withPOST /v1/cards/{id}/unfreeze. - Deferred network fees: some fees arrive after the payment, on the issuer’s monthly invoice. Monerails reconciles them card by card; a fee already taken is never taken twice.
Cards for AI agents
An agent card belongs to an AI agent rather than to a person: it has no cardholder and no identity verification. Before the first one, an Owner issues an agent card from the dashboard (Cards › Issue a card, For: AI agent); this sends your business details to the issuer (RCCM number, address, city, international phone). Until then, the API returns 400 agent_cards_not_enabled. After that:
{ "type": "agent", "agent_name": "Procurement bot", "amount": 5000, "spending_limit": { "amount": 5000, "interval": "per_transaction" } }Give each agent its own card with a tight spending limit, use a single-use card (without spending_limit) for one-off purchases, and freeze the card when the agent is idle.