Skip to content

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 is public but invite-only, and everything in it is synthetic:

  • Invited testers only. Futa creates each tester’s account, a synthetic @futa.invalid address, 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.

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.

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

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.

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.

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.

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 init
python3 scripts/sandbox.py up
python3 scripts/sandbox.py build
python3 scripts/sandbox.py start
python3 scripts/sandbox.py cdc

init 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)

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"]
}

For a fast run, restart with shorter timers, then run the verification suites:

python3 scripts/sandbox.py stop
APPROVAL_SECONDS=5 UNCERTAINTY_SECONDS=12 python3 scripts/sandbox.py start
python3 scripts/verify-sandbox.py --restart
python3 scripts/verify-recovery.py

stop and start without those variables bring the normal timers back. Futa-platform/sandbox/README.md covers diagnostics.

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.