Build on MsjPay
The MsjPay API lets you connect an existing website or app — or build a brand new one — to the same digital services your customers use every day: data, airtime, bills, eSIM and more. Every request is authenticated against your account and settles against your MsjPay wallet balance in real time.
All available endpoints are versioned under /api/v1/ and speak JSON over HTTPS.
Authentication
Every request must include your API key as a Bearer token in the Authorization header. Requests without a valid, active key are rejected with 401 Unauthorized.
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
Keys never expire on their own and are not tied to any fixed prefix — treat yours like a password. If a key is compromised, regenerate it from your dashboard immediately.
API Credentials
Your API key is generated from your user dashboard after sign-up. It is unique per account, and every request made with it draws directly from that account's wallet balance.
Environments
Production
All requests to /api/v1/ made with a live key are live and move real funds — real airtime/data/etc. is delivered and your real wallet balance is debited.
Sandbox
Same base URL and endpoints as production — swap your live key for a sandbox key and every request is fully simulated: no real money moves, no real provider is ever contacted, and nothing here touches your live wallet or transaction history.
Using the sandbox
- Generate a sandbox key from your dashboard's Developer API page (login required) — same page as your live key, kept in a separate section.
- Send it in the same
Authorization: Bearerheader — which key you send determines the environment, not the URL or any extra parameter. - Every sandbox account starts with a simulated ₦1,000,000.00 balance, resettable any time from the dashboard.
- Purchases (airtime, data, cable TV, electricity, exam pins, betting, recharge cards, data cards, bulk SMS, airtime-to-cash, eSIM, international airtime, gift cards, virtual cards) always succeed instantly — unless the customer identifier you send (phone/meter/smartcard/account number) ends in the 4 digits
0000, which deterministically simulates a provider decline so you can test your failure-handling path too. - Sandbox transactions, balance, and virtual cards are entirely separate from your live account's — nothing you do in sandbox is visible on
/api/v1/balance,/api/v1/transactions, etc. when called with your live key, and vice versa. - No webhook, email, push, or WhatsApp notification is ever sent for sandbox activity.
Available APIs
Endpoints are grouped by what they do. Services shown here reflect what's actually enabled on this account — features not on your plan return 403.
Account & Balance
/api/v1/balance
/api/v1/dashboard
/api/v1/profile
/api/v1/update-profile
/api/v1/change-pin
/api/v1/change-password
/api/v1/kyc
/api/v1/account-upgrade
Catalog & Pricing
/api/v1/catalog
/api/v1/pricing
/api/v1/site-info
Purchases
/api/v1/airtime
/api/v1/data
/api/v1/cabletv
/api/v1/electricity
/api/v1/validate-meter
/api/v1/validate-cable
/api/v1/exam_pin
/api/v1/recharge-card
/api/v1/data_card
/api/v1/bulk_sms
/api/v1/betting
/api/v1/esim
/api/v1/international_airtime
/api/v1/a2c
/api/v1/smile
/api/v1/alpha
/api/v1/kirani
Money Movement & Cards
/api/v1/fund
/api/v1/virtual_accounts
/api/v1/bank_transfer
/api/v1/beneficiaries
/api/v1/virtual_cards
Gift Cards
/api/v1/giftcard_buy
/api/v1/giftcard_sell
Rewards & Support
/api/v1/cashback
/api/v1/promo
/api/v1/referrals
/api/v1/notifications
/api/v1/tickets
/api/v1/faqs
/api/v1/push_register
Transaction History
/api/v1/transactions
/api/v1/receipt
Request body
{
"network": "mtn",
"phone": "08031234567",
"plan_id": "145"
}
Response 200
{
"status": "success",
"data": {
"reference": "MSJ-9F2K1...",
"cashback_earned": 0,
"balance_before": 45250.00,
"balance_after": 44050.00
}
}
Transaction Status & Webhooks
Most purchases resolve immediately, returning status: "success" or status: "error" in the same response. Where an upstream provider is slow to confirm, you'll get back status: "pending" with a reference.
There is no outbound webhook subscription for partner integrations yet — poll GET /api/v1/transactions or GET /api/v1/receipt with the reference to resolve a pending transaction's final state. If real-time push callbacks are a requirement for your integration, raise it with the business team.
Error Codes
| Code | Meaning |
|---|---|
| 400 | Bad request — a required field is missing or invalid. |
| 401 | Missing, invalid, or suspended API key. |
| 403 | This feature is not enabled on your account/plan. |
| 405 | Wrong HTTP method for this endpoint (check GET vs. POST). |
| 429 | Too many requests — you have hit the rate limit. |
| 500 | Something went wrong on our side. Retry, then contact support if it persists. |
API Limits
Purchase-type endpoints (airtime, data, cable TV, electricity, and similar) are rate-limited to 30 requests per 60 seconds per account. Exceeding this returns 429 Too Many Requests — back off and retry after a short delay. Standard daily transaction limits that apply on the website also apply to API purchases on the same account.
Pricing
There is no separate API fee — you transact at your account's own pricing tier (regular, agent, or vendor), the same tiered pricing used on the website. Upgrade your account type to unlock agent/vendor rates. Wallet funding carries no additional fee, subject to applicable terms.
Integration Guide
- 1 Create an account and verify your details.
- 2 Grab your API key from your dashboard.
- 3 Call GET /api/v1/balance to confirm your key works.
- 4 Call GET /api/v1/catalog to fetch live, correctly-priced data plans for your tier.
- 5 Fund your wallet, then make a test purchase with a small amount.
- 6 Go live — point your production integration at the same base URL.
Developer Support
Stuck on an integration, or need a feature enabled for your account? The business team handles developer and partner requests directly.