Guides
Mobile and API checkout
Your server creates the payment. Your app shows the account number and waits.
Use this when you build the payment screen yourself. iOS, Android, and Flutter apps should use this flow.
The secret key lives on your server. Register to get sk_test_, then follow Get started if this is your first payment.
Create the payment
- Your app
- Your server
- Payjar
Return the account
- Payjar
- Your server
- Your app
The customer transfers money in their bank app. Your app shows the account and waits. Payjar confirms the transfer.
Steps#
- The app asks your server to start a payment.
- Your server calls
POST /supapay/v1/transaction/initializewith the secret key. - Your server returns
bank,charged_amount,reference, andexpires_atto the app. - The app shows the bank name, account name, account number, and the naira amount (
charged_amount / 100). - The customer pays that exact amount.
- Your server learns it was paid from a webhook, or by calling
GET /supapay/v1/transaction/verify/{reference}every few seconds until the status changes. - Your server tells the app the payment succeeded. Then you deliver the order.
Stop polling when the status is success, expired, failed, or cancelled, or when expires_at has passed.
Hosted page#
If you do not want to draw the account screen, open checkout_url in the phone browser or in a web view. That page is the same payment window, full screen. Keep polling verify from your server so the app knows when to close the web view.
https://app.supa.cash/supapay/v1/checkout/frame/a1b2c3d4e5f6789012345678abcdef01Create a payment#
/supapay/v1/transaction/initializeSecret keyRequest body#
| Field | Required | Rules |
|---|---|---|
email | Yes | A valid email. You can send customer_email instead. |
amount | Yes | Number, at least 1. Kobo. |
reference | No | String, up to 100 characters. |
currency | No | 3 letters. Use NGN. |
name | No | String, up to 150 characters. customer_name also works. |
phone | No | String, up to 30 characters. customer_phone also works. |
callback_url | No | A valid URL, up to 255 characters. Stored on the payment. |
metadata | No | A JSON object. |
POST /supapay/v1/transaction/initialize HTTP/1.1
Host: app.supa.cash
Authorization: Bearer sk_test_your_secret_key
Accept: application/json
Content-Type: application/json
{
"email": "[email protected]",
"amount": 500000,
"reference": "order_1001",
"currency": "NGN",
"name": "Ada Lovelace",
"phone": "08031234567",
"metadata": {
"order_id": "1001",
"item": "Blue sneakers"
}
}200Response
{
"success": true,
"message": "Payment initialized",
"options": {
"notifications_count": 0,
"payment": {
"id": 1042,
"reference": "order_1001",
"access_code": "a1b2c3d4e5f6789012345678abcdef01",
"amount": 500000,
"fee": 5000,
"charged_amount": 500000,
"settled_amount": 495000,
"fee_paid_by": "merchant",
"currency": "NGN",
"status": "awaiting_transfer",
"environment": "test",
"customer_id": 88,
"customer_email": "[email protected]",
"customer_name": "Ada Lovelace",
"customer_phone": "08031234567",
"metadata": {
"order_id": "1001",
"item": "Blue sneakers"
},
"bank": {
"bank_name": "9JAPAY MFB",
"account_name": "SUPAPAY CHECKOUT",
"account_number": "0123456789",
"amount": 500000,
"currency": "NGN"
},
"paid_at": null,
"expires_at": "2026-11-03T17:07:00+01:00",
"created_at": "2026-11-03T16:37:00+01:00",
"checkout_url": "https://app.supa.cash/supapay/v1/checkout/frame/a1b2c3d4e5f6789012345678abcdef01",
"script_url": "https://app.supa.cash/js/payjar.js"
}
}
}Show the customer:
- Bank:
options.payment.bank.bank_name - Account name:
options.payment.bank.account_name - Account number:
options.payment.bank.account_number - Amount:
options.payment.charged_amount / 100naira
The same body works with a public key at POST /supapay/v1/checkout/initialize. The message is then Checkout initialized. Use the secret endpoint from your server. Use the public endpoint only from the popup.
Android, iOS, and Flutter#
Call Payjar from your server, or from a debug build that uses a test key. Parse options.payment.bank and show it on screen.
Swift: read payment["bank"] and payment["charged_amount"] for the screen.
final payment = await startPayment();
final bank = payment['bank'] as Map<String, dynamic>;
final naira = (payment['charged_amount'] as num) / 100;
// Show bank['bank_name'], bank['account_name'], bank['account_number'], naira.