Skip to content
On this page

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

  1. Your app
  2. Your server
  3. Payjar

Return the account

  1. Payjar
  2. Your server
  3. Your app

The customer transfers money in their bank app. Your app shows the account and waits. Payjar confirms the transfer.

Steps#

  1. The app asks your server to start a payment.
  2. Your server calls POST /supapay/v1/transaction/initialize with the secret key.
  3. Your server returns bank, charged_amount, reference, and expires_at to the app.
  4. The app shows the bank name, account name, account number, and the naira amount (charged_amount / 100).
  5. The customer pays that exact amount.
  6. 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.
  7. 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.

URL
https://app.supa.cash/supapay/v1/checkout/frame/a1b2c3d4e5f6789012345678abcdef01

Create a payment#

POST/supapay/v1/transaction/initializeSecret key

Request body#

FieldRequiredRules
emailYesA valid email. You can send customer_email instead.
amountYesNumber, at least 1. Kobo.
referenceNoString, up to 100 characters.
currencyNo3 letters. Use NGN.
nameNoString, up to 150 characters. customer_name also works.
phoneNoString, up to 30 characters. customer_phone also works.
callback_urlNoA valid URL, up to 255 characters. Stored on the payment.
metadataNoA 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 / 100 naira

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.

Flutter
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.