Docs
ENFR
Dashboard
Products

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.

  1. Open Cards › Top up the card balance.
  2. 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).
  3. Click Generate the deposit address. Each top-up gets its own address, the exact amount of tokens to send and an expiry time.
  4. 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

bash
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:

JSON
{
  "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.city and address.state: 2 to 60 characters, no digits. address.line1 (required) and address.line2: letters, digits, spaces and , . - only. address.postal_code is 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.back is required except for a passport. Otherwise 400 document_invalid or parameter_missing, with param naming the side.
  • If the issuer declines the submission itself, you get 402 verification_declined (or identity_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

bash
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_limit does not apply: the card amount is the limit. Sending both returns 400 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 with POST /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:

JSON
{ "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.