MFS Sandbox Gateway — API reference
← Back to dashboardAuthentication
Every route below requires Authorization: Bearer <SANDBOX_RAIL_API_KEY>, except those marked “no auth”. Wrong or missing key → 401.
All routes share one rate limit: SANDBOX_RAIL_RATE_LIMIT requests (default 120) per rolling 60s window. Exceeding it → 429 with a Retry-After header.
Endpoints
/healthno auth200 if service + Supabase are reachable, non-200 otherwise.
/api/v1/referenceno authThe test-MSISDN table as JSON, including the dummy OTP.
/api/v1/mfs/chargesRequires an Idempotency-Key header. A repeated request with the same key returns the original result, never creates a second charge.
{ "msisdn": "+8801700000001", "amount": 29900, "currency": "BDT", "redirect_uri": "https://engine.example.com/mfs/callback" }→ 202:
{
"id": "ch_...", "msisdn": "...", "amount": 29900, "currency": "BDT",
"status": "pending_confirmation", "outcome": "PENDING",
"confirmation_id": "conf_...",
"confirmation_url": "http://localhost:3000/mfs-checkout/conf_...",
"created_at": "..."
}confirmation_url is a real, working hosted page — this is what a consumer (in practice, the Subscription Engine) passes straight through as its own checkout_url. Not a display string.
/api/v1/mfs/confirm/:confirmationIdRequires an OTP field. Dummy OTP for every test MSISDN: 123456.
{ "otp": "123456" }Any other value returns 400 with a generic incorrect-code error — never a hint that the value is fixed. On a correct OTP, resolves per the MSISDN's test-value behavior. Scoped to one confirmation attempt for onboarding — recurring debit means this is called once, at consent, not on every billing cycle.
/api/v1/mfs/charges/:idStatus: pending_confirmation | pending_retry | succeeded | failed | expired.
/api/v1/mfs/charges/:id/renewNot in the original engine contract — added as an extension, not yet coordinated with the engine team. See CHANGELOG.md.
Simulates a silent, engine-initiated recharge on an already-established mandate. No OTP. :id is the mandate's charge id (must already be succeeded).
Requires an Idempotency-Key header. A repeated request with the same key returns the original result rather than creating a second renewal.
{ "mandate_id": "ch_..." }mandate_id must equal the path :id. Returns 201 with a new charge row for that billing cycle, resolved immediately via the same per-MSISDN outcome table used at consent.
/api/v1/resetClears all MFS state (mfs_charges, events). merchant_redirect_allowlist is configuration, not transactional data, and is not cleared by reset.
Error shape
{ "error": { "code": "snake_case_code", "message": "..." } }Test MSISDNs
See the dashboard or GET /api/v1/reference for the full table of deterministic test MSISDNs, their outcomes, and decline codes.
Contract source: modules/02-api-routes.md. Route paths, field names, and outcome value meanings are load-bearing for the Subscription Engine — see INTEGRATION.md before changing any of them.