Base URL
| Environment | URL |
|---|---|
| Sandbox | https://api.sandpay.dev |
sp_sk_test_... keys produce simulated transactions — no real money moves.
Authentication
Bearer token on every request:Versioning
The API is versioned in the URL: all public endpoints live under/v1/. Compatible changes (new fields, new endpoints) are deployed directly to /v1. Breaking changes trigger a new version (/v2) with an overlap period of at least 12 months.
Available endpoints
| Method | Endpoint | Description |
|---|---|---|
GET | /v1/health | Health probe (no auth required). |
POST | /v1/payments | Create a simulated payment. |
GET | /v1/payments/{id} | Retrieve a payment by its tx_id. |
GET | /v1/payments | List payments (cursor pagination). |
POST | /v1/payments/{id}/refund | Refund all or part of a collection. |
POST | /v1/disbursements | Free-form payout (merchant → msisdn). |
GET | /v1/meta | API version + capabilities (no auth). |
Raw operator response (raw)
Every Payment resource (POST, GET, or list) includes a raw field with the native operator shape (MTN MoMo, Orange Money, Moov, Airtel). In sandbox this shape is synthesised to match the real operator structure, with _simulated: true at the top level. See Scenarios for per-operator examples.
Rate limits
| Plan | Limit per minute |
|---|---|
| Trial / Free | 100 req/min |
| Pro | 1 000 req/min |
| Pro Lifetime | 1 000 req/min |
| Custom | on request |
429 rate_limited with a Retry-After header. See Errors for the retry strategy.
Quotas
Independently of rate limits, each organisation has a monthly simulation quota (reset on the 1st of the month). Exceeding it returns402 quota_exceeded. Upgrade your plan from /settings/billing to increase the quota.
OpenAPI spec
The raw spec is versioned in the repo:docs-site/openapi/sandpay.yaml. Mintlify uses it to automatically generate the detailed per-endpoint pages in this section’s sidebar.
See also
- Quickstart — first API call
- Errors — HTTP codes and retry strategy
- Node SDK — official TypeScript client