Docs
ENFR
Dashboard
Get started

Testing

Test mode in depth: the sandboxes, the test helpers, the dashboard simulators and a full card scenario.

Everything here uses a test key (mr_test_…) and moves no real money. Read Test mode first for how test and live data are separated.

Mobile money in test mode

Collections and payouts go to the payment partner’s sandbox, not to real operators.

  • In most countries, the sandbox decides how a test collection proceeds (approval on the phone or a code) and which final status it reaches. Send numbers in a valid format for the country (for example 237670000999 for Cameroon). Format errors (400 phone_invalid) behave as in live mode.
  • In the countries listed under Test phone numbers, only the test numbers are accepted in test mode, and the last digit decides the outcome.
  • Write your code for every status: pending, requires_otp, processing, then succeeded, failed or expired. Do not assume a test collection always succeeds.
  • Collections that succeed credit your test balance. Use that balance to try payouts and settlements.

Test phone numbers

In Gabon, Chad, Congo, Central African Republic, Mali, Niger, Guinea and DR Congo, test mode accepts only these numbers, for collections and payouts. Any other number returns 400 test_phone_required, so a test can never reach a real wallet.

Country country, currency Succeeds Stays pending Fails
Gabon GA, XAF 24100000001 24100000002 24100000003
Chad TD, XAF 23500000001 23500000002 23500000003
Congo CG, XAF 24200000001 24200000002 24200000003
Central African Republic CF, XAF 23600000001 23600000002 23600000003
Mali ML, XOF 22300000001 22300000002 22300000003
Niger NE, XOF 22700000001 22700000002 22700000003
Guinea GN, GNF 224600000001 224600000002 224600000003
DR Congo CD, CDF 243120000011 243120000012 243120000013
  • Use any operator returned by List operators for the country. The final status arrives within a few seconds, by webhook and on the object.
  • A number ending in 2 never reaches a final status: use it to test your handling of long waits.
  • Orange Money in Guinea asks for a code: the collection is requires_otp. Send any 6-digit code with authorize. 000000, 111111, 222222, 333333 and 444444 make the collection fail; any other code lets the number decide.

Card test helpers

Two endpoints play the card issuer’s role. They need a test key and the Owner or Finance role.

Endpoint Body Effect
POST /v1/test/cardholders/{id}/verification result: approved or rejected; reason (optional, up to 200 characters) Decides a verification in in_review. With rejected, reason becomes verification.reason (default: Document unreadable (simulation)). Sends cardholder.kyc_updated.
POST /v1/test/cards/{id}/authorizations amount (US cents), merchant (optional, up to 40 characters), status: approved (default) or declined Approved: the payment and its fee are taken from the card and card.transaction is sent. Declined: nothing is charged and card.authorization_declined is sent, with reason Declined (simulation).

A full card scenario

  1. Top up the test cards balance. In the dashboard, in test mode, open Cards › Top up and click Simulate the deposit (Owner or Finance). It simulates a USDT deposit on TRON (TRC20).
  2. Create a 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"}'
  1. Submit the verification. Send JPEG or PNG images in base64: the API checks the format and the size (4 MB each). verification.status becomes in_review.
bash
curl https://api.monerail.com/v1/cardholders/5df6acd9-4bac-4e19-869c-fcde6b79f389/verification \
  -H "Authorization: Bearer $MONERAIL_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "id_number": "CM12345678",
    "birth_date": "1991-02-03",
    "place_of_birth": "Douala",
    "address": { "line1": "12 rue Joss", "city": "Douala" },
    "documents": { "front": "data:image/jpeg;base64,/9j/4AAQ…", "back": "data:image/jpeg;base64,/9j/4AAQ…" }
  }'
  1. Decide the verification. Approve it. To test your rejection path, send "result": "rejected" with a reason, read verification.reason, then submit again.
bash
curl https://api.monerail.com/v1/test/cardholders/5df6acd9-4bac-4e19-869c-fcde6b79f389/verification \
  -H "Authorization: Bearer $MONERAIL_KEY" \
  -H "Content-Type: application/json" \
  -d '{"result": "approved"}'
  1. Wait for cardholder.kyc_updated with verification.status verified, then issue a card. You get 201 with an active card, or 202 with a pending card followed by card.issued or card.issue_failed.
bash
curl https://api.monerail.com/v1/cards \
  -H "Authorization: Bearer $MONERAIL_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: test-card-awa-1" \
  -d '{"cardholder": "5df6acd9-4bac-4e19-869c-fcde6b79f389", "amount": 1000, "label": "Test card"}'
  1. Simulate payments. An approved payment, then a declined one. Check that your code handles card.transaction and card.authorization_declined, and that the declined one changed nothing on the card.
bash
curl https://api.monerail.com/v1/test/cards/ce2f0aea-7f87-4cbd-8383-03129d1253e0/authorizations \
  -H "Authorization: Bearer $MONERAIL_KEY" \
  -H "Content-Type: application/json" \
  -d '{"amount": 400, "merchant": "Notion"}'

curl https://api.monerail.com/v1/test/cards/ce2f0aea-7f87-4cbd-8383-03129d1253e0/authorizations \
  -H "Authorization: Bearer $MONERAIL_KEY" \
  -H "Content-Type: application/json" \
  -d '{"amount": 90000, "merchant": "Notion", "status": "declined"}'
  1. Manage the card. Fund it, withdraw from it, freeze and unfreeze it. Each action can answer 202: handle the webhook that follows.
  2. Terminate it. Terminate the card and check that card.terminated arrives and that its balance is back on the cards balance (Retrieve the balance).

Dashboard simulators

The dashboard, in test mode, has the same simulations behind buttons:

What Where Button (EN / FR)
Top up the cards balance (Owner or Finance) Cards › Top up Simulate the deposit / Simuler le dépôt
Decide a verification A cardholder in review Approve / Valider, Reject / Refuser
Pay with a card A card Simulate a payment / Simuler un achat

Test your webhooks

  • Create a test endpoint: test events only go to test endpoints, signed with their own secret.
  • To receive events on your machine, expose your local server through an HTTPS tunnel with a domain name.
  • To test your signature check without Monerail, send yourself an event signed the same way (the curl tab of Verify the signature).
  • Answer 2xx within 10 seconds, then try a failing answer and watch the retries. Use Redeliver an event to replay one.

Before going live

  • Every final status is handled: failed and expired collections, failed payouts and settlements, card.issue_failed, rejected verifications, declined card payments.
  • Every 202 is followed by a webhook, never by a second creation.
  • Your tests fail if they receive "livemode": true.

Then follow Going live.