Skip to main content
All sandbox API calls must use the base URL https://sandbox.nomba.com and your sandbox credentials. Mixing production credentials with the sandbox URL (or vice versa) will cause authentication errors. See Environment for details.

Before you start

Get your sandbox credentials

Log in to the Nomba dashboard, navigate to API Keys, and copy your test clientId, clientSecret, and accountId. These are generated alongside your production credentials and only work with https://sandbox.nomba.com.

Generate a sandbox access token

Exchange your test credentials for an access token. The sandbox token is short-lived — if you get 401 errors mid-test, generate a new one.
curl --request POST \
  --url https://sandbox.nomba.com/v1/auth/token/issue \
  --header 'Content-Type: application/json' \
  --header 'accountId: <your-sandbox-accountId>' \
  --data '{
    "grant_type": "client_credentials",
    "client_id": "<your-sandbox-clientId>",
    "client_secret": "<your-sandbox-clientSecret>"
  }'
Response
{
  "code": "00",
  "description": "Success",
  "data": {
    "access_token": "eyJhbGci...",
    "refresh_token": "01h4gdx2...",
    "expiresAt": "2026-01-01T12:00:00Z"
  }
}
All sandbox checkout endpoints are under the /sandbox/checkout/ path prefix, not /v1/checkout/. This is the key difference between sandbox and production.

Card payment flow

Step 1 — Create a checkout order

curl --request POST \
  --url https://sandbox.nomba.com/sandbox/checkout/order \
  --header 'Authorization: Bearer <sandbox-token>' \
  --header 'Content-Type: application/json' \
  --header 'accountId: <your-sandbox-accountId>' \
  --data '{
    "order": {
      "orderReference": "test-order-001",
      "amount": "400000.00",
      "currency": "NGN",
      "customerEmail": "[email protected]",
      "callbackUrl": "https://merchant.com/callback"
    }
  }'
Response
{
  "code": "00",
  "description": "Success",
  "data": {
    "checkoutLink": "https://checkout.nomba.com/sandbox/<encrypted-ref>",
    "orderReference": "test-order-001"
  }
}
If you omit orderReference, Nomba generates one in the format {accountId_prefix}_{timestamp} and returns it in the response. Use that value for all subsequent calls.
The sandbox checkout link has the format https://checkout.nomba.com/sandbox/{encryptedRef} — note the /sandbox/ segment, which distinguishes it from production links. Orders and their data are stored for 48 hours before expiring.

Step 2 — Submit card details

Submit the test card details to the checkout. The response depends entirely on which card number you use.

Test card numbers

Use one of these three cards to simulate different payment outcomes:
Card NumberNetworkOutcomeNext step
5434621074252808MastercardOTP required (T0 response)Submit OTP to complete
4000000000002503Visa3DS authentication required (S0 response)Handle 3DS redirect
5484497218317651MastercardDeclined — “do not honor”No further steps; payment failed
Card expiry, CVV, and PIN values are not validated in the sandbox — any values are accepted. Only the card number determines the outcome.

Step 3 - Submit Card Pin (if required)

Enter 1234 as the card pin
Declined card (5484497218317651) response:

Step 4 — Submit OTP

After submitting the successful Mastercard (5434621074252808), the customer is prompted for an OTP. Submit one of the following test values to control the outcome:
OTPOutcomeMessage
9999Approved”Approved by Financial Institution”
1234Timeout”Your payment has exceeded the time required to pay”
5464Invalid OTP”Invalid OTP”
Successful card (5434621074252808) response:
On a successful OTP submission, Nomba immediately fires a webhook to your configured callbackUrl with a payment_success event. See Webhook payload below.

Step 4 — Verify the transaction

Use the sandbox-specific fetch endpoint to confirm the transaction result:
curl --request GET \
  --url 'https://sandbox.nomba.com/sandbox/checkout/transaction?idType=orderReference&id=test-order-001' \
  --header 'Authorization: Bearer <sandbox-token>' \
  --header 'accountId: <your-sandbox-accountId>'
Response
{
  "code": "00",
  "description": "Success",
  "data": {
    "success": true,
    "message": "PAYMENT SUCCESSFUL",
    "order": {
      "orderId": "a1b2c3d4-e5f6-47a8-xxxx-xxxxxxxxxxxx",
      "orderReference": "test-order-001",
      "amount": "4000.00",
      "currency": "NGN",
      "customerEmail": "[email protected]"
    },
    "transactionDetails": {
      "transactionDate": "2026-03-31T10:00:00Z",
      "paymentReference": "WEB-ONLINE_C-abc123-550e4c3a-...",
      "statusCode": "PAYMENT SUCCESSFUL",
      "tokenizedCardPayment": "false"
    },
    "cardDetails": {
      "cardPan": "543462 **** **** 2808",
      "cardType": "MASTERCARD",
      "cardCurrency": "NGN"
    }
  }
}
You can query by idType=orderReference or idType=orderId. The id value changes accordingly.
The sandbox transaction fetch endpoint is GET /sandbox/checkout/transaction — not GET /v1/checkout/transaction, which is production-only. Transaction IDs in the sandbox follow the format WEB-ONLINE_C-{first6charsOfAccountId}-{UUID}.

Webhook payload

The sandbox fires webhooks synchronously immediately after a successful transaction — either after OTP approval (card) or confirm-transaction-receipt (bank transfer). Webhooks include HMAC-SHA256 signature headers for verification. Signature headers:
HeaderDescription
nomba-signatureHMAC-SHA256 signature of the payload
nomba-sig-valueRaw signature value
nomba-signature-algorithmAlways HmacSHA256
nomba-timestampISO 8601 UTC timestamp of the event
Sample card payment webhook payload:
{
  "event_type": "payment_success",
  "requestId": "550e8400-e29b-41d4-a716-446655440000",
  "data": {
    "merchant": {
      "userId": "<your-accountId>"
    },
    "transaction": {
      "fee": 0.28,
      "type": "online_checkout",
      "transactionId": "WEB-ONLINE_C-abc123-550e4c3a-0af4-4887-a089-xxxx",
      "merchantTxRef": "txref-1743379200",
      "transactionAmount": 4000.00,
      "time": "2026-03-31T10:00:00Z"
    },
    "order": {
      "amount": 4000.00,
      "orderId": "a1b2c3d4-e5f6-47a8-xxxx-xxxxxxxxxxxx",
      "accountId": "<your-accountId>",
      "customerEmail": "[email protected]",
      "orderReference": "test-order-001",
      "paymentMethod": "card_payment",
      "currency": "NGN"
    }
  }
}
To receive webhooks during local development, use a tunnel tool (e.g. ngrok) to expose your local server and set the public URL as your callbackUrl when creating the order.

Refund testing

Refunds are available in the sandbox. Use POST /sandbox/checkout/refund with the transactionId from the fetch transaction response.
curl --request POST \
  --url https://sandbox.nomba.com/sandbox/checkout/refund \
  --header 'Authorization: Bearer <sandbox-token>' \
  --header 'Content-Type: application/json' \
  --header 'accountId: <your-sandbox-accountId>' \
  --data '{
    "transactionId": "WEB-ONLINE_C-abc123-550e4c3a-...",
    "amount": 4000.00
  }'
To simulate a failed refund, use this specific transactionId:
WEB-ONLINE_C-97922-db88d4c3-a0af-4887-a089-b5d2e51b8f19
This always returns code: "400" regardless of the amount.

Simulating error states

What to testHow to trigger
Order not foundUse orderReference: "1234567890" — returns 404 on all endpoints
Card declinedUse card 5484497218317651
OTP timeoutSubmit OTP 1234
Invalid OTPSubmit OTP 5464
Failed refundUse transactionId WEB-ONLINE_C-97922-db88d4c3-a0af-4887-a089-b5d2e51b8f19
Failed tokenized card fetchUse customerEmail: "[email protected]"

Sandbox vs production — what’s different

FeatureSandboxProduction
Base path for checkout/sandbox/checkout//v1/checkout/
Create order
Card payment✅ Test cards only✅ Real cards
Bank transfer✅ Simulated✅ Real transfers
3DS authentication✅ Simulated✅ Real
Webhooks✅ Fires synchronously✅ Queued delivery
Fetch transactionGET /sandbox/checkout/transactionGET /v1/checkout/transaction
Refund
Cancel order
Tokenized cards✅ Hardcoded mock data✅ Real tokens
Real card validation❌ Card number determines outcome
Data persistenceRedis, expires after 48 hoursPermanent

Next steps

Create a Checkout Order

Full field reference and production code examples

Verify Transactions

Confirm payment status before delivering value

Webhooks

Set up and verify webhook signatures

Environment

Understand sandbox vs production base URLs