Mystack API
Embed revenue-splitting bank accounts into your product. Create managed accounts, give each a real NUBAN, define how money splits the moment it lands, and pay out — all over a simple REST API.
Base URL
https://mystack-api.onrender.comGet an API key
Open the Mystack app → Settings → Developer API → Enable developer API. You’ll get a msk_test_ key instantly to build with, and can mint a msk_live_ key once your BVN is verified (live money access is identity-gated, like every regulated processor).
Authentication
Every request needs your secret API key as a Bearer token. Keep it server-side — never ship it in a browser or mobile app.
curl https://mystack-api.onrender.com/v1/whoami \
-H "Authorization: Bearer msk_test_xxxxxxxxxxxx"Response:
{ "developerId": "…", "mode": "test", "scopes": ["accounts","balances","payouts","splits"] }Test vs. Live mode
- msk_test_… keys never move real money — payouts are simulated as successful so you can build the full flow safely.
- msk_live_… keys move real funds. Request a live key once your integration is ready.
Scopes
Each key carries scopes. A call to an endpoint without its scope returns 403.
Endpoints
| Method | Path | Scope | Description |
|---|---|---|---|
| POST | /v1/accounts | accounts | Create a managed business + buckets |
| GET | /v1/accounts/:id | accounts | Account overview |
| GET | /v1/accounts/:id/balances | balances | Bucket balances + NUBANs |
| POST | /v1/accounts/:id/splits | splits | Set split percentages |
| POST | /v1/accounts/:id/bank-accounts | accounts | Add a payout destination |
| POST | /v1/accounts/:id/payouts | payouts | Pay out from a bucket |
| GET | /v1/webhooks/deliveries | — | Your webhook delivery history |
| GET | /v1/keys | — | List your API keys |
Create an account
Each account gets real bank account numbers, so a valid BVN is required (the bank uses it to open the accounts). Percentages must total 100.
curl -X POST https://mystack-api.onrender.com/v1/accounts \
-H "Authorization: Bearer msk_test_xxxx" \
-H "Content-Type: application/json" \
-d '{
"fullName": "Ada Stores",
"email": "owner@adastores.com",
"bvn": "22212345678",
"pots": [
{ "name": "Restock", "percent": 60 },
{ "name": "Profit", "percent": 20 },
{ "name": "Tax", "percent": 20 }
]
}'Pay out (idempotent)
Send an Idempotency-Key header. Retrying with the same key returns the original payout instead of paying twice.
curl -X POST https://mystack-api.onrender.com/v1/accounts/{id}/payouts \
-H "Authorization: Bearer msk_test_xxxx" \
-H "Idempotency-Key: 7c1f-restock-2026-06-15" \
-H "Content-Type: application/json" \
-d '{
"potId": "…",
"amountKobo": 5000000,
"destinationBankAccountId": "…"
}'Amounts are always in kobo (integers). ₦50,000 = 5000000.
Webhooks
Set a webhook URL on your developer account and we POST events (e.g. payment.received) as they happen. Deliveries are retried with backoff; check history at /v1/webhooks/deliveries.
Verify the mystack-signature header — HMAC-SHA256 of the raw body with your webhook secret — and reject events whose at timestamp is stale:
import crypto from 'node:crypto';
function verify(rawBody, signature, secret) {
const expected = crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}Errors
Errors return a non-2xx status with { "error": "message" }. Common: 401 bad key · 403 missing scope · 400 validation.