Docs
ENFR
Dashboard
Products

Cards

Issue virtual Visa and Mastercard cards to your team, your customers or your AI agents.

Monerail issues virtual cards in US dollars, through a licensed card issuer. 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, Cards › Top up: in live mode, with USDT on TRON (TRC20), once the card partner is connected for live mode; in test mode, with Simulate the deposit. 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.

1. Create the cardholder

bash
curl https://api.monerail.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",
    "id_document": "national_id"
  }'

type is team for your own staff and customer for your customers. Cardholders have no access to your dashboard.

2. Verify their identity

The issuer must verify every cardholder. Submit the verification with the document details and photos of the document (JPEG or PNG, base64, 4 MB at most each):

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 is required; address.postal_code is optional.

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.monerail.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.

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.