Sandbox
The sandbox runs Futa with synthetic issuers: every payment, refund and webhook is real for the platform and moves no money. No phone receives a prompt and no issuer PIN or password is ever asked. Futa hosts one for the testers it invites, and you can also run it locally, from the Futa repositories.
The hosted sandbox
Section titled “The hosted sandbox”The hosted sandbox is public but invite-only, and everything in it is synthetic:
- Invited testers only. Futa creates each tester’s account, a synthetic
@futa.invalidaddress, and hands over a temporary password; there is no sign-up and no password reset. The first sign-in asks for a new password and sets up an authenticator app, whose code each sign-in then asks for. - Synthetic money only. Test keys, the six test payers and synthetic issuers: no payment, refund or payout moves real money, and live keys are refused.
- Synthetic KYB only. A test business’s KYB details and documents are made up for the test: never upload a real identity document, registration or proof of address.
- No real data. No real person’s name, phone number, e-mail address or document goes into a payment, a reference, a description or the portal.
| Service | Address |
|---|---|
| Merchant API, the contract’s first server | https://api.sandbox.futa-app.com, its /v1 routes |
| Hosted checkout | https://checkout.sandbox.futa-app.com |
| Developer console: test keys, webhooks and the request log | https://console.sandbox.futa-app.com |
| Merchant portal | https://portal.sandbox.futa-app.com |
| Webhook destination | The sandbox’s test receiver, http://127.0.0.1:18161/sandbox/webhooks inside Futa, never your server: it answers each delivery and keeps none, and the developer console lists them |
Webhooks never leave Futa, so your server receives none from the hosted sandbox. A test business starts with no
endpoint; in the developer console’s Webhooks page, add one on the test receiver,
http://127.0.0.1:18161/sandbox/webhooks, which the console names « Récepteur de test 2 du sandbox ».
It answers 204 to every delivery whose Futa-Signature is well formed and fresh, checks no signature against your
secret and keeps nothing, so « Journal de livraison » lists each delivery with its event, its
attempts and the status each received (webhooks in the hosted sandbox). The
console’s first receiver, http://127.0.0.1:18160/sandbox/webhooks, accepts only the deliveries of Futa’s own sandbox
merchant and answers yours 401; its third has no listener when hosted. GET /v1/payments/{id} gives each payment’s
authoritative state. Deliveries to your own servers wait for destination checks and egress controls.
Test keys
Section titled “Test keys”In the hosted sandbox, the developer console opens to the members of a test business: if your account belongs to
none, first create one in the merchant portal, « Créez votre commerce de test. », which makes
you its owner. Then create your server’s key in the developer console: « Clés API », then
« Créer une clé restreinte », with the permissions it needs, such as payments:read,
payments:write, webhooks:read and webhooks:manage. On your machine, the sandbox’s bootstrap key issues it
(run it locally). Either way, the secret starts with sk_test_ and is shown once.
Send keys as Authorization: Bearer sk_test_… from your server only, never from a payer’s browser or app. A key
never grants keys:manage. Live keys, sk_live_…, are refused: live mode waits for production, and an approved KYB
alone unlocks nothing.
Test payers
Section titled “Test payers”Six synthetic numbers choose a payment’s outcome, typed at checkout or sent as msisdn with method: "simulator"
for a direct payment. No other number is accepted.
| Number | Outcome |
|---|---|
+243810000001 |
Approved |
+243810000002 |
Declined |
+243810000003 |
Expiry, as the issuer states it |
+243810000004 |
Uncertain, then escalated to operations |
+243810000005 |
Approved after the approval window |
+243810000006 |
Issuer unavailable, then checked again |
Timers
Section titled “Timers”The payer has 120 seconds to approve, and an uncertain payment is checked for 15 minutes before operations take it on. The hosted sandbox keeps these timers; on your machine you can shorten them for a fast run.
Invoice reminders keep Kinshasa’s clock, at 09:00 on the days their batch’s policy names. A test key holding
invoices:write runs them at once for its own batches with POST /v1/sandbox/invoice-reminders/run, as of any instant
from now to 100 days ahead, SYNTHETIC; only the sandbox serves that route, and its messages reach no phone: see
the sandbox reminder run.
Client libraries
Section titled “Client libraries”Futa publishes no client library yet. The TypeScript clients of the merchant and payer APIs are generated beside
these docs from their contracts and checked against them, but neither is packaged or published. The opener of the
embedded checkout is served by the checkout itself, at /sdk/v1/checkout.js; the mobile
SDKs and the WooCommerce plugin are built from source and not yet distributed. Call
the API over HTTP, as the cURL, Node, PHP and Python samples in these pages do: the published contract,
openapi.json, describes every public operation, and the webhooks guide links the
event schemas.
Run it locally
Section titled “Run it locally”The same sandbox runs on your machine from the Futa repositories, its secrets in your own sandbox/.env. It is what
these pages’ local steps use; in the hosted sandbox you need none of them.
Start it
Section titled “Start it”Keep the Futa repositories side by side, install Java 21 and Docker Compose, and leave at least 8 GB of disk free.
From Futa-platform:
python3 scripts/sandbox.py initpython3 scripts/sandbox.py uppython3 scripts/sandbox.py buildpython3 scripts/sandbox.py startpython3 scripts/sandbox.py cdcinit writes private credentials to sandbox/.env and keeps them on later runs. Start the switch before cdc, so
its database migrations exist. stop stops the services; down stops the containers and keeps their data.
| Service | Address |
|---|---|
| Merchant API, the contract’s second server | http://127.0.0.1:18130 |
| Hosted checkout | http://127.0.0.1:18140 |
| Webhook destinations allowed | http://127.0.0.1:18160/sandbox/webhooks, the channels service’s sink, where the sandbox merchant’s endpoint starts; for your own receiver, http://127.0.0.1 on a port from 18161 to 18169 at its own path (at most 512 characters) with an optional query (at most 512) |
Its test keys
Section titled “Its test keys”MERCHANT_API_KEY in sandbox/.env is the sandbox’s bootstrap key: use it only to issue the keys your server uses.
POST /v1/keys with it creates a restricted key whose secret starts with sk_test_ and is shown once:
{ "label": "Order service", "permissions": ["payments:read", "payments:write", "webhooks:read", "webhooks:manage"]}Shorter timers
Section titled “Shorter timers”For a fast run, restart with shorter timers, then run the verification suites:
python3 scripts/sandbox.py stopAPPROVAL_SECONDS=5 UNCERTAINTY_SECONDS=12 python3 scripts/sandbox.py startpython3 scripts/verify-sandbox.py --restartpython3 scripts/verify-recovery.pystop and start without those variables bring the normal timers back. Futa-platform/sandbox/README.md covers
diagnostics.
What waits for production
Section titled “What waits for production”Real participants, live keys and live payouts, production deployment and its addresses are not part of the sandbox,
hosted or local. A payout in the sandbox reaches only the simulator’s synthetic participants, with synthetic money,
the synthetic zero fee and SYNTHETIC limits and thresholds: see payouts. docs/prd-traceability.md in
Futa-platform lists what remains.