Sandbox

Two simulated networks that behave like real ones

The sandbox is not a stub that returns success. Each simulated network holds its own account balances, reserves funds when it authorizes, refuses what it cannot fund, and issues its own transaction references instead of echoing yours back.

That last detail matters more than it sounds: reconciliation only means something when the counterparty's report is produced independently. A simulator that repeated our own numbers back would make every reconciliation pass, including the broken ones.

Sandbox and live participants are kept strictly apart. A sandbox payment can never be routed to a real operator, and a live payment can never land on a simulator.

Driving outcomes

The last four digits of an address decide what happens, so any scenario is reproducible on demand rather than something you wait to encounter.

SuffixOutcomeBehaviour
...0001successAuthorizes, executes and credits the recipient.
...0002insufficient_fundsRefused at authorization. No funds are held.
...0003timeoutThe destination never answers. Any hold is released.
...0004declinedThe destination refuses the payment outright.
...0005invalid_recipientThe address does not resolve to an account.
...0006pendingAccepted for processing; resolves on a later status check.
...0007limit_exceededRejected against a limit on the destination side.
...0008unavailableThe rail is temporarily down.

A full round trip

Sending from a Tanzanian address to a Kenyan one, across two independent simulated networks and a currency boundary.

# 1. Who am I paying, and who can reach them
POST /network/v1/directory/resolve
{ "address": "+254700000001" }

# 2. Price it
POST /network/v1/quotes
{
  "sender":    { "type": "payment_address", "value": "+255700000001" },
  "recipient": { "type": "payment_address", "value": "+254700000001" },
  "amount":    { "value": 100000, "currency": "TZS" }
}
# -> quote_id, recipient_amount 500000 KES, expires_at

# 3. Commit to that price and execute
POST /network/v1/payments
Idempotency-Key: your-unique-key
{
  "sender":    { "type": "payment_address", "value": "+255700000001" },
  "recipient": { "type": "payment_address", "value": "+254700000001" },
  "quote_id":  "uln_qte_...",
  "auto_execute": true
}
# -> status destination_accepted, settlement obligation created,
#    balanced ledger pair written

# 4. Inspect everything that happened
GET /network/v1/payments/uln_tx_...
# -> full state history and the settlement obligations it produced

Then certify

When your integration handles all of the above, run the certification suite. It exercises the same scenarios plus the ones that catch a connector telling comfortable lies: authorizing what it cannot fund, reversing money it already delivered, over-refunding, or reporting a timeout as a success.

GET  /network/v1/certification/suite
POST /network/v1/certification/runs