Moja SwitchDocs Sandbox live

Guide

Sandbox testing

What the sandbox simulates, and how to drive each outcome deliberately.

The sandbox at https://api-sandbox.mojaswitch.com/v1 runs the same API, the same validation and the same durable payment path as production. It moves no real money, and it uses sk_sandbox_ keys only.

What differs from production

Sandbox Production
Keys sk_sandbox_…, from POST /signup or Moja Switch sk_live_…, issued at go-live
FX without fx (BYO-FX tenants) Priced from a sandbox rate on corridors that have one (CA-TZ) Refused: 422 fx_required
Collections (kind: collection) Available after product activation 403 product_not_available
Tenant payouts Simulated; the outcome is yours to choose Not offered yet
Outcome controls sandbox.collection_outcome, PUT /sandbox/payout-outcome, webhook redelivery None

A sandbox rate is a development convenience. Never use it to estimate production prices.

Collection outcomes

Set sandbox.collection_outcome when you create a collection (see Collections):

Value What happens
paid The payer pays the full amount. The collection is collected and becomes eligible for a tenant payout.
expired The payer never pays. The collection ends FAILED with failure.code: collection_not_completed.
amount_mismatch The payer pays a different amount. The collection is held at COLLECTING for review by Moja Switch operations.
reverse_after_collect The payer pays, then the payment is reversed. The collection is never paid out.

Payout outcomes

PUT /sandbox/payout-outcome sets the outcome of your next tenant payout. The value is captured when the payout is created.

bash
curl -sS -X PUT "$MOJA_BASE/sandbox/payout-outcome" \
  -H "Authorization: Bearer $MOJA_KEY" \
  -H 'Content-Type: application/json' \
  -d '{ "payout_outcome": "returned" }'
Value Payout status path
paid CREATED → SENT → PAID
delayed CREATED → SENT, staying SENT for longer before PAID
failed_before_send CREATED → FAILED. Its collections become eligible for a later payout.
returned CREATED → SENT → RETURNED. Its collections become eligible for a later payout.

Webhook redelivery

POST /sandbox/webhooks/{event_id}/redeliver sends an event you have already received again: same event_id, same body, fresh signature. Use it to prove your receiver deduplicates. It moves no money and changes no state.

A checklist before you ask to go live

  • Every money call persists its Idempotency-Key before the first attempt, and retries reuse it.
  • Your webhook receiver verifies signatures on raw bytes, rejects stale timestamps and deduplicates on event id.
  • A reconciliation job reads GET /payments/{payment_id} for anything not terminal in your expected window.
  • You branch on error.code and handle 201 FAILED payments.
  • Amounts use each currency's minor_unit_exponent from GET /corridors/{corridor_code}.
  • No API key or webhook secret appears in logs, URLs, client code or tickets.