# Claude Code Source: https://developer.nomba.com/developer-resources/ai-tools/claude-code Set up Claude Code for Nomba API integration [Claude Code](https://claude.ai/code) is Anthropic's AI coding assistant that works directly in your terminal. You can load the Nomba developer docs as a skill so Claude has full context about the API when you're building. ## Prerequisites * Active Claude subscription (Pro, Max, or API access) * Node.js 18+ installed ## Setup ```bash theme={null} npm install -g @anthropic-ai/claude-code ``` In your project directory, run: ```bash theme={null} npx skills add https://developer.nomba.com ``` This gives Claude Code access to the full Nomba API reference, guides, and authentication docs. ```bash theme={null} claude ``` ## Example prompts Once the skill is loaded, you can ask Claude Code things like: ``` Generate a Node.js function that authenticates with the Nomba API using client credentials ``` ``` Write a bank transfer integration that handles PENDING_BILLING and REFUND statuses with proper webhook verification ``` ``` Show me how to do a bank account lookup before initiating a transfer in Python ``` ``` Help me set up error handling for Nomba API responses in my Express app ``` ## Using the Copy button Every page on the Nomba developer docs has a **Copy** button in the top right. Use it to: * **Open in Claude** — opens the current page in Claude.ai with one click * **Copy page** — copies the full page as Markdown, ready to paste into Claude This is useful when you want to ask specific questions about a single endpoint without loading the full skill. # Cursor Source: https://developer.nomba.com/developer-resources/ai-tools/cursor Use Nomba API docs as context in Cursor [Cursor](https://cursor.sh) is an AI-powered code editor built on VS Code. You can add the Nomba developer docs as a documentation source so Cursor's AI has context when generating or editing your integration code. ## Add Nomba docs to Cursor Press `Cmd/Ctrl + Shift + J` to open Cursor Settings, then navigate to **Features → Docs**. Click **+ Add new doc** and enter: ``` https://developer.nomba.com ``` Cursor will crawl and index the documentation. In the Cursor AI chat (`Cmd/Ctrl + L`), type `@Nomba` to reference the docs: ``` @Nomba How do I authenticate and make a bank transfer? ``` ## Tips * Use `@Nomba` in inline edits (`Cmd/Ctrl + K`) to generate endpoint-specific code directly in your editor * Combine with `@codebase` to get answers that are aware of both your existing code and the Nomba API * Use the **Copy page** button on any Nomba docs page to quickly paste relevant context into the Cursor chat ## Example prompts ``` @Nomba Generate a transfer service class in TypeScript that handles bank lookups and bank transfers with retry logic ``` ``` @Nomba What are the required headers for every Nomba API request? ``` ``` @Nomba Show me how to verify a webhook signature from Nomba ``` # AI Tools Overview Source: https://developer.nomba.com/developer-resources/ai-tools/overview Use AI coding assistants to integrate Nomba APIs faster AI coding assistants can help you build Nomba integrations faster by understanding the API docs, generating boilerplate code, and answering questions about specific endpoints. This section shows you how to connect your favorite AI coding tool to the Nomba developer documentation so it has full context when you're writing code. Use Claude Code with the Nomba skill for AI-assisted integration Add Nomba docs as a context source in Cursor Integrate Nomba docs into Windsurf for in-editor help ## Why use AI tools with Nomba docs? * **Faster integration** — Generate authentication flows, transfer requests, and webhook handlers without reading through every page * **Contextual answers** — Ask "how do I handle a PENDING\_BILLING status?" and get answers grounded in the actual API behavior * **Code in your language** — Get working examples in Node.js, Python, Go, or whatever your stack uses * **LLM-ready content** — Every page on this site can be copied as Markdown via the **Copy** button in the top right, making it easy to paste into any AI tool # Windsurf Source: https://developer.nomba.com/developer-resources/ai-tools/windsurf Use Nomba API docs as context in Windsurf [Windsurf](https://codeium.com/windsurf) is an AI-powered IDE by Codeium. You can point Windsurf's Cascade AI agent at the Nomba developer docs to get contextually accurate help when building your integration. ## Add Nomba docs to Windsurf Click the Cascade icon in the sidebar or press `Cmd/Ctrl + L`. In the Cascade chat, use the `@url` mention to pull in the Nomba docs: ``` @url https://developer.nomba.com/docs/getting-started/authentication ``` You can reference any specific page this way. Once the URL is loaded, ask your question and Cascade will answer using the page content as context. ## Using llms.txt Nomba's developer docs publish a machine-readable summary at: ``` https://developer.nomba.com/llms.txt ``` You can feed this directly to Windsurf (or any AI tool) for a structured overview of all available endpoints and pages: ``` @url https://developer.nomba.com/llms.txt What endpoints are available for transfers? ``` ## Tips * Use `@url` with the full docs URL for broad questions about the API * Use `@url` with a specific page URL (e.g., `/docs/products/transfers/transfer-to-banks`) for focused endpoint questions * Use the **Copy page** button on any Nomba docs page to paste the Markdown directly into Cascade ## Example prompts ``` @url https://developer.nomba.com/docs/products/transfers/transfer-to-banks How do I handle the PENDING_BILLING status and set up a requery loop? ``` ``` @url https://developer.nomba.com/llms.txt Generate a complete payment integration for accepting checkout payments and initiating bank transfers ``` # Overview Source: https://developer.nomba.com/developer-resources/overview Learn how to use our Plugins and SDKs for easier integration Nomba is building a developer ecosystem that makes it easier to integrate payments and business solutions. You’ll find clear API references, SDKs, and code samples to help you ship faster and with confidence. Whether your product runs online, offline, or a mix of both, our tools and community give you the support you need to build, test, and scale. ## Developer Resources Explore our collection of resources to help you integrate, learn, and connect with the Nomba developer community. Watch integration guides, tutorials, and developer resources. Connect with other developers, ask questions, and get support. Stay updated with the latest articles and API updates. # Definitions Source: https://developer.nomba.com/docs/api-basics/definitions Learn about some terminologies used in this documentation An entity engaged in commercial, industrial, or professional activities. A group of people working together toward common goals, often structured in a formal system A record of financial transactions and balances associated with a specific entity. The main account that may have subordinate accounts associated with it. An account linked to and subordinate to a primary or parent account. An online representation of a traditional bank account, often used for specific purposes like online transactions. Automatic processing and settlement of financial transactions without manual intervention. A device used for processing electronic payments, often connected to point-of-sale systems. A mechanism for real-time communication between systems, triggering events when certain actions occur. An exchange or interaction, typically referring to a financial activity. Financial transactions involving the addition (credit) or subtraction (debit) of funds. Security framework for managing digital identities and controlling access to resources. A credential used to access specific resources, often obtained after successful authentication. A device used for securely entering personal identification numbers (PINs) in electronic transactions. # Environment Source: https://developer.nomba.com/docs/api-basics/environment Learn about the production and sandbox environment The Nomba API operates within two distinct environments: the production environment (LIVE) and the sandbox environment. These environments serve different purposes and require specific credentials for interaction. ## Base URLs | Environment | Base URL | Purpose | | ----------- | --------------------------- | ----------------------------- | | Production | `https://api.nomba.com` | Live transactions, real money | | Sandbox | `https://sandbox.nomba.com` | Development and testing | The base URL and credentials must always be paired to match the same environment. Using sandbox credentials with `api.nomba.com`, or production credentials with `sandbox.nomba.com`, will result in authentication errors. ## Credentials When you create an API key on the Nomba dashboard, both production and sandbox credential pairs (`clientId` + `clientSecret`) are generated at the same time. They are separate — sandbox credentials only work with the sandbox base URL, and production credentials only work with the production base URL. ## Production When using the production environment, your interactions directly affect the live system. Real transactions are processed and real money moves. Always use `https://api.nomba.com` with your production `clientId` and `clientSecret`. ## Sandbox The sandbox is an isolated environment for development and testing. Transactions do not affect your live account or move real funds. Transactions conducted in the sandbox environment do not impact the production environment. To make a sandbox API call, use `https://sandbox.nomba.com` with your **test credentials** from the dashboard. Here is a sample sandbox authentication request: ```bash theme={null} curl --request POST \ --url https://sandbox.nomba.com/v1/auth/token/issue \ --header 'Content-Type: application/json' \ --header 'accountId: ' \ --data '{ "grant_type": "client_credentials", "client_id": "", "client_secret": "" }' ``` The sandbox returns simulated responses that mirror production behaviour. Data in the sandbox is isolated and does not appear on your live dashboard. See the [Testing](/docs/api-basics/testing) page for test card details and transaction scenarios. # Error Codes Source: https://developer.nomba.com/docs/api-basics/error-codes Understand Nomba API error codes and how to handle them The Nomba API uses a `code` field in the response body to indicate the outcome of every request. A successful response always returns `"code": "00"`. All other codes indicate an error or a specific state you need to handle. ## Response structure Every Nomba API response follows this structure: ```json theme={null} { "code": "00", "description": "Success", "data": { ... } } ``` On errors, `data` is typically `null` and `description` explains what went wrong: ```json theme={null} { "code": "02", "description": "amount can not be null", "data": null } ``` ## HTTP status codes | HTTP Status | Meaning | | ----------- | -------------------------------------------------------- | | `200` | Request processed (check `code` field for outcome) | | `400` | Bad request — invalid payload or missing required fields | | `401` | Unauthorized — missing or expired `access_token` | | `403` | Forbidden — insufficient permissions | | `404` | Resource not found | | `422` | Unprocessable entity — validation error | | `429` | Rate limit exceeded — slow down requests | | `500` | Internal server error — retry with backoff | A `200 HTTP` status does not always mean success. Always check the `code` field in the response body. ## API response codes ### General codes | Code | Description | Retryable | | ---- | -------------------------------------- | --------- | | `00` | Success | — | | `01` | Generic error | Yes | | `02` | Validation error (check `description`) | No | | `05` | Transaction not permitted | No | | `06` | Error — do not retry | No | ### Authentication codes | Code | Description | Action | | ----- | ------------------- | --------------------------------------------------------------------------------------------- | | `01` | Invalid credentials | Check `client_id` / `client_secret` | | `02` | Token expired | Call the [refresh token](/nomba-api-reference/authenticate/refresh-an-expired-token) endpoint | | `401` | Unauthorized | Re-authenticate and get a new `access_token` | ### Transfer-specific codes These appear in `data.status` on transfer responses: | Status | Description | Action | | ----------------- | ---------------------------------------- | ----------------------------------- | | `SUCCESS` | Transfer completed immediately | No action needed | | `PENDING_BILLING` | Transfer is being processed | Wait for webhook or poll for status | | `REFUND` | Transfer failed and account was refunded | Safe to retry | Nomba-to-Nomba wallet transfers (`/v2/transfers/wallet`) do not return a `sessionId`. Use the parent or sub-account requery endpoints instead. ## Handling errors in code ```javascript Node.js theme={null} async function makeTransfer(payload) { const response = await fetch('https://api.nomba.com/v2/transfers/bank', { method: 'POST', headers: { 'Authorization': `Bearer ${accessToken}`, 'Content-Type': 'application/json', 'accountId': accountId, }, body: JSON.stringify(payload), }); const result = await response.json(); if (result.code !== '00') { throw new Error(`Transfer failed: [${result.code}] ${result.description}`); } const { status } = result.data; if (status === 'PENDING_BILLING') { // Wait for webhook notification or poll with transaction ID return { pending: true, id: result.data.id }; } if (status === 'REFUND') { // Transaction failed — safe to retry throw new Error('Transfer was refunded. Safe to retry.'); } return result.data; } ``` ```python Python theme={null} import requests def make_transfer(payload, access_token, account_id): response = requests.post( 'https://api.nomba.com/v2/transfers/bank', headers={ 'Authorization': f'Bearer {access_token}', 'Content-Type': 'application/json', 'accountId': account_id, }, json=payload, ) result = response.json() if result['code'] != '00': raise Exception(f"Transfer failed: [{result['code']}] {result['description']}") status = result['data']['status'] if status == 'PENDING_BILLING': # Wait for webhook or poll with transaction ID return {'pending': True, 'id': result['data']['id']} if status == 'REFUND': raise Exception('Transfer was refunded. Safe to retry.') return result['data'] ``` ## Rate limit errors If you exceed the rate limit, you'll receive a `429` HTTP status. See the [Rate Limits](/docs/api-basics/rate_limit) page for limits per endpoint. ```json theme={null} { "code": "429", "description": "Too many requests. Please slow down.", "data": null } ``` **Transfer-specific:** There is a limit of **5 bank transfers to the same recipient per minute**. Space out repeat transfers or implement a queue. ## Need help? If you receive an error code not listed here or need help debugging, contact [docs@nomba.com](mailto:docs@nomba.com). # Pagination Source: https://developer.nomba.com/docs/api-basics/pagination Learn how pagination is implemented in the Nomba API ## Overview Pagination in the Nomba API is a crucial feature designed to efficiently manage and retrieve large sets of data. The system employs two main pagination mechanisms: limit and cursor pagination. This approach ensures flexibility and ease of use for the API caller while optimizing the retrieval of data. When retrieving a list of data using the Nomba API, you can define a `limit` indicating the amount of data you want the endpoint to provide at a time. After a successful response, the endpoint furnishes the requested data along with a `cursor`. This `cursor` is essential for navigating to the subsequent page, which contains the next batch of items. The limit has a maximum value of 50. You cannot get more than 50 items per time. ```bash Request (with limit = 2) theme={null} curl --request GET \ --url 'https://api.nomba.com/v1/accounts/terminals?limit=2' \ --header 'Authorization: Bearer ' \ --header 'accountId: ' ``` ```json Response (with cursor) theme={null} { "code": "00", "description": "Success", "data": { "results": [ { "terminalId": "201124LM", "serialNumber": "55555555", "accountId": "01a10aeb-d989-460a-bbde-9842f2b4320f", "parentAccountId": "", "merchantName": "trident and rees", "terminalLabel": "Testing", "createdAt": "2020-09-23T10:21:48.789Z", "updatedAt": "2023-09-04T15:23:55.173Z" } ], "cursor": "xchbaVFsjdsbaADddd" } } ``` Utilize the cursor acquired from the response to retrieve the next batch of data. Continue this process until the endpoint responds without a cursor, indicating that all the data has been fully retrieved. ```bash Request (with limit = 2 and cursor = "xchbaVFsjdsbaADddd") theme={null} curl --request GET \ --url 'https://api.nomba.com/v1/accounts/terminals?limit=2&cursor=xchbaVFsjdsbaADddd' \ --header 'Authorization: Bearer ' \ --header 'accountId: ' ``` ```json Response (last page - no cursor) theme={null} { "code": "00", "description": "Success", "data": { "results": [ { "terminalId": "201124LM", "serialNumber": "55555555", "accountId": "01a10aeb-d989-460a-bbde-9842f2b4320f", "parentAccountId": "", "merchantName": "trident and rees", "terminalLabel": "Testing", "createdAt": "2020-09-23T10:21:48.789Z", "updatedAt": "2023-09-04T15:23:55.173Z" } ], "cursor": "" } } ``` ## Limit Pagination The limit pagination mechanism allows the caller to specify the number of items or records they want to receive in each API response. This parameter, known as the "limit," enables fine-grained control over the amount of data returned. By setting an appropriate limit, the caller can manage the size of the response to align with their application's requirements, optimizing performance and reducing unnecessary data transfer. ## Cursor Pagination In conjunction with the limit pagination, the Nomba API utilizes cursor pagination to support seamless navigation through result sets. When making an API call with the specified limit, the response includes a cursor, a unique identifier pointing to the end of the current data page. The caller can use this cursor to request the next page of data. This approach is highly efficient for scenarios where the dataset is extensive, and retrieving all data in a single request is impractical. ## Conclusion Nomba API's pagination system offers a well-balanced solution that combines limit and cursor pagination mechanisms. This approach empowers API callers to manage the size of API responses efficiently, navigate through extensive datasets seamlessly, and determine the completeness of data retrieval with precision. It reflects a commitment to providing a robust and user-friendly API experience for developers integrating with the Nomba platform. # Ratelimit Source: https://developer.nomba.com/docs/api-basics/rate_limit Learn about Nomba's fixed window rate limit strategy ## Overview In the realm of efficient API management and optimization, the Nomba API employs a Fixed Window Rate Limit Strategy which is used to control the rate at which the system processes requests over a specific time period. This strategy serves as a robust mechanism to regulate and control the rate at which incoming requests are processed. ## Configuration Nomba API's ratelimiting is highly configurable to meet diverse requirements. The following configurations play a crucial role in defining the parameters of the rate limiting strategy. `TIME_WINDOW_IN_MS` The duration of the fixed window in milliseconds. `NO_OF_REQUEST_PER_MS` The maximum number of requests allowed within the fixed window for regular accounts. `NO_OF_POST_REQ` The maximum number of POST requests allowed within the fixed window for regular accounts. Most customers will fall under the REGULAR accounts category. `ELEVATED_ACCOUNTS` A list of account identifiers (e.g. accountIDs) considered elevated or privileged. These are accounts that require high rate limits due to the volumes they handle. Requests from these accounts have different rate limits compared to regular accounts. `NO_OF_POST_REQ_FOR_ELEVATED_ACCOUNTS` The maximum number of `POST` requests allowed within the fixed window for elevated accounts. `NO_OF_OTHER_REQ_FOR_ELEVATED_ACCOUNTS` The maximum number of `non-POST` requests allowed within the fixed window for elevated accounts. Feel free to contact us if you believe you meet the criteria for an ELEVATED account. We will conduct the required assessments, and if your eligibility is confirmed, we will include your account in the ELEVATED account list. `LOW_TRAFFIC_ACCOUNTS` A list of account identifiers considered as low-traffic accounts. `TIME_WINDOW_IN_MILLIS_FOR_LOW_TRAFFIC_ACCOUNTS` The fixed window duration for low-traffic accounts, in milliseconds. `NO_OF_POST_REQ_FOR_LOW_TRAFFIC_ACCOUNTS` The maximum number of `POST` requests allowed within the fixed window for low-traffic accounts. `NO_OF_OTHER_REQ_FOR_LOW_TRAFFIC_ACCOUNTS` The maximum number of `non-POST` requests allowed within the fixed window for low-traffic accounts. Please reach out to us if you believe you meet the criteria for a LOW\_TRAFFIC account. #### Default values | Property | Default | | ------------------------------------------------ | ------- | | `ELEVATED_ACCOUNTS` | `NA` | | `TIME_WINDOW_IN_MS` | `1000` | | `NO_OF_REQUEST_PER_MS` | `75 ` | | `LOW_TRAFFIC_ACCOUNTS` | `NA` | | `TIME_WINDOW_IN_MILLIS_FOR_LOW_TRAFFIC_ACCOUNTS` | `60000` | | `NO_OF_POST_REQ_FOR_ELEVATED_ACCOUNTS` | `40` | | `NO_OF_POST_REQ_FOR_LOW_TRAFFIC_ACCOUNTS` | `1` | | `NO_OF_OTHER_REQ_FOR_ELEVATED_ACCOUNTS` | `100` | | `NO_OF_OTHER_REQ_FOR_LOW_TRAFFIC_ACCOUNTS` | `25` | | `NO_OF_POST_REQ` | `15` | ## Benefits of Nomba API's Ratelimit #### Predictability and Fairness The Fixed Window Rate Limit Strategy offers predictability and fairness by providing a clear time-based structure for request processing. Users can anticipate and adapt to the defined rate limits, fostering an equitable usage environment. #### Efficient Resource Utilization By distributing requests over fixed windows, Nomba optimizes resource utilization. This prevents sudden spikes in traffic and ensures a steady, manageable flow of requests, leading to improved overall system efficiency. #### Protection Against Abuse The rate limiter acts as a shield against potential abuse or malicious activity by enforcing strict limits on the number of requests. This proactive approach safeguards the integrity and stability of the Nomba system. ## Response Headers We add the following properties to the headers to let you know when the rate limiter is approaching its limit on your requests `X-Rate-Limit-Limit` The number of allowed requests in the current period. `X-Rate-Limit-Remaining` The number of remaining requests in the current period. `X-Rate-Limit-Window` The specified rate limit window. # Testing Source: https://developer.nomba.com/docs/api-basics/testing Learn about the test cards we use for testing purposes To use the sandbox environment, you must generate a token using your **test credentials** (`clientId` and `clientSecret` from the dashboard) and the **sandbox base URL** (`https://sandbox.nomba.com`). Using the wrong URL or credentials will cause authentication failures. See the [Environment](/docs/api-basics/environment) page for details. Test cards are provided for use in the sandbox environment only. They cannot be used for real transactions and should not be used in production. ## Test Card Details Use the following card details when testing transactions in a sandbox or staging environment. ### Test cards | Card Number | Network | Outcome | | --------------------- | ---------- | --------------------------- | | `5434 6210 7425 2808` | Mastercard | OTP required → approved | | `4000 0000 0000 2503` | Visa | 3DS authentication required | | `5484 4972 1831 7651` | Mastercard | Declined — "do not honor" | For all cards: CVV and expiry are not validated — any 3-digit CVV and any future expiry date are accepted. The card number alone determines the outcome. ### PIN and OTP | Field | Value | Notes | | -------------- | ------ | -------------------------------------- | | Card PIN | `9999` | Used during card detail submission | | OTP — Approved | `9999` | Payment succeeds | | OTP — Timeout | `1234` | Payment fails with timeout message | | OTP — Invalid | `5464` | Payment fails with invalid OTP message | ### Transaction scenarios | Scenario | How to trigger | Expected outcome | | ----------------------- | --------------------------------------- | -------------------- | | Successful card payment | Card `5434 6210 7425 2808` + OTP `9999` | Transaction Approved | | Declined card | Card `5484 4972 1831 7651` | do not honor | | OTP timeout | OTP `1234` | Payment timed out | | Invalid OTP | OTP `5464` | Invalid OTP | | Insufficient funds | Amount greater than `500,000` | Transaction Declined | | Expired card | Expiry `12/20` | Transaction Declined | This test card should only be used in development or staging environments. Do not attempt real transactions with this card. ## Quick Sandbox Flow Follow these steps to run a checkout transaction end-to-end in the sandbox: 1. **Generate a sandbox token** — Use `https://sandbox.nomba.com/v1/auth/token/issue` with your test `clientId` and `clientSecret` 2. **Create a checkout order** — `POST https://sandbox.nomba.com/v1/checkout/order` with your sandbox token 3. **Open the checkout link** — Load the `checkoutLink` from the response in a browser 4. **Enter the test card** — Use the card number, CVV, and expiry date from the table above 5. **Enter the test OTP** — Use `9999` for a successful transaction 6. **Verify the transaction** — Use the `transactionRef` from the webhook or the `orderReference` you provided For a detailed walkthrough with request/response examples, see [Sandbox Testing](/docs/products/accept-payment/sandbox-testing). *** ### Fetch Sandbox Checkout Transactions You can retrieve the details of a specific transaction performed in the sandbox environment by sending a POST request with the transaction reference. This is useful for testing how your system handles different transaction outcomes (e.g., success, failure, pending). ```bash Request theme={null} curl --request POST \ --url https://sandbox.nomba.com/v1/transactions/accounts \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --header 'accountId: ' \ --data ' { "transactionRef": "WEB-ONLINE_C-SANDBOXDFC05-693cd007-cd1e-4ea6-xxxxxxxxxx" } ' ``` ```bash Response theme={null} { "code": "00", "description": "success", "data": { "results": [ { "id": "WEB-ONLINE_C-SANDBOXDFC05-693cd007-cd1e-4ea6-xxxxxxxxxx", "status": "PAYMENT_SUCCESSFUL", "amount": 4000, "fixedCharge": 123, "source": "web", "type": "online_checkout", "gatewayMessage": "payment successful", "customerBillerId": "543462 **** **** 2808", "timeCreated": "2023-09-08T19:26:34.657000Z", "timeUpdated": "2023-09-08T19:26:34.900000Z", "walletCurrency": "NGN", "userId": "dfc05ca1-4xx5-41dd-xx41-2d362dxxxxx3", "onlineCheckoutOrderId": "a1b2c3d4-e5f6-47a8-xxxx-xxxxxxxxxxxx", "onlineCheckoutOrderReference": "fd3002af-d48b-40a0-adba-xxxxxxxxxxxx", "onlineCheckoutTokenizedCardPayment": "false", "onlineCheckoutCardPan": "543462 **** **** 2808", "onlineCheckoutCurrency": "NGN", "onlineCheckoutCustomerEmail": "abcde@gmail.com", "onlineCheckoutAmount": "4000", "onlineCheckoutPaymentMethod": "card_payment", "onlineCheckoutTokenKey": "N/A", "onlineCheckoutCardType": "Mastercard", "currency": "NGN", "entryType": "CREDIT", "merchantTxRef": "c90d-4bxx-ad0f" } ], "cursor": "xchbaVFsjdsbaADddd" } } ``` # Debug webhooks Source: https://developer.nomba.com/docs/api-basics/troubleshoot-webhooks Learn how to re-push or debug a webhook ## Get Delivered Events Nomba offers a smooth method for tracking down or debugging earlier webhooks that were sent to your system. This is useful: * When you wish to verify whether a webhook was actually sent to your system. * When a problem occurs and you need to go back and confirm that you have received notifications of all payment events via webhooks. You can access webhook delivery logs in two ways: ### From the Nomba Dashboard This is the easiest way to debug webhooks. You can view webhook logs, inspect responses from your server, monitor delivery attempts and repush an event directly from the dashboard. * Navigate to **Developer** → **Webhook Repush**. ### Programmatically via API You can query the event logs endpoint to retrieve webhook delivery details for automated monitoring or debugging. By specifying parameters such as the event type or date range, you can fetch webhooks sent within a given timeframe and verify their delivery status. To do this, send a `POST`request to this\`\`; this will return a detailed list of events that have been sent to your system. See a sample request and response data below: ```bash Request theme={null} curl --request POST \ --url https://api.nomba.com/v1/webhooks/event-logs \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --header 'accountId: ' \ --data '{ "coreUserId": "6703XXXd1-158a-42XX-8f0b-XXXXXXXXX", "limit": 1, "eventType": "payment_success", "startDateTime": "2025-03-03", "endDateTime": "2025-03-12" }' ``` ```json Response theme={null} { "code": "200", "description": "Webhook events fetched successfully", "data": { "list": [ { "webhookUrl": "https://hip-namsj.preme.ngrok-free.app/api/v1/nomba-hook", "eventId": 257, "eventType": "payment_success", "hookRequestId": "ff99274c-58f7-4da4-b20f-XXXXXXXX", "responsePayload": "This URL has no default content configured. Change response in Webhook.site.", "responseHttpStatus": 200 }, ], "pageToken": "MjEyOTY3MThzM2NyM3Q=" } } ``` *** #### Repush After carefully reviewing the webhook via the event log API, you may want to do a single webhook repush or bulk repush; this will trigger a resend of the event back to your system. To do a repush, send a `POST` request to `v1/webhooks/re-push`, copy the `hooksRequestId` of the event to repush from the event log list, and pass it as the request payload. See a sample request and response data below: ```bash Request theme={null} curl --request POST \ --url https://api.nomba.com/v1/webhooks/re-push \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --header 'accountId: '\ --data '{ "hooksRequestId": "6703XXXd1-158a-42XX-8f0b-XXXXXXXXX" }' ``` ```json Success response theme={null} { "code": "200", "description": "Webhooks message re-pushed successfully" } ``` *** #### Bulk Repush Trigger a bulk webhook repush by passing an array of `hooksRequestIds` selected from your delivery logs. See a sample request and response data below: ```bash Request theme={null} curl --request POST \ --url https://api.nomba.com/v1/webhooks/bulk-re-push \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --header 'accountId: ' \ --data '{ "hooksRequestIds": [ "6703XXXd1-158a-42XX-8f0b-XXXXXXXXX", "703XXXd1-158a-42XX-8f0b-XXXXXXXXX", "8703XXXd1-158a-42XX-8f0b-XXXXXXXXX" ] }' ``` ```json Success response theme={null} { "code": "200", "description": "Webhook events bulk re-pushed successfully" } ``` *** #### Webhook Events You can also query all events that were sent to your system. See a sample request and response data below: ```bash Request theme={null} curl --request POST \ --url https://api.nomba.com/v1/webhooks/events \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --header 'accountId: '\ --data '{ "coreUserId": "6703XXXd1-158a-42XX-8f0b-XXXXXXXXX", "limit": 20 }' ``` ```json Success theme={null} { "code": "200", "description": "Webhook events fetched successfully", "data": { "list": [ { "webHookId": 782, "eventURL": "https://hip-guinea-supr.net", "description": "new", "eventType": "order_success", "enabled": true }, { "webHookId": 257, "eventURL": "https://hip-guinea-supr.net", "description": "new", "eventType": "payment_success", "enabled": true } ], "pageToken": "" } } ``` *** #### Webhook Replay Webhook replay allows you to **re-trigger previous webhook events** that were not successfully delivered or whose delivery outcome is uncertain within a timeframe. **Replay Eligibility** Only certain webhook log statuses are safe to replay. | Status | Replay Allowed | Meaning | | -------------- | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | | `INITIATED` | ✅ Yes (safe) | Webhook was logged to be delivered but delivery never completed | | `FAILED` | ✅ Yes (safe) | Delivery attempt failed. We did not get a 2xx response status from your server, we got a 5xx or 4xx when we previously pushed the event | | `INCONCLUSIVE` | ⚠️ Yes (with caution) | Delivery outcome is unknown; we didn't hear from your server when we previously pushed | | `PUSHED` | ‼️ Yes (only when needed) | Delivery outcome was successful. Only use when needed | You can choose from any of the event types below: `PAYMENT_SUCCESS`, `PAYMENT_FAILED`, `PAYOUT_SUCCESS`, `PAYOUT_FAILED`, `ORDER_SUCCESS`, `PAYMENT_REVERSAL`, and `PAYOUT_REFUND`. We strongly recommend implementing **idempotency handling** on your webhook endpoint to prevent duplicate processing, especially when replaying `INCONCLUSIVE` and `PUSHED` events. Sample request ```bash Request theme={null} curl --request POST \ --url https://api.nomba.com/v1/webhooks/replay \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --header 'accountId: '\ --data '{ "startDate": "2026-01-27T00:00:00Z", "endDate": "2026-01-28T23:59:59Z", "filter": { "statuses": ["INITIATED", "FAILED", "INCONCLUSIVE"], "eventTypes": ["PAYMENT_SUCCESS", "PAYMENT_FAILED", "PAYOUT_SUCCESS", "PAYOUT_FAILED", "ORDER_SUCCESS"] } }' ``` ```json Success theme={null} { "code": "200", "description": "Webhook messages re-played successfully" } ``` *** # Webhooks Source: https://developer.nomba.com/docs/api-basics/webhook Learn how to interact with Nomba webhooks ## Overview Webhooks allow your system to establish a communication channel with Nomba, usually via a public URL. When a payment event occurs on your account, Nomba will send a notification via this communication channel to notify you about this event. Nomba will send a `POST`request to the public webhook URL containing the details of the event and header strictly for verifying that the webhook event originated from the Nomba system. This image shows an established communication via webhook URL between your system and Nomba. It is good to note that, you must subscribe for the event type you want to get notified on. ## Set up webhook event To set up your webhooks, navigate to 'Developer' and click on 'Webhook Setup'. On this page you can set a live or test webhook URL and signature key. When you add a webhook URL, you can subscribe for the event you want to get notified on. Kindly ensure that your webhook URL is publicly available. ## Supported Events * **Payment Success** `payment_success` : Triggered when a payment is successfully credited to your Nomba account, e.g., Card transactions, Virtual account payments or PayByTransfer. * **Payout Success** `payout_success` : Triggered when a payment is successfully debited from your account, e.g., funds transfer, bill payment. * **Payment Failed** `payment_failed` : Triggered when a proposed payment attempt fails. * **Payment Reversal** `payment_reversal` : Triggered when a payment is reversed from your account back to the customer’s account. * **Payout Failed** `payout_failed` : Triggered when a payout transaction fails to process successfully and is not completed. * **Payout Refund** `payout_refund` : Triggered when a payout is refunded back to your Nomba account. ### Webhook headers Every webhook notification from Nomba includes special headers and a payload that matches the content of all supported event types. These headers will help you verify and process the request to ensure that it’s coming from Nomba, as a public URL can be accessed by anyone, so it’s to verify that all webhooks are from Nomba before giving value to your customers. A typical webhook payload will come with the following Nomba-specific headers: ```http theme={null} nomba-signature: 0zzATkAuEta5kpKVCExReupW/XglCk/re51P4jiDJ9c= nomba-sig-value: 0zzATkAuEta5kpKVCExReupW/XglCk/re51P4jiDJ9c= nomba-signature-algorithm: HmacSHA256 nomba-signature-version: 1.0.0 nomba-timestamp: 2023-03-31T05:56:47Z ``` | Header | Description | | --------------------------- | ----------------------------------------------------------------------------------------------------------------------- | | `nomba-signature` | A signature created using the signature key configured while creating the webhook on the Nomba dashboard | | `nomba-signature-algorithm` | The algorithm used to generate the signature. Value is always `HmacSHA256` | | `nomba-signature-version` | The version of the signature used. Value is `1.0.0` at the moment. It will keep updating as the signing process updates | | `nomba-timestamp` | An `RFC-3339` timestamp that identifies when the payload was sent. | * The RFC-3339 format specifies that dates should be represented using the year, month, and day, separated by hyphens, followed by a "T" to separate the date from the time, and then the time represented in hours, minutes, and seconds, separated by colons, with an optional fractional second component. Example; 2022-01-01T15:45:22Z * HTTP header names are case insensitive. Your client should convert all header names to a standardized lowercase or uppercase format before trying to determine the value of a header. Since webhooks are simply HTTP POST requests, there’s a chance that malicious actors could try to send fake webhook events to your server. To protect you from this, Nomba signs each webhook payload using the signature key you set when creating the webhook. The generated signature is included in the request headers, so your server can verify that the request truly came from Nomba and not an attacker. We recommend configuring the signature key while creating a webhook URL. While this configuration is optional, it is important to configure the keys and verify the signature of the payloads in order to prevent DDoS or Man-in-the-Middle attacks. ### Webhook payload The content of the payload is a JSON object and it gives details about the event that has been triggered. | Field | Type | Description | | ------------ | ------------- | -------------------------------------------------------- | | `event_type` | String | The event type that was triggered | | `request_id` | String (UUID) | A unique request identifier useful for tracking messages | | `data` | Object (JSON) | An object describing the details of the triggered event | ```json expandable Payment Success theme={null} { "event_type": "payment_success", "requestId": "49e11b44-909b-4f83-82b4-9a83aXXXXXX", "data": { "merchant": { "walletId": "693e907aad9ea59616XXXX", "walletBalance": 539.4, "userId": "613bb620-c8e5-45f6-9c00-XXXXXXXX" }, "terminal": {}, "transaction": { "aliasAccountNumber": "967913XXX", "fee": 0.6, "sessionId": "1000042602061021531516XXXXXX", "type": "vact_transfer", "transactionId": "API-VACT_TRA-613BB-eeae578a-cdd4-459c-8bd5-XXXXXX", "aliasAccountName": "Peter/Peter Enterprise", "responseCode": "", "originatingFrom": "api", "transactionAmount": 120, "narration": "Transfer from JOHN GRASS", "time": "2026-02-06T10:21:56Z", "aliasAccountReference": "122320250916PM", "aliasAccountType": "VIRTUAL" }, "customer": { "bankCode": "305", "senderName": "JOHN GRASS", "bankName": "Paycom (Opay)", "accountNumber": "81689XXX" } } } ``` ```json expandable Payout Success theme={null} { "event_type": "payout_success", "requestId": "76a7df87-4819-493c-90ee-XXXXXXX", "data": { "merchant": { "walletId": "693e907aad9ea59XXXXX", "walletBalance": 420, "userId": "613bb620-c8e5-45f6-9c00-XXXXXXXX" }, "terminal": {}, "transaction": { "fee": 20, "sessionId": "09FG260206111644XXXXXX", "type": "transfer", "transactionId": "API-TRANSFER-057A0-21e353c0-4168-4275-8355-XXXXXX", "responseCode": "", "originatingFrom": "api", "merchantTxRef": "20260212130PM", "transactionAmount": 50, "narration": "For API Test ", "time": "2026-02-06T10:16:30Z" }, "customer": { "bankCode": "011", "senderName": "Peter Okins", "recipientName": "JOHN GRASS", "bankName": "First Bank of Nigeria", "accountNumber": "31107XXXX" } } } ``` ```json expandable Payment Failed theme={null} { "event_type": "payment_failed", "requestId": "7b28d6d1-f91e-46c3-b312-89e9XXXXXXX", "data": { "merchant": { "userId": "usr_71kd89e9XXXXXXX" }, "terminal": { "terminalLabel": "IKEJA MALL", "terminalId": "3PLQXXX" }, "transaction": { "fee": 150, "type": "purchase", "transactionId": "POS-PURCHASE-71KD9-ae67-91fe-4b6a-a45b-689e9XXXXXXX", "responseCodeMessage": "Insufficient Funds", "rrn": "2510089e9XXXXXXX5", "cardIssuer": "MASTERCARD", "responseCode": "51", "originatingFrom": "pos", "terminalSerialNumber": "91230989e9XXXXXXX", "cardBank": "058", "transactionAmount": 25000, "time": "2025-10-06T17:38:45Z" }, "customer": { "productId": "058", "cardPan": "539983 **** **** 4297" } } } ``` ```json expandable Payout Refund theme={null} { "event_type": "payout_refund", "requestId": "062bbb0f-ecaa-481a-9ae5-12f73fXXXXXX", "data": { "merchant": { "walletId": "67khagklfXXXXXX", "walletBalance": 45000, "userId": "e5e6987d-32ea-4d04-8c49-13fXXXXXX" }, "terminal": {}, "transaction": { "fee": 7, "sessionId": "090645251008183142932001fXXXXXX", "type": "transfer", "transactionId": "API-TRANSFER-9772C-bf28b3d1-e18f-4ecd-a33c-4fXXXXXX", "responseCode": "", "originatingFrom": "api", "merchantTxRef": "5TDL0CL7CP", "transactionAmount": 45000, "narration": "From Bidemi O", "time": "2025-10-08T19:00:33Z" }, "customer": { "bankCode": "327", "senderName": "Test", "recipientName": "Test Technology Limited - MAKANJU FEMI", "bankName": "Paga", "accountNumber": "07937890XX" } } } ``` ## Webhook signature verification To make sure a webhook truly comes from Nomba and hasn’t been altered, each request we send includes a signature in the header. This signature is generated using your webhook payload and the secret key you set on your dashboard. On your end, verification is straightforward: 1. **Re-create the signature** : Use the same secret key and payload to generate a hash - HMAC signature. 2. **Compare signatures** : Match your generated hash with the nomba-signature header we sent. If they’re the same, you can trust the webhook. The tab below contains sample code demonstrating how to calculate the HMAC signature and compare it with the signature sent via the webhook. ```go expandable CalculateHMAC.go theme={null} package main import ( "crypto/hmac" "crypto/sha256" "encoding/base64" "encoding/json" "fmt" "log" "strings" ) // --- Struct Definitions for JSON Mapping --- type Payload struct { EventType string `json:"event_type"` RequestID string `json:"requestId"` Data Data `json:"data"` } type Data struct { Merchant Merchant `json:"merchant"` Terminal map[string]interface{} `json:"terminal"` Transaction Transaction `json:"transaction"` Customer Customer `json:"customer"` } type Merchant struct { WalletID string `json:"walletId"` WalletBalance float64 `json:"walletBalance"` UserID string `json:"userId"` } type Transaction struct { AliasAccountNumber string `json:"aliasAccountNumber"` Fee float64 `json:"fee"` SessionID string `json:"sessionId"` Type string `json:"type"` TransactionID string `json:"transactionId"` AliasAccountName string `json:"aliasAccountName"` ResponseCode string `json:"responseCode"` OriginatingFrom string `json:"originatingFrom"` TransactionAmount float64 `json:"transactionAmount"` Narration string `json:"narration"` Time string `json:"time"` AliasAccountReference string `json:"aliasAccountReference"` AliasAccountType string `json:"aliasAccountType"` } type Customer struct { BankCode string `json:"bankCode"` SenderName string `json:"senderName"` BankName string `json:"bankName"` AccountNumber string `json:"accountNumber"` } // --- Core Logic --- func main() { hooksCron2() } func hooksCron2() { payloadJSON := ` { "event_type": "payment_success", "requestId": "45f2dc2d-d559-4773-bba3-2d5ec17b2e20", "data": { "merchant": { "walletId": "6756ff80aafe04a795f18b38", "walletBalance": 6052, "userId": "b7b10e81-e57d-41d0-8fdc-f4e23a132bbf" }, "terminal": {}, "transaction": { "aliasAccountNumber": "5343270516", "fee": 5, "sessionId": "IFAP-TRANSFER-46501-e0339485-1a2f-4b43-9bd5-fec9649e5928", "type": "vact_transfer", "transactionId": "API-VACT_TRA-B7B10-0435b274-807a-4bc7-8abe-9dbb4548fd7a", "aliasAccountName": "ZAXBOX/EZENNA NWACHUKWU", "responseCode": "", "originatingFrom": "api", "transactionAmount": 10, "narration": "Habiblahi Hamzat Transfer 10.00 To ZAXBOX/EZENNA NWACHUKWU - Nomba", "time": "2025-09-29T10:51:44Z", "aliasAccountReference": "654f7c80bd4a510c90fb7f92", "aliasAccountType": "VIRTUAL" }, "customer": { "bankCode": "090645", "senderName": "Habiblahi Hamzat", "bankName": "Nombank", "accountNumber": "9617811496" } } }` signatureValue := "Kt9095hQxfgmVbx6iz7G2tPhHdbdXgLlyY/mf35sptw=" nombaTimeStamp := "2025-09-29T10:51:44Z" secret := "HkatexKDZg7CLWy96q5sfrVHSvtoz92B" mySig, err := generateSignature(payloadJSON, secret, nombaTimeStamp) if err != nil { log.Fatalf("Error generating signature: %v", err) } log.Printf("Generated signature [%s]", mySig) log.Printf("Expected signature [%s]", signatureValue) if strings.EqualFold(signatureValue, mySig) { log.Println(">>>>>>> Signatures match <<<<<<<<<") } else { log.Println("<<<<<<<<< Signatures did not match >>>>>>>>>") } } func generateSignature(payloadJSON, secret, timeStamp string) (string, error) { var payload Payload if err := json.Unmarshal([]byte(payloadJSON), &payload); err != nil { return "", fmt.Errorf("error parsing JSON payload: %w", err) } transaction := payload.Data.Transaction merchant := payload.Data.Merchant transactionResponseCode := transaction.ResponseCode if transactionResponseCode == "null" { transactionResponseCode = "" } // Construct the exact signature payload as in Java hashingPayload := fmt.Sprintf( "%s:%s:%s:%s:%s:%s:%s:%s:%s", payload.EventType, payload.RequestID, merchant.UserID, merchant.WalletID, transaction.TransactionID, transaction.Type, transaction.Time, transactionResponseCode, timeStamp, ) log.Printf("::: payload to hash --> [%s] :::", hashingPayload) // Generate HMAC SHA256 and encode Base64 h := hmac.New(sha256.New, []byte(secret)) h.Write([]byte(hashingPayload)) hash := h.Sum(nil) return base64.StdEncoding.EncodeToString(hash), nil } ``` ```python expandable CalculateHMAC.py theme={null} import json import hmac import hashlib import base64 import logging logging.basicConfig(level=logging.INFO, format="%(message)s") def hooks_cron2(): try: payload = """ { "event_type": "payment_success", "requestId": "45f2dc2d-d559-4773-bba3-2XXXXXXXXXX", "data": { "merchant": { "walletId": "6756ff80aafe04a795f18b3XXXXXXXXXX", "walletBalance": 6052, "userId": "b7b10e81-e57d-41d0-8XXXXXXXXXX" }, "terminal": {}, "transaction": { "aliasAccountNumber": "5343270516", "fee": 5, "sessionId": "IFAP-TRANSFER-46501-e0339485-1a2f-4b43-9bXXXXXXXXXX", "type": "vact_transfer", "transactionId": "API-VACT_TRA-B7B10-0435b274-807a-4bc7-8abe-9dbXXXXXXXXXX", "aliasAccountName": "SAMPLE/JOHN DOE", "responseCode": "", "originatingFrom": "api", "transactionAmount": 10, "narration": "John Doe Transfer 10.00 To ZAXBOX/EZENNA NWACHUKWU - Nomba", "time": "2025-09-29T10:51:44Z", "aliasAccountReference": "654f7c80bd4**10c90fb7f92", "aliasAccountType": "VIRTUAL" }, "customer": { "bankCode": "090645", "senderName": "John Doe", "bankName": "Nombank", "accountNumber": "0000000000" } } } """ signature_value = "Kt9095hQxfgmVbx6iz7G2tPhHdbdXgLlyY/mf35sptw=" nomba_timestamp = "2025-09-29T10:51:44Z" secret = "sampleScret" my_sig = generate_signature(payload, secret, nomba_timestamp) logging.info(f"Generated signature [{my_sig}]") logging.info(f"Expected signature [{signature_value}]") if signature_value.lower() == my_sig.lower(): logging.info(">>>>>>> Signatures match <<<<<<<<<") else: logging.info("<<<<<<<<< Signatures did not match >>>>>>>>>") except Exception as ex: logging.error(f"Error occurred while generating signature: {ex}") def generate_signature(payload: str, secret: str, timestamp: str) -> str: request_payload = json.loads(payload) data = request_payload.get("data", {}) merchant = data.get("merchant", {}) transaction = data.get("transaction", {}) event_type = request_payload.get("event_type", "") request_id = request_payload.get("requestId", "") user_id = merchant.get("userId", "") wallet_id = merchant.get("walletId", "") transaction_id = transaction.get("transactionId", "") transaction_type = transaction.get("type", "") transaction_time = transaction.get("time", "") transaction_response_code = transaction.get("responseCode", "") if transaction_response_code == "null": transaction_response_code = "" # Construct the same hashing payload as in Java/Go hashing_payload = f"{event_type}:{request_id}:{user_id}:{wallet_id}:{transaction_id}:{transaction_type}:{transaction_time}:{transaction_response_code}:{timestamp}" logging.info(f"::: payload to hash --> [{hashing_payload}] :::") # Compute HMAC-SHA256 and Base64 encode it digest = hmac.new(secret.encode(), hashing_payload.encode(), hashlib.sha256).digest() signature = base64.b64encode(digest).decode() return signature if __name__ == "__main__": hooks_cron2() ``` ```javascript expandable CalculateHMAC.js theme={null} import crypto from "crypto"; async function hooksCron2() { try { const payload = ` { "event_type": "payment_success", "requestId": "45f2dc2d-d559-4773-bba3-2XXXXXXXXXX", "data": { "merchant": { "walletId": "6756ff80aafe04XXXXXXXXXX", "walletBalance": 6052, "userId": "b7b10e81-**-**-**-f4e23a132bbf" }, "terminal": {}, "transaction": { "aliasAccountNumber": "5343270516", "fee": 5, "sessionId": "IFAP-TRANSFER-46501-e0339485-1a2f-4b43-9bd5-XXXXXXXXXX", "type": "vact_transfer", "transactionId": "API-VACT_TRA-B7B10-0435b274-807a-4bc7-8abe-9XXXXXXXXXX", "aliasAccountName": "SAMPLE/JOHN DOE", "responseCode": "", "originatingFrom": "api", "transactionAmount": 10, "narration": "John Does Transfer 10.00 To SAMPLE/JOHN DOE - Nomba", "time": "2025-09-29T10:51:44Z", "aliasAccountReference": "sampleAccountReference", "aliasAccountType": "VIRTUAL" }, "customer": { "bankCode": "090645", "senderName": "John Does", "bankName": "Nombank", "accountNumber": "0000000000" } } }`; const signatureValue = "Kt9095hQxfgmVbx6iz7G2tPhHdbdXgLlyY/mf35sptw="; const nombaTimeStamp = "2025-09-29T10:51:44Z"; const secret = "sampleSecret"; const mySig = generateSignature(payload, secret, nombaTimeStamp); console.log(`Generated signature [${mySig}]`); console.log(`Expected signature [${signatureValue}]`); if (signatureValue.toLowerCase() === mySig.toLowerCase()) { console.log(">>>>>>> Signatures match <<<<<<<<<<<"); } else { console.log("<<<<<<<<< Signatures did not match >>>>>>>>>"); } } catch (ex) { console.error("Error occurred while generating signature:", ex.message); } } function generateSignature(payload, secret, timeStamp) { const requestPayload = JSON.parse(payload); const data = requestPayload.data || {}; const merchant = data.merchant || {}; const transaction = data.transaction || {}; const eventType = requestPayload.event_type || ""; const requestId = requestPayload.requestId || ""; const userId = merchant.userId || ""; const walletId = merchant.walletId || ""; const transactionId = transaction.transactionId || ""; const transactionType = transaction.type || ""; const transactionTime = transaction.time || ""; let transactionResponseCode = transaction.responseCode || ""; if (transactionResponseCode === "null") { transactionResponseCode = ""; } const hashingPayload = `${eventType}:${requestId}:${userId}:${walletId}:${transactionId}:${transactionType}:${transactionTime}:${transactionResponseCode}:${timeStamp}`; console.log(`::: payload to hash --> [${hashingPayload}] :::`); const hmac = crypto.createHmac("sha256", secret); hmac.update(hashingPayload); const hash = hmac.digest("base64"); return hash; } // Run hooksCron2(); ``` ```java expandable CalculateHMAC.java theme={null} import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.Data; import lombok.extern.slf4j.Slf4j; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.util.Base64; @Slf4j public class NombaHooksRefactored { private static final ObjectMapper objectMapper = new ObjectMapper(); public static void main(String[] args) throws Exception { new NombaHooksRefactored().hooksCron2(); } public void hooksCron2() { try { String payload = """ { "event_type": "payment_success", "requestId": "45f2dc2d-d559-4773-bba3-2XXXXXXXXXX", "data": { "merchant": { "walletId": "6756ff80aafe04aXXXXXXXXXX", "walletBalance": 6052, "userId": "b7b10e81-**-**-**-f4e23a132bbf" }, "terminal": {}, "transaction": { "aliasAccountNumber": "5343270516", "fee": 5, "sessionId": "IFAP-TRANSFER-46501-***-1a2f-4b43-9bd5-fec964XXXXXXXXXX28", "type": "vact_transfer", "transactionId": "API-VACT_TRA-B7B10-0435b274-807a-4bc7-8XXXXXXXXXX", "aliasAccountName": "SAMPLE/JOHN DOE", "responseCode": "", "originatingFrom": "api", "transactionAmount": 10, "narration": "John Doe Transfer 10.00 To ZAXBOX/EZENNA NWACHUKWU - Nomba", "time": "2025-09-29T10:51:44Z", "aliasAccountReference": "654f7c80bd4***0c90fb7f92", "aliasAccountType": "VIRTUAL" }, "customer": { "bankCode": "090645", "senderName": "John Doe", "bankName": "Nombank", "accountNumber": "0000000000" } } } """; String signatureValue = "Kt9095hQxfgmVbx6iz7G2tPhHdbdXgLlyY/mf35sptw="; String nombaTimeStamp = "2025-09-29T10:51:44Z"; String secret = "HkatexKDZg7CLWy96q5sfrVHSvtXXXXXXXXXXB"; HookPayload hookPayload = objectMapper.readValue(payload, HookPayload.class); String mySig = generateSignature(hookPayload, secret, nombaTimeStamp); log.info("Generated signature [{}]", mySig); log.info("Expected signature [{}]", signatureValue); if (signatureValue.equalsIgnoreCase(mySig)) { log.info(">>>>>>> Signatures match <<<<<<<<<"); } else { log.info("<<<<<<<<< Signatures did not match >>>>>>>>>"); } } catch (Exception ex) { log.error("Error occurred while generating signature. Error message [{}]", ex.getMessage(), ex); } } public String generateSignature(HookPayload payload, String secret, String timeStamp) throws Exception { var data = payload.getData(); var merchant = data.getMerchant(); var transaction = data.getTransaction(); String eventType = safe(payload.getEventType()); String requestId = safe(payload.getRequestId()); String userId = safe(merchant.getUserId()); String walletId = safe(merchant.getWalletId()); String transactionId = safe(transaction.getTransactionId()); String transactionType = safe(transaction.getType()); String transactionTime = safe(transaction.getTime()); String transactionResponseCode = safe(transaction.getResponseCode()); if ("null".equalsIgnoreCase(transactionResponseCode)) { transactionResponseCode = ""; } String hashingPayload = String.format( "%s:%s:%s:%s:%s:%s:%s:%s:%s", eventType, requestId, userId, walletId, transactionId, transactionType, transactionTime, transactionResponseCode, timeStamp ); log.info("::: payload to hash --> [{}] :::", hashingPayload); Mac sha256HMAC = Mac.getInstance("HmacSHA256"); SecretKeySpec secretKey = new SecretKeySpec(secret.getBytes(), "HmacSHA256"); sha256HMAC.init(secretKey); byte[] hash = sha256HMAC.doFinal(hashingPayload.getBytes()); return Base64.getEncoder().encodeToString(hash); } private String safe(String value) { return value == null ? "" : value; } } // POJO Models (Strongly Typed Payload Classes) import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; @Data public class HookPayload { @JsonProperty("event_type") private String eventType; @JsonProperty("requestId") private String requestId; @JsonProperty("data") private HookData data; } @Data class HookData { private Merchant merchant; private Transaction transaction; private Customer customer; private Object terminal; } @Data class Merchant { private String walletId; private Double walletBalance; private String userId; } @Data class Transaction { private String transactionId; private String type; private String time; private String responseCode; } @Data class Customer { private String bankCode; private String senderName; private String bankName; private String accountNumber; } ``` ```csharp expandable CalculateHMAC.cs theme={null} using System; using System.Text; using System.Text.Json; using System.Text.Json.Serialization; using System.Security.Cryptography; public class HooksCron { public static void Main() { try { var payload = @" { ""event_type"": ""payment_success"", ""requestId"": ""45f2dc2d-d559-4773-bba3-2XXXXXXXXXX"", ""data"": { ""merchant"": { ""walletId"": ""6756ff80aafe04a7XXXXXXXXXX"", ""walletBalance"": 6052, ""userId"": ""b7b10e81-e57d-41d0-8fdc-f4XXXXXXXXXX"" }, ""terminal"": {}, ""transaction"": { ""aliasAccountNumber"": ""5343270516"", ""fee"": 5, ""sessionId"": ""IFAP-TRANSFER-46501-e0339485-1a2f-4b43-9bd5-feXXXXXXXXXX28"", ""type"": ""vact_transfer"", ""transactionId"": ""API-VACT_TRA-B7B10-0435b274-807a-4bc7-8abe-XXXXXXXXXXd7a"", ""aliasAccountName"": ""ZAXBOX/EZENNA NWACHUKWU"", ""responseCode"": """", ""originatingFrom"": ""api"", ""transactionAmount"": 10, ""narration"": ""Habiblahi Hamzat Transfer 10.00 To ZAXBOX/EZENNA NWACHUKWU - Nomba"", ""time"": ""2025-09-29T10:51:44Z"", ""aliasAccountReference"": ""654XXXXXXXXXX92"", ""aliasAccountType"": ""VIRTUAL"" }, ""customer"": { ""bankCode"": ""090645"", ""senderName"": ""Habiblahi Hamzat"", ""bankName"": ""Nombank"", ""accountNumber"": ""9617811496"" } } }"; var signatureValue = "Kt9095hQxfgmVbx6iz7G2tPhHdbdXgLlyY/mf35sptw="; var nombaTimestamp = "2025-09-29T10:51:44Z"; var secret = "HkatexKDZg7CLWy96q5sfrVH92B"; // Deserialize payload into object model var requestPayload = JsonSerializer.Deserialize(payload); var mySig = GenerateSignature(requestPayload, secret, nombaTimestamp); Console.WriteLine($"Generated signature [{mySig}]"); Console.WriteLine($"Expected signature [{signatureValue}]"); if (string.Equals(signatureValue, mySig, StringComparison.OrdinalIgnoreCase)) { Console.WriteLine(">>>>>>> Signatures match <<<<<<<<<"); } else { Console.WriteLine("<<<<<<<<< Signatures did not match >>>>>>>>>"); } } catch (Exception ex) { Console.WriteLine($"Error occurred while generating signature. Error: {ex.Message}"); } } public static string GenerateSignature(HookPayload payload, string secret, string timestamp) { var data = payload.Data; var merchant = data.Merchant; var transaction = data.Transaction; string eventType = payload.EventType ?? ""; string requestId = payload.RequestId ?? ""; string userId = merchant?.UserId ?? ""; string walletId = merchant?.WalletId ?? ""; string transactionId = transaction?.TransactionId ?? ""; string transactionType = transaction?.Type ?? ""; string transactionTime = transaction?.Time ?? ""; string transactionResponseCode = transaction?.ResponseCode ?? ""; if (transactionResponseCode == "null") { transactionResponseCode = ""; } var hashingPayload = $"{eventType}:{requestId}:{userId}:{walletId}:{transactionId}:{transactionType}:{transactionTime}:{transactionResponseCode}:{timestamp}"; Console.WriteLine($"::: payload to hash --> [{hashingPayload}] :::"); using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret)); var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(hashingPayload)); var signature = Convert.ToBase64String(hash); return signature; } } #region Models public class HookPayload { [JsonPropertyName("event_type")] public string? EventType { get; set; } [JsonPropertyName("requestId")] public string? RequestId { get; set; } [JsonPropertyName("data")] public HookData Data { get; set; } = new(); } public class HookData { [JsonPropertyName("merchant")] public Merchant? Merchant { get; set; } [JsonPropertyName("transaction")] public Transaction? Transaction { get; set; } [JsonPropertyName("customer")] public Customer? Customer { get; set; } [JsonPropertyName("terminal")] public object? Terminal { get; set; } } public class Merchant { [JsonPropertyName("walletId")] public string? WalletId { get; set; } [JsonPropertyName("walletBalance")] public decimal? WalletBalance { get; set; } [JsonPropertyName("userId")] public string? UserId { get; set; } } public class Transaction { [JsonPropertyName("transactionId")] public string? TransactionId { get; set; } [JsonPropertyName("type")] public string? Type { get; set; } [JsonPropertyName("time")] public string? Time { get; set; } [JsonPropertyName("responseCode")] public string? ResponseCode { get; set; } } public class Customer { [JsonPropertyName("bankCode")] public string? BankCode { get; set; } [JsonPropertyName("senderName")] public string? SenderName { get; set; } [JsonPropertyName("bankName")] public string? BankName { get; set; } [JsonPropertyName("accountNumber")] public string? AccountNumber { get; set; } } #endregion ``` This code samples is supported in php ```php expandable CalculateHMAC.php theme={null} >>>>>> Signatures match <<<<<<<<<\n"; } else { echo "<<<<<<<<< Signatures did not match >>>>>>>>>\n"; } } catch (Exception $ex) { echo "Error occurred while generating signature: {$ex->getMessage()}\n"; } } function generateSignature($payload, $secret, $timeStamp) { $requestPayload = json_decode($payload, true); $data = $requestPayload['data'] ?? []; $merchant = $data['merchant'] ?? []; $transaction = $data['transaction'] ?? []; $eventType = $requestPayload['event_type'] ?? ''; $requestId = $requestPayload['requestId'] ?? ''; $userId = $merchant['userId'] ?? ''; $walletId = $merchant['walletId'] ?? ''; $transactionId = $transaction['transactionId'] ?? ''; $transactionType = $transaction['type'] ?? ''; $transactionTime = $transaction['time'] ?? ''; $transactionResponseCode = $transaction['responseCode'] ?? ''; if ($transactionResponseCode === "null") { $transactionResponseCode = ''; } // Construct payload string same as Java's String.format(SIG_FORMAT, data, timeStamp) $hashingPayload = sprintf( "%s:%s:%s:%s:%s:%s:%s:%s:%s", $eventType, $requestId, $userId, $walletId, $transactionId, $transactionType, $transactionTime, $transactionResponseCode, $timeStamp ); echo "::: payload to hash --> [{$hashingPayload}] :::\n"; // Generate HMAC SHA256 and encode in Base64 $hash = hash_hmac('sha256', $hashingPayload, $secret, true); return base64_encode($hash); } // Run hooksCron2(); ``` ## Idempotency in Nomba Nomba allows you to pass an idempotency key using the `X-Idempotent-key` header. This helps prevent duplicate requests when the first request fails due to issues like network interruptions. Although our system already handles idempotency internally, we recommend that you include an idempotency key when calling endpoints such as Bank Transfer. For example, if a bank transfer request succeeds but the confirmation is lost, resending the same request with the same idempotency key ensures that: * Only the first request is processed. * A duplicate request will either return the original response if identical or throw an error if different. This keeps your transactions safe and predictable by avoiding accidental duplicate transfers. Always use a unique idempotency key for each request. This is best practice to ensure consistent behavior. The following examples show how to generate a unique keys in popular programming languages. ```go unique_key.go theme={null} package main import ( "fmt" "github.com/google/uuid" ) func main() { idempotentKey := uuid.New().String() fmt.Println(idempotentKey) } ``` ```javascript unique_key.js theme={null} const { v4: uuidv4 } = require('uuid'); const idempotentKey = uuidv4(); console.log(idempotentKey); ``` ```python unique_key.py theme={null} import uuid idempotent_key = str(uuid.uuid4()) print(idempotent_key) ``` ```java unique_key.java theme={null} import java.util.UUID; String idempotentKey = UUID.randomUUID().toString(); System.out.println(idempotentKey); ``` ```cs unique_key.cs theme={null} using System; string idempotentKey = Guid.NewGuid().ToString(); Console.WriteLine(idempotentKey); ``` ## Retrying Failed Webhooks When a webhook fails to deliver because the receiving server does not return a `2XX` status code, Nomba automatically retries the request using an exponential backoff policy. This approach spaces out retries with increasing delays, preventing your server from being overwhelmed while still ensuring delivery. Both `4XX` client errors and `5XX` server errors will trigger this retry flow. After the first failed attempt, Nomba will make up to five additional attempts to re-deliver the webhook. The table below gives proper perspective into how failed webhooks would be retried. | No of Retries | WaitTime (in Seconds) | WaitTime (in Mins) | | ------------- | --------------------- | ------------------ | | 1 | `120 secs` | `2 mins` | | 2 | `280 secs` | `~ 5 mins` | | 3 | `640 secs` | `~ 11 mins` | | 4 | `1440 secs` | `24 mins` | | 5 | `3200 secs` | `~ 53 mins` | # Acceptable KYB Documents Source: https://developer.nomba.com/docs/getting-started/acceptable-documents Learn the documents needed for KYB verification To comply with local regulations, we require specific documents. These documents are necessary for Know Your Customer (KYB) verification purposes and help ensure the legitimacy of your business. ## KYB Document Stages 1. Pre-Approval 2. Post-Approval We must collect these documents for verification purposes as they are mandated by our local regulators. ## Business Category Types Depending on the business category you select, we will request documents specific to that type. The four business categories are: 1. Private or Public Limited Company (LTD/PLC), 2. Business Name 3. Registered Partnership 4. Incorporated Trustees To learn more about the document requirements for each business category, please visit the Business Requirements section. *** ## Acceptable Documents **Certificate of Incorporation** This is a formal document issued by the Corporate Affairs Commission (CAC) that signifies the official registration of the company. **CAC Status Report** This includes various CAC forms, such as CAC 2, CAC 7, CAC 1.1, CAC BN1 and Form CAC/IT 1. These documents provide a status update or profile of a company, indicating that it is properly registered with the CAC. **Board Resolution** A document signed by a company's board of directors that reflects decisions or actions taken by the board. **Utility Bill or Bank Statement** Utility Bill or Bank Statement within the last three months or Rental Agreement (valid for 12 months) These are documents used to verify the physical address of the business. **BVN (Bank Verification Number)** The Bank Verification Number (BVN) of the business owners is used for identity verification and security, along with a valid form of identification. **NIN (National Identification Number)** The National Identification Number (NIN) or a valid ID is used to verify the identity of the business's directors. **Partnership Resolution (For Partnerships)** A written agreement or decision made by the partners of a business, typically regarding the operation or governance of the partnership. **Valid ID** A Valid ID (such as a national ID, BVN, NIN, passport, or driver’s license) for identity verification of the directors, partners, or trustees involved in the business. **Board of Trustees Resolution (For Incorporated Trustees)** A resolution document signed by the Board of Trustees, outlining official decisions or actions taken by the board regarding the management or governance of the organization. *** ## Pre-Approval Business Type Requirements ### Private or Public Limited Company (LTD/PLC) 1. Certificate of Incorporation 2. CAC Status Report or CAC 2 AND CAC 7 or CAC 1.1 3. Board Resolution 4. Utility Bill or bank statement within the last three months or rental agreement valid within 12 months 5. BVN abd NIN of All Directors (1 of each at onboarding) ### Business Name 1. Certificate of Incorporation 2. CAC Status Report or CAC BN1 3. BVN and Valid ID of Business Owners 4. Utility Bill or bank statement within the last three months or rental agreement valid within 12 months ### Registered Partnership 1. Certificate of Incorporation 2. CAC Status Report or Form CAC/LLP 01 or CAC/LP O1 3. Partnership resolution 4. Utility Bill or bank statement within the last three months or rental agreement valid within 12 months 5. BVN of ALL Partners (1 of each at onboarding) 6. NIN or Valid ID of Partners 7. BVN and NIN of ALL Partners (1 of each at onboarding) ### Incorporated Trustees 1. Certificate of Incorporation 2. CAC Status Report or Form CAC/ IT 1 3. Board of Trustees resolution 4. Utility Bill or bank statement within the last three months or rental agreement valid within 12 months 5. BVN of ALL Partners (1 of each at onboarding) 6. NIN or Valid ID of Trustees *** ## Post Approval Business Type Requirements ### Private or Public Limited Company (LTD/PLC) 1. Tax Identification Number 2. SCMUL 3. BVN and NIN of all shareholders above 5% shareholding 4. Social media handle of the business ### Business Name 1. Tax Identification Number 2. SCMUL 3. Social media handle of the business ### Registered Partnership 1. Business Operating license (if applicable) 2. Tax Identification Number 3. SCMUL 4. Registered Partnership Agreement/Deed (certified as true copy by the Registrar of Companies) 5. Social media handle of the business ### Incorporated Trustees 1. Business Operating license 2. Tax Identification Number 3. SCMUL 4. Social media handle of the business It's important to note that some documents can be substituted, and they are indicated on the sheet with **' or'**. For instance, the merchant can provide either a Utility Bill or bank statement within the last three months or a rental agreement valid within 12 months # Authenticate Source: https://developer.nomba.com/docs/getting-started/authentication Learn how to ensure secure access to Nomba API Resources. ## Overview Nomba uses **OAuth 2.0** to secure API access. You'll use your `client_id` and `client_secret` to obtain an `access_token`. To get the client credentials from the Nomba dashboard, follow the steps on how to [obtain API keys](/docs/getting-started/get-api-keys). The authentication flow has three key steps: 1. **Obtain** an `access_token` and `refresh_token` 2. **Refresh** the token when it expires 3. **Revoke** the token when no longer needed ## Obtain Access Token Use the `client_credentials` grant to request an `access_token` and `refresh_token`. The `access_token` is required for making API requests. ```bash cURL theme={null} curl --request POST \ --url https://api.nomba.com/v1/auth/token/issue \ --header 'Content-Type: application/json' \ --header 'accountId: ' \ --data '{ "grant_type": "client_credentials", "client_id": "replace-with-your-client-id", "client_secret": "replace-with-your-client-secret" }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api.nomba.com/v1/auth/token/issue', { method: 'POST', headers: { 'Content-Type': 'application/json', 'accountId': '', }, body: JSON.stringify({ grant_type: 'client_credentials', client_id: 'replace-with-your-client-id', client_secret: 'replace-with-your-client-secret', }), }); const { code, data } = await response.json(); if (code !== '00') throw new Error('Authentication failed'); const { access_token, refresh_token, expiresAt } = data; ``` ```python Python theme={null} import requests response = requests.post( 'https://api.nomba.com/v1/auth/token/issue', headers={ 'Content-Type': 'application/json', 'accountId': '', }, json={ 'grant_type': 'client_credentials', 'client_id': 'replace-with-your-client-id', 'client_secret': 'replace-with-your-client-secret', }, ) result = response.json() if result['code'] != '00': raise Exception('Authentication failed') access_token = result['data']['access_token'] refresh_token = result['data']['refresh_token'] ``` ```json Response theme={null} { "code": "00", "description": "Success", "data": { "businessId": "01a10aeb-d989-460a-bbde-9842f2b4320f", "access_token": "eyJhbGciOiJIUzI1NiJ9...", "refresh_token": "01h4gdx2tctxfjgacbdwrcvs5d1688473602892", "expiresAt": "2022-07-08T14:33:00Z" } } ``` ## Refresh Access Token Access tokens expire after 30 minutes. Instead of requesting a new token with your credentials, exchange the `refresh_token` for a new `access_token`. This avoids exposing your client\_secret repeatedly and keeps the process secure. We recommend refreshing your `access_token` at least 5 minutes before it expires. ```bash cURL theme={null} curl --request POST \ --url https://api.nomba.com/v1/auth/token/refresh \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --header 'accountId: ' \ --data '{ "grant_type": "refresh_token", "refresh_token": "01h4gdx2tctxfjgacbdwrcvs5d1688473602892" }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api.nomba.com/v1/auth/token/refresh', { method: 'POST', headers: { 'Authorization': `Bearer ${accessToken}`, 'Content-Type': 'application/json', 'accountId': '', }, body: JSON.stringify({ grant_type: 'refresh_token', refresh_token: refreshToken, }), }); const { code, data } = await response.json(); if (code !== '00') throw new Error('Token refresh failed'); const newAccessToken = data.access_token; ``` ```python Python theme={null} import requests response = requests.post( 'https://api.nomba.com/v1/auth/token/refresh', headers={ 'Authorization': f'Bearer {access_token}', 'Content-Type': 'application/json', 'accountId': '', }, json={ 'grant_type': 'refresh_token', 'refresh_token': refresh_token, }, ) result = response.json() if result['code'] != '00': raise Exception('Token refresh failed') new_access_token = result['data']['access_token'] ``` ```json Response theme={null} { "code": "00", "description": "Success", "data": { "businessId": "01a10aeb-d989-460a-bbde-9842f2b4320f", "access_token": "eyJhbGciOiJIUzI1NiJ9...", "refresh_token": "01h4gdx2tctxfjgacbdwrcvs5d1688473602892", "expiresAt": "2022-07-08T14:33:00Z" } } ``` ## Revoke Access Token Revoke an `access_token` when you need to immediately terminate access. This is useful if the token is compromised, expired, or no longer needed. Once revoked, the token is invalid and cannot be used to access resources. ```bash cURL theme={null} curl --request POST \ --url https://api.nomba.com/v1/auth/token/revoke \ --header 'Content-Type: application/json' \ --header 'accountId: ' \ --data '{ "clientId": "2242b79d-f2cf-4ccc-ada1-e890bd1a9f0d", "access_token": "" }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api.nomba.com/v1/auth/token/revoke', { method: 'POST', headers: { 'Content-Type': 'application/json', 'accountId': '', }, body: JSON.stringify({ clientId: '2242b79d-f2cf-4ccc-ada1-e890bd1a9f0d', access_token: accessToken, }), }); const { code } = await response.json(); if (code !== '00') throw new Error('Token revocation failed'); ``` ```python Python theme={null} import requests response = requests.post( 'https://api.nomba.com/v1/auth/token/revoke', headers={ 'Content-Type': 'application/json', 'accountId': '', }, json={ 'clientId': '2242b79d-f2cf-4ccc-ada1-e890bd1a9f0d', 'access_token': access_token, }, ) result = response.json() if result['code'] != '00': raise Exception('Token revocation failed') ``` ```json Response theme={null} { "code": "00", "description": "Token revoked successfully" } ``` ## Authentication Best Practices To keep your integration secure, follow these best practices: * Never expose credentials (`client_id`, `client_secret`, `refresh_token`) in frontend code or public repositories. * Use secure storage for tokens in your backend (e.g., environment variables, encrypted storage). * Refresh tokens proactively (5 minutes before expiry) instead of waiting until the last moment. * Revoke tokens immediately if you suspect they've been leaked or compromised. * Rotate credentials periodically and remove unused API keys. # Obtain API Keys Source: https://developer.nomba.com/docs/getting-started/get-api-keys We are excited to have you here. ## Overview To obtain API keys for secure authentication to Nomba resources, you must first create an account and complete your KYC.\ Your documents will be reviewed by our compliance team, and approval will be granted once they are validated. *** ## Setting up your account Getting started is simple. Sign up today to create your account. During registration, we collect basic information such as your address and estimated revenue. The process is designed to be quick and seamless. You need a **corporate account** to use the Nomba API. Click **I'm Ready, Let's Begin** Complete the account creation steps. To complete registration, you must provide a valid email, phone number, Bank Verification Number (BVN), and other required information.\ You must also upload documents that verify your business. See the full list of [acceptable KYB documents](/docs/getting-started/acceptable-documents). After registration, [sign in](https://dashboard.nomba.com/auth/login) to your dashboard to generate your API keys. *** ## Get your API Key You can generate API keys directly from your Nomba dashboard: 1. Go to **Developer** → **API Keys**. 2. Click **Generate API keys**. 3. Copy your keys for integration with the Nomba API. 4. After copying, proceed to [obtain an access token.](/docs/getting-started/authentication) After completing your integration and testing in the Sandbox environment, you will need access to production keys to start processing real transactions. Please reach out to the Nomba team to enable your production keys. Always protect your secret keys. Anyone with access to them can gain control of your account. *** ## Adding a team member You can invite colleagues to collaborate on your Nomba dashboard. 1. Go to the **Teams** section in the left menu and click on add team member. 2. Enter your colleague’s email address and send the invitation. 3. The invitee will receive an email and can accept it to join your team. Each member can be assigned a role with specific permissions: * **Owner** – Full access, including account and billing management. * **Super Admin** – Full access to resources and settings, a Super Administrator has unrestricted access to all current and future accounts under this business. Assign this role with caution, as it grants complete control. * **IT/Developer** – Access to API keys, integrations, and technical resources. * **Unassigned User** – Limited access until a role is assigned. This role-based access ensures each team member only has the permissions necessary for their responsibilities. # Accept online payments Source: https://developer.nomba.com/docs/guides/accept-online-payments End-to-end guide for integrating Nomba Checkout to accept online payments. This guide walks you through the full integration journey. For a detailed field reference, code examples, and advanced features, see the [Create Checkout Order](/docs/products/accept-payment/create-checkout-order) product page. ## Introduction Nomba Checkout is a hosted payment page that lets your customers pay via bank transfer or debit card (Mastercard, Visa, Verve). You create an order via API, hand your customer the checkout link, and Nomba handles the payment flow — including card authentication, OTP, and 3DS. ## Integration steps Before making any API call, retrieve your credentials from the [Nomba dashboard](https://dashboard.nomba.com). You'll need your `clientId`, `clientSecret`, and `accountId`. Both sandbox (test) and production credentials are available. Use sandbox credentials with `https://sandbox.nomba.com` during development. See [Environment](/docs/api-basics/environment) for base URL details. Nomba notifies your server of payment events via webhooks. Set up your webhook endpoint in the dashboard and subscribe to the `payment_success` event before you go live. See the [Webhook guide](/docs/api-basics/webhook) for setup instructions and payload verification. Exchange your credentials for an access token. All subsequent API calls require this token in the `Authorization` header. ```bash theme={null} curl --request POST \ --url https://api.nomba.com/v1/auth/token/issue \ --header 'Content-Type: application/json' \ --header 'accountId: ' \ --data '{ "grant_type": "client_credentials", "client_id": "", "client_secret": "" }' ``` ```json Response theme={null} { "code": "00", "description": "Success", "data": { "access_token": "eyJhbGci...", "refresh_token": "01h4gdx2...", "expiresAt": "2026-01-01T14:33:00Z" } } ``` Call `POST /v1/checkout/order` with the payment amount and customer details. Nomba returns a `checkoutLink` — display or redirect your customer to this URL to complete payment. ```bash theme={null} curl --request POST \ --url https://api.nomba.com/v1/checkout/order \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --header 'accountId: ' \ --data '{ "order": { "orderReference": "your-unique-order-ref", "amount": "10000.00", "currency": "NGN", "customerEmail": "customer@example.com", "callbackUrl": "https://merchant.com/callback" } }' ``` ```json Response theme={null} { "code": "00", "description": "Success", "data": { "checkoutLink": "https://checkout.nomba.com/pay/fd3002af-d48b-40a0-adba-0b1e2f3a4b5c", "orderReference": "fd3002af-d48b-40a0-adba-0b1e2f3a4b5c" } } ``` Pick the `checkoutLink` from the response and load it in a browser or iframe to let your customer pay. The `orderReference` in the response is the Nomba-generated order ID, not the reference you passed in the request. See [Create Checkout Order](/docs/products/accept-payment/create-checkout-order#request-fields) for how the two values are used. For the full list of request fields (split payments, tokenization, allowed payment methods), see [Create Checkout Order](/docs/products/accept-payment/create-checkout-order). Once payment is successful, Nomba sends a `payment_success` webhook to your configured URL. The payload differs slightly between card and bank transfer payments. **Card payment webhook:** ```json theme={null} { "event_type": "payment_success", "requestId": "ddfadc29-d1c0-41d6-904d-a71a6740f1c4", "data": { "transaction": { "transactionId": "WEB-ONLINE_C-CB677-27b33599-9359-4aa3-b4d0-9c60f3b4a978", "type": "online_checkout", "transactionAmount": 2400.0, "fee": 93.6, "time": "2024-01-11T16:33:04Z" }, "order": { "orderReference": "your-unique-order-ref", "amount": 2400.0, "currency": "NGN", "paymentMethod": "card_payment", "cardType": "Visa", "cardLast4Digits": "8038" } } } ``` **Bank transfer webhook:** ```json theme={null} { "event_type": "payment_success", "requestId": "a8b2c3d4-e5f6-47a8-b9c0-d1e2f3a4b5c6", "data": { "transaction": { "transactionId": "WEB-ONLINE_C-CB677-83a1b2c3-d4e5-6f7a-b8c9-0d1e2f3a4b56", "type": "online_checkout", "transactionAmount": 2400.0, "fee": 93.6, "time": "2024-01-11T16:40:12Z" }, "customer": { "billerId": "8022636522", "senderName": "John Doe" }, "order": { "orderReference": "your-unique-order-ref", "amount": 2400.0, "currency": "NGN", "paymentMethod": "bank_transfer" } } } ``` See the [Webhook guide](/docs/api-basics/webhook) for signature verification instructions. Always verify the transaction server-side before delivering goods or services. Do not rely on the webhook alone. Use the `transactionId` from the webhook (`data.transaction.transactionId`) to call `GET /v1/transactions/accounts/single`: ```bash theme={null} curl --request GET \ --url 'https://api.nomba.com/v1/transactions/accounts/single?transactionRef=WEB-ONLINE_C-CB677-27b33599-9359-4aa3-b4d0-9c60f3b4a978' \ --header 'Authorization: Bearer ' \ --header 'accountId: ' ``` Check that `data.status` is `"SUCCESS"` before proceeding. You can also verify using the `orderReference` as a query param instead of `transactionRef`. See [Verify Transactions](/docs/products/accept-payment/verify-transactions) for full details. ## Next steps See all checkout features and quick links Test your integration with sandbox credentials and test cards Charge saved cards for subscriptions and recurring billing Process refunds for completed payments # Accept Payments with Payment Links Source: https://developer.nomba.com/docs/guides/accept-payment-with-payment-links Effortlessly accept payments with a unique payment URL. ## Introduction Nomba provides numerous ways to accept payment between merchants and their customers. Payment solutions like POS terminals (point of sale), mobile banking for local and international payments, and Vendor API for businesses looking to integrate payment flow for their businesses. All of these are excellent ways to accept payment. However, Nomba has also provided a payment link for accepting payment via a shareable unique URL that can be sent via email, social channel and any other means for convenience and ease of accepting payment. Payment links are a convenient way to accept online payment without hassle; the unique link shared with a customer will redirect to a payment page where they will complete the payment. ## Create a Payment link There are few things to take note of when creating a payment link on your Nomba dashboard. The list below highlights some of the important things to know so that merchants can get the best out of Nomba payment links. * Payment links can only be created on your Nomba dashboard. * When creating a payment link, you have options to set a fixed amount or allow the customer to input a varying amount. * Payment links are reusable; this means that multiple customers can pay via the same link at different time intervals. * Payment links can be deactivated and reactivated at your convenience. * Payment links can be edited or deleted after creation. To get started, log in to your Nomba dashboard and navigate to the payment link page by clicking the payment link text on the side navigation. Click on the Create Link button on the page, and you will be redirected to a page containing a form where you can set up a payment link. While filling the form, you can configure the payment link to accept USD, EUR, NGN, and GBP. You can also allow tipping or varying amounts by toggling the radio button with the label "allow customer to set price." When set, the amount field will be disabled. To enable tipping, you must set an amount, as this feature does not work if you intend to allow your customer to set the price. When you click on the advanced setting dropdown icon, you may select the option that suits your needs, either allowing your customer to redirect to a website when they complete payment or enabling tipping if you added a fixed price. ## Share Created Payment Link After you have successfully created a payment link, click on the share button on the list to share it with your customer. ## Complete Payment. When a customer opens this link, it redirects them to this view where they enter their name and email before completing the payment on the Nomba checkout page. Payment link is a product built to ensure simplicity in payment collection. Whether you want to receive a one-time payment or reuse this payment channel for different customers, we've got you covered! # Authentication best practises Source: https://developer.nomba.com/docs/guides/authentication-best-practises Strategies for optimizing the authentication workflow with the Nomba API. #### Secure Credentials Storage Safeguard your credentials by storing client\_id and client\_secret securely in your server application rather than exposing them in client applications. Ensure a robust security posture by refraining from connecting to our services directly from client applications unless utilizing the PKCE flow. Never store sensitive credentials, such as `client_id` and `client_secret`, in client applications where they could be susceptible to exposure. Instead, securely store these credentials in your server application, providing an added layer of protection. #### Single-Instance Authentication Streamline your authentication process by utilizing the refresh token approach for obtaining new access tokens, ensuring seamless access to resources with minimal disruptions. In a single-instance environment, the primary workflow involves the instance obtaining an `access_token` through the [Obtain access token](/docs/getting-started/authentication#obtain-access-token) endpoint. Subsequently, use this `access_token` to interact with the Nomba API. If a 401 Unauthenticated response is received, it indicates a potential expiration of the `access_token`, prompting the need for renewal. While the [Obtain access token](/docs/getting-started/authentication#obtain-access-token) endpoint can be utilized for obtaining a new `access_token`, we recommend employing the refresh token approach. Use the [Refreshing access token](/docs/getting-started/authentication#refresh-access-token) endpoint with the `refresh_token` obtained during the initial `access_token` retrieval. This method streamlines the process, ensuring a seamless token refresh and providing both `access_token` and `refresh_token` upon success. Repeatedly refresh the token using this approach whenever the `access_token` expires. #### Multi-Instance Authentication Architect your system to support a single instance authenticating at a time, implementing a lock mechanism to ensure secure and synchronized authentication across multiple instances. In a multi-instance environment, where multiple instances may authenticate simultaneously, careful consideration is required to avoid potential issues. Authentication from multiple instances within an application is not recommended, as it can lead to 401 errors due to security measures maintaining a single session. To address this, architect your system to support a single instance authenticating with our services at a given time. Implement a robust locking mechanism to enforce this constraint, allowing only one instance to authenticate. After successful authentication, store the `access_token` and `refresh_token` in a cache within the same instance. Subsequent instances can then retrieve the tokens from the cache, ensuring a secure and synchronized authentication process across multiple instances. # Introduction Source: https://developer.nomba.com/docs/guides/introduction Start effortlessly with our user-friendly guides ## Overview We acknowledge the substantial time and effort required to build and integrate your exceptional products with Nomba. To streamline this process, we've thoughtfully curated an array of comprehensive guides. These resources are tailored to expedite your initiation, offering clear and concise pathways that align with your objectives. Our goal is to provide you with the necessary support to seamlessly integrate with Nomba, allowing you to focus on the core aspects of developing and enhancing your products. #### Dive Straight in Strategies for optimizing the authentication workflow with the Nomba API. Instructions on integrating Nomba's payment gateway for processing online payments. Guidance on how to configure your webhooks on your Nomba dashboard. # Managing accounts with Nomba Source: https://developer.nomba.com/docs/guides/managing-accounts-with-nomba Learn everything about accounts with Nomba. ## Introduction Accounts in Nomba are like dedicated spaces you can create under your business. They come in handy for different use cases, whether you’re accepting payments or setting up persistent, standalone bank accounts for your customers. Just like any other resource in Nomba, accounts are protected by permissions. With your API keys (which give admin-level access), you can manage all accounts under your business. That means full control—create accounts, view balances, move money, and more. ## What are accounts Accounts play a pivotal role as operational units within a business. They also act as a pocket of money where funds can sit in. This means that payments from your customers can sit inside of an account. Accounts typically have a bank account number that is linked to them. When you provide this bank account to your customer, and they make a bank transfer from their commercial bank into it, the money will sit inside of the account. This guide is designed to provide software engineers with an in-depth understanding of the intricacies of accounts, including their types, functionalities, and relationships. All accounts can accept inbound transfers. When the bank account number linked to the account is provided to your customer, they can transfer money into it and you will be credited. ## Types of Accounts There are three primary types of accounts on the Nomba platform: ### Parent or Primary Account Automatically generated upon dashboard signup, the primary account serves as the foundational element of a business on Nomba. It facilitates essential functions, including accepting payments, making transfers, assigning terminals, and configuring auto-settlement. ### Virtual Account Created exclusively through the API, virtual accounts serve a unique purpose. While they do not function as standalone repositories of money, virtual accounts efficiently route inbound payments to the primary account. Notably, outbound transfers and terminal assignments are not supported for virtual accounts. ### Sub Account A sub-account is an account type that is exclusively available on the dashboard; it serves as a pocket of money due to its repository nature of holding funds. When you intend to have a separate account where you can hold or accept some dedicated funds, it's great to consider opening a sub-account. Nomba allows you to create a sub-account that receives USD and NGN inflows all in one place, sitting right on top of your primary account; it can also process settlement to external banks. ## Create a Sub-account To create a sub account, sign in on the dashboard and navigate to the account section. click on the Open Account button on the top right corner of the account section. you will have the option to select Naira account or Dollar account. When you are done selecting based on your preference you will be presented with a modal to add your account name. follow the on screen guide to complete the process. You can use your sub-account to accept split payment from checkout. To do this, copy your sub-account account ID and pass it on your checkout setup. ## Core Functionalities of Accounts * **Payment Handling** Accounts offer comprehensive functionalities, empowering businesses to: * **Accept Payments** Serve as repositories for funds received from customers, allowing businesses to seamlessly handle transactions. * **Make Transfers** Facilitate both inbound and outbound fund transfers between accounts for efficient financial management. * **Assign Terminals** Enable businesses to organize payment processing by assigning terminals as needed. * **Configure Auto Settlement** Provide automation options for settling funds into commercial bank accounts, streamlining financial processes. ## Relationship between Accounts When an account is created, it becomes an integral part of the business structure. Virtual accounts are considered subordinate to the primary account, establishing a hierarchical relationship. Comprehending the nuanced details of account types, their functionalities, and relationships is vital for software engineers working on applications within the Nomba platform. By leveraging this comprehensive documentation, engineers can design robust solutions aligned with the platform's architecture, ensuring seamless integration with businesses utilizing Nomba services. The following table shows the features across the different types of accounts | | Primary Account | Virtual Account | Sub Account | | ----------------------------- | --------------- | --------------- | ----------- | | BVN requirement for creation | `Y` | `N` | `N` | | Inbound transfers | `Y` | `Y` | `Y` | | Outbound transfers | `Y` | `N` | `Y` | | Terminal assignment | `Y` | `N` | `Y` | | Auto-settlement configuration | `Y` | `N` | `Y` | # Nomba woocommerce integration Source: https://developer.nomba.com/docs/guides/nomba-woocommerce-integration # How to setup Nomba payment on WooCommerce Nomba offers Nigerian merchants a seamless way to accept payments on their WooCommerce-powered WordPress websites. This guide will walk you through installing and configuring the Nomba payment gateway plugin for WooCommerce. *** ## Overview To get started, you'll need to: 1. Install the required plugins 2. Get your Nomba API keys 3. Configure the Nomba plugin settings 4. Add webhooks for payment notifications 5. Test your checkout experience *** ## Required Plugins 1. Install the following plugins from your WordPress admin panel: 2. WooCommerce (for eCommerce functionality) 3. Classic Editor (to prevent compatibility issues with Nomba plugin) 4. Nomba Payment Gateway for WooCommerce *** ## How to Install a Plugin 1. Go to your WordPress Dashboard 2. Navigate to Plugins > Add New 3. Search for each plugin (e.g., "WooCommerce", "Nomba") 4. Click Install, then Activate > > If you encounter errors during checkout, install and activate the Classic Editor plugin to resolve them. *** ## Get Your Nomba API Keys 1. Sign up or log into your Nomba dashboard: [https://nomba.com](https://nomba.com) 2. Go to Settings > Webhooks & API Keys 3. Copy your Test or Live API keys and Account ID *** ## Configure the Nomba Plugin 1. From the WordPress dashboard, go to WooCommerce > Settings > Payments 2. Click Manage next to “Nomba Payment Gateway” 3. Enter your Nomba API Keys and Account ID 4. Enable Test Mode (for development) or disable it for live transactions 5. Click Save Changes # Setting up webhooks Source: https://developer.nomba.com/docs/guides/setting-up-webhooks Guidance on how to configure your webhooks on your Nomba dashboard. Setting up your webhook through the Nomba dashboard is a straightforward process. Before configuring your webhooks, your dashboard will resemble the image below. To initiate the setup, proceed by adding your webhook URL and the corresponding signature key. Additionally, carefully select the events you wish to monitor. For a comprehensive understanding of available webhook events, refer to the [Webhooks documentation](/docs/api-basics/webhook). Before inclusion, we perform a validation check on the webhook URL to ensure it is ready to accept HTTP RESTful POST calls. Please ensure your webhook URL is prepared for seamless integration. It's crucial to remember your Signature Key, as it plays a vital role in the signature verification process, especially when generating an HMAC signature. Once you have successfully subscribed to events via your webhooks, your dashboard will reflect the configured events. Take care to subscribe to the appropriate events to tailor your webhook functionality to your specific needs. Feel free to [Reach out](/support/reach-out) if you have any questions or need further assistance. # Shopify nomba integration Source: https://developer.nomba.com/docs/guides/shopify-nomba-integration # Set Up Nomba Checkout on Shopify Nomba provides a secure and developer-friendly payment solution that integrates easily with Shopify. Similar to the WordPress plugin, Nomba for Shopify allows merchants to accept both local and international payments through a simple no-code setup. This guide will walk you through the complete process of integrating Nomba into your Shopify store. *** ## Prerequisites Before you begin, make sure you have: 1.A Shopify Store (with admin access) 2.A Nomba Account (Create one here: [https://nomba.com](https://nomba.com)) 3. Your Client ID, Private Key, and Account ID (from Nomba dashboard) *** ## Get Your Nomba API Credentials 1. Login to your Nomba Dashboard 2. Navigate to Settings > API & Webhooks 3. Copy the following "Client ID", "Private Key" and "Account ID" 4. Choose between Test Mode or Live Mode ## Step-by-Step Installation ### Install the Nomba Shopify App 1. Visit the Nomba Shopify App: [https://apps.shopify.com/nomba-gateway](https://apps.shopify.com/nomba-gateway) 2. Click Install App 3. You’ll be redirected to your Shopify Admin panel ### Authorize the App 1. Click Install to confirm the app installation ### Add API Credentials Once installed, you will be redirected to the Nomba Configuration Page: * Paste your Client ID * Paste your Private Key * Paste your Account ID * Check the "Ready" checkbox * Click Submit You’ll see a success message “Your settings have been saved successfully.” ## Activate Nomba as a Payment Method 1. Click ← Go back to payment settings 2. On the Payments Settings page, locate Nomba 3. Click Activate (Optional) Choose the card types you wish to accept 4. Click Save ## Test Your Setup 1. If you're using test credentials: 2. Go to your Shopify storefront 3. Add a product to cart and proceed to checkout 4. Choose Nomba and complete the payment with test card detail ## Add the Webhook URL to Nomba Dashboard 1. Log in to your [Nomba dashboard](https://dashboard.nomba.com/auth/login/). 2. In the left sidebar, click on **Settings**. 3. Select **Webhook and APIkeys** from the settings tab. 4. Scroll down to the **Webhooks** section. 5. Click **Create webhook**. 6. Paste this webhook url: [https://shopcheckout.nomba.com/app/payment\_webhooks](https://shopcheckout.nomba.com/app/payment_webhooks) 7. In the **Event** dropdown, select the event you want to listen for (e.g., "payment success"). 8. Click **Subscribe**. *** ## Monitor and Manage Webhooks 1. You can view, edit, or delete webhooks from the Shopify **Notifications** settings. 2. Ensure your webhook URL remains active and secure. *** ## Troubleshooting 1. **Webhook not triggering:** Ensure the event type matches your use case and the URL is correct. 2. **No response in Nomba:** Check your Nomba dashboard for errors or contact Nomba support. *** By following these steps, you can successfully integrate Shopify webhooks with your Nomba dashboard for real-time event notifications. # Try the API Source: https://developer.nomba.com/docs/guides/try-the-api Test Nomba APIs instantly — no account or credentials required No sign-up needed. Call the sandbox endpoints below directly — skip the `Authorization` header and `accountId` entirely. This is the fastest way to see Nomba APIs in action. All examples on this page point to `https://sandbox.nomba.com`. No real money moves — it's a fully isolated test environment. *** ## Option 1 — Try it directly in the API Reference The quickest way to test with zero setup. No terminal, no code. Navigate to the [API Reference](/nomba-api-reference/introduction) section in the sidebar, then pick any endpoint — for example [Transfer](/nomba-api-reference/transfers/perform-bank-account-transfer-from-the-parent-account), [Create Virtual Account](/nomba-api-reference/virtual-accounts/create-virtual-account), or [Create Checkout Order](/nomba-api-reference/online-checkout/create-an-online-checkout-order). On the endpoint page, click the **Try it** button to open the interactive request panel. At the top of the request panel, open the base URL dropdown and select **Sandbox** (`https://sandbox.nomba.com`). You will see fields for **Bearer Token** and **accountId** — leave both completely empty. You do not need credentials to test. Enter your request body fields and click **Send**. The live response will appear directly on the page. The API Reference playground sends requests directly to `https://sandbox.nomba.com`. Leaving the auth fields empty is intentional — it is how the no-account test mode works. *** ## Option 2 — Run it from your terminal ## Transfer to a bank account Send money to any Nigerian bank account. ```bash cURL theme={null} curl --request POST \ --url https://sandbox.nomba.com/v2/transfers/bank \ --header 'Content-Type: application/json' \ --data '{ "amount": 3500, "accountNumber": "055472814", "accountName": "M.A Animashaun", "bankCode": "058", "merchantTxRef": "UNQ_test_001", "senderName": "Test Sender", "narration": "Test transfer" }' ``` ```javascript Node.js theme={null} const response = await fetch('https://sandbox.nomba.com/v2/transfers/bank', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ amount: 3500, accountNumber: '055472814', accountName: 'M.A Animashaun', bankCode: '058', merchantTxRef: 'UNQ_test_001', senderName: 'Test Sender', narration: 'Test transfer', }), }); const data = await response.json(); console.log(data); ``` ```python Python theme={null} import requests response = requests.post( 'https://sandbox.nomba.com/v2/transfers/bank', headers={'Content-Type': 'application/json'}, json={ 'amount': 3500, 'accountNumber': '055472814', 'accountName': 'M.A Animashaun', 'bankCode': '058', 'merchantTxRef': 'UNQ_test_001', 'senderName': 'Test Sender', 'narration': 'Test transfer', }, ) print(response.json()) ``` ```json Response theme={null} { "code": "00", "description": "Success", "data": { "id": "txn_abc123", "status": "SUCCESS", "amount": 3500, "accountNumber": "055472814", "bankCode": "058", "merchantTxRef": "UNQ_test_001" } } ``` *** ## Create a virtual account Generate a unique account number to receive payments. ```bash cURL theme={null} curl --request POST \ --url https://sandbox.nomba.com/v1/accounts/virtual \ --header 'Content-Type: application/json' \ --data '{ "accountRef": "ref_test_001", "accountName": "John Doe", "currency": "NGN" }' ``` ```javascript Node.js theme={null} const response = await fetch('https://sandbox.nomba.com/v1/accounts/virtual', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ accountRef: 'ref_test_001', accountName: 'John Doe', currency: 'NGN', }), }); const data = await response.json(); console.log(data); ``` ```python Python theme={null} import requests response = requests.post( 'https://sandbox.nomba.com/v1/accounts/virtual', headers={'Content-Type': 'application/json'}, json={ 'accountRef': 'ref_test_001', 'accountName': 'John Doe', 'currency': 'NGN', }, ) print(response.json()) ``` ```json Response theme={null} { "code": "00", "description": "Success", "data": { "accountNumber": "9900012345", "accountName": "John Doe", "bankName": "Nomba", "bankCode": "000026", "accountRef": "ref_test_001", "currency": "NGN" } } ``` *** ## Create a checkout order Generate a payment link your customers can use to pay. ```bash cURL theme={null} curl --request POST \ --url https://sandbox.nomba.com/v1/checkout/order \ --header 'Content-Type: application/json' \ --data '{ "order": { "orderReference": "order_test_001", "amount": "10000.00", "currency": "NGN", "customerEmail": "test@example.com", "callbackUrl": "https://merchant.com/callback" } }' ``` ```javascript Node.js theme={null} const response = await fetch('https://sandbox.nomba.com/v1/checkout/order', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ order: { orderReference: 'order_test_001', amount: '10000.00', currency: 'NGN', customerEmail: 'test@example.com', callbackUrl: 'https://merchant.com/callback', }, }), }); const data = await response.json(); console.log(data); ``` ```python Python theme={null} import requests response = requests.post( 'https://sandbox.nomba.com/v1/checkout/order', headers={'Content-Type': 'application/json'}, json={ 'order': { 'orderReference': 'order_test_001', 'amount': '10000.00', 'currency': 'NGN', 'customerEmail': 'test@example.com', 'callbackUrl': 'https://merchant.com/callback', } }, ) print(response.json()) ``` ```json Response theme={null} { "code": "00", "description": "Success", "data": { "checkoutLink": "https://checkout.nomba.com/sandbox/", "orderReference": "order_test_001" } } ``` Open the `checkoutLink` in your browser to see the full payment UI. Use the [test cards](/docs/products/accept-payment/sandbox-testing#test-card-numbers) to simulate different payment outcomes. *** ## Ready to go further? Once you've explored the sandbox, create a free Nomba account to get your own credentials and go live. Get your API keys and start building in minutes. Test cards, webhooks, and error simulation for Checkout. Learn how bearer tokens and accountId work. Browse all available endpoints. # Welcome to Nomba Source: https://developer.nomba.com/docs/introduction/welcome-to-nomba We are excited to have you here. **No account? No problem.** You can test Transfer, Virtual Account, and Checkout right now — no sign-up, no bearer token, no `accountId` needed. [Try the API →](/docs/guides/try-the-api) ## Our products Explore our range of product offerings and discover how they can enhance and empower your overall experience. Accept card and bank transfer payments using checkout or charge API Make instant transfer into bank accounts through our API Integrate our payment acceptance flow into your custom application for in-person payments Learn the fundamentals of the API, including webhooks and pagination. ## Dive Straight in Begin swiftly with the help of our resources. Test Transfer, Virtual Account, and Checkout instantly in our sandbox. No sign-up required. Learn about our API in our interactive API reference. Download the OpenAPI Spec and get started right away. Go through our guides to get started quickly. # Cancel a Checkout Order Source: https://developer.nomba.com/docs/products/accept-payment/cancel-checkout-order Learn how to cancel pending checkout orders using the Nomba API Cancel an incomplete or pending checkout order by order reference ## Overview The Cancel Order API allows you to invalidate a checkout order that has not yet been completed. This is useful when a customer abandons a payment flow, an order expires, or you need to programmatically void a pending transaction before any funds are captured. Cancel Order applies **only to orders that have not been paid**. For completed transactions where funds have already been collected, use the [Refund API](/docs/products/accept-payment/refund-checkout-order) instead. ## When to Use | Scenario | Action | | ---------------------------------------------- | ---------------------------- | | Customer abandons the checkout page | Cancel the pending order | | Order session expires on your platform | Cancel to clean up the order | | Merchant needs to void an order before payment | Cancel the order | | Transaction completed and funds captured | Use **Refund** instead | ## Cancel an Order To cancel an order, send a [POST request](/nomba-api-reference/online-checkout/cancel-checkout-order) to `/v1/checkout/order/cancel` with the `orderReference` of the order you want to cancel. ```bash Request theme={null} curl --request POST \ --url https://api.nomba.com/v1/checkout/order/cancel \ --header 'Content-Type: application/json' \ --data '{ "orderReference": "OD-69923-2e102708-ee34-4a29-b713-a826ca928a12" }' ``` ```json Response theme={null} { "code": "00", "description": "success", "data": { "success": true, "message": "Order cancelled successfully" } } ``` ```json Error Response theme={null} { "code": "01", "description": "Error cancelling order", "data": null } ``` ## Request Parameters | Parameter | Type | Required | Description | | ---------------- | ------ | -------- | ----------------------------------------------------------------------------------------------------------------------- | | `orderReference` | string | Yes | The unique reference of the checkout order to cancel. This is the `orderReference` returned when the order was created. | ## Important Considerations ### Order Status This endpoint only works on **incomplete or pending** orders. Attempting to cancel an already completed or paid order will return an error. ### Idempotency If an order is already cancelled, subsequent cancel requests for the same `orderReference` will return an error. Always check the `success` field in the response to confirm the cancellation. ## Best Practices 1. **Cancel promptly**: Cancel orders as soon as you know they will not be completed to keep your order state clean. 2. **Distinguish cancel from refund**: Cancel is for pre-payment orders; refund is for post-payment transactions. Using the wrong endpoint will result in an error. ## Next Steps Learn how to create a checkout order Verify transaction status after a payment attempt Process refunds for completed transactions # Checkout Overview Source: https://developer.nomba.com/docs/products/accept-payment/checkout-overview Accept payments from your customers using Nomba Checkout Nomba Checkout is a hosted payment page that lets your customers pay you through supported methods such as card, bank transfer, USSD, QR code, Buy Now Pay Later, Apple Pay, International Card, Pay by Bank, or Mobile Money where applicable. You create an order via API, display the checkout link to your customer, and Nomba handles the rest. ## How it works Create an account and retrieve your `clientId`, `clientSecret`, and `accountId` from the [Nomba dashboard](https://dashboard.nomba.com). See [Get API Keys](/docs/getting-started/get-api-keys) for a step-by-step guide. Always use **sandbox credentials** with `https://sandbox.nomba.com` and **production credentials** with `https://api.nomba.com`. Mixing credentials across environments will result in authentication errors. Exchange your credentials for a short-lived access token. Use the sandbox base URL (`https://sandbox.nomba.com`) during development and `https://api.nomba.com` in production. Call `POST /v1/checkout/order` with the amount, currency, and optional customer details. Nomba returns a `checkoutLink` and an `orderReference`. Redirect your customer to the `checkoutLink` or embed it in an iframe. The customer completes payment on the Nomba-hosted page. Nomba sends a `payment_success` event to your configured webhook URL when payment is completed. The webhook payload contains the transaction details and order reference. Verify the transaction using `/v1/transactions/accounts/single` before delivering goods or services. Never rely solely on the webhook without server-side verification. ## Supported payment methods | Method | Description | | ------------------ | --------------------------------------------------------------------------------------- | | Card | Mastercard, Visa, and Verve debit/credit cards | | International Card | Cross-border card acceptance for supported foreign-currency checkout flows | | Bank Transfer | Customer transfers directly to a dynamically generated account number | | USSD | Payment via USSD shortcode on mobile | | Nomba QR | QR code scan-to-pay | | Buy Now Pay Later | Deferred payment option | | Mobile Money | Accept CDF and USD through Mpesa, Orange and Airtel money in DRC | | Apple Pay | On supported Apple devices | | Pay by Bank | UK and European customers authorise the payment in their banking app, in `GBP` or `EUR` | You can restrict which methods appear on the checkout page using the `allowedPaymentMethods` field when creating an order. ## Quick links Full field reference, code examples, split payments, and tokenization Confirm payment status before delivering value End-to-end walkthrough for testing your integration Process full or partial refunds for completed transactions Cancel a pending order before payment is made See all supported card networks and payment options ## SDKs and integrations For web and mobile integrations, using an SDK reduces boilerplate and handles token management for you. Use the Nomba React SDK to embed checkout in your web app Native SDKs for iOS and Android integrations # Create a checkout order Source: https://developer.nomba.com/docs/products/accept-payment/create-checkout-order Learn how to create a checkout order to accept payments Create an online checkout order to accept payments from your customers Charge customer tokenize card with a token key. ## Create a checkout order To create a checkout order, you need to authenticate with Nomba to get your [access token](/docs/getting-started/authentication). If you don't know how to do this, see the getting started section to learn how to obtain API keys and obtain access tokens. Checkout supports different payment methods based on your account, region, currency, and enabled checkout configuration. To generate a [checkout order link](/nomba-api-reference/online-checkout/create-an-online-checkout-order), make a `POST` call to `/checkout/order`. The Nomba API responds with a success message containing the checkout link, which your app will display to the customer for them to make payment. Here are a few things to take note of when creating a checkout order. * Kindly be aware that the optional boolean value `tokenizeCard` should be included or set to true only if you intend to tokenize your customer's card for the purpose of attempting card payments at a later time. * Please pass the `accountId` inside the order request object if you wish to generate a checkout link for a subaccount. * Include the `splitRequest` parameter in the order object if you intend to split your payment. Account ID: if specified in the order object, this is the account where the funds will be deposited. Also, this has to be one of your outlet accounts with Nomba. This will enable you to process checkout transactions for different subaccounts. You can create a subaccount from the dashboard; follow this guide to learn how to create a subaccount and obtain your subaccount account ID. You will also learn how to follow our settlement cycle to set up auto settlement to external banks via subaccount. To create a checkout, send a [POST request](/nomba-api-reference/online-checkout/create-an-online-checkout-order) to this endpoint `/v1/checkout/order`. ```bash cURL theme={null} curl --request POST \ --url https://api.nomba.com/v1/checkout/order \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --header 'accountId: ' \ --data '{ "order": { "amount": "10000.00", "currency": "NGN", "callbackUrl": "https://merchant.com/callback" } }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api.nomba.com/v1/checkout/order', { method: 'POST', headers: { 'Authorization': `Bearer ${accessToken}`, 'Content-Type': 'application/json', 'accountId': accountId, }, body: JSON.stringify({ order: { amount: '10000.00', currency: 'NGN', callbackUrl: 'https://merchant.com/callback', customerEmail: 'customer@example.com', }, }), }); const { code, data } = await response.json(); if (code !== '00') throw new Error(`Checkout creation failed: ${code}`); // Redirect or display the checkout link to your customer const { checkoutLink, orderReference } = data; ``` ```python Python theme={null} import requests response = requests.post( 'https://api.nomba.com/v1/checkout/order', headers={ 'Authorization': f'Bearer {access_token}', 'Content-Type': 'application/json', 'accountId': account_id, }, json={ 'order': { 'amount': '10000.00', 'currency': 'NGN', 'callbackUrl': 'https://merchant.com/callback', 'customerEmail': 'customer@example.com', } }, ) result = response.json() if result['code'] != '00': raise Exception(f"Checkout creation failed: {result['code']} — {result['description']}") checkout_link = result['data']['checkoutLink'] order_reference = result['data']['orderReference'] ``` ```json Response theme={null} { "code": "00", "description": "Success", "data": { "checkoutLink": "https://checkout.nomba.com/pay/78388899***8", "orderReference": "90e81e8a-bc14-4ebf-89c0-57**********" } } ``` ```json Error Response theme={null} { "code": "02", "description": "amount can not be null", "data": null } ``` ## Request Fields ### Top-level fields | Field | Type | Required | Description | | -------------- | ------- | -------- | -------------------------------------------------------------------------------------------------------------------------------- | | `order` | object | Yes | The order object. See fields below. | | `tokenizeCard` | boolean | No | Set to `true` to save the customer's card for future charges. Returns a `tokenKey` in the webhook payload on successful payment. | | `meta` | object | No | Arbitrary key-value metadata attached to the order. Not used for payment processing. | ### `order` object fields | Field | Type | Required | Description | | ----------------------- | ------ | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `amount` | string | **Yes** | The order amount as a string (e.g. `"10000.00"`). | | `currency` | string | **Yes** | ISO 4217 currency code. Use `"NGN"` for Nigerian checkout. For DRC accounts, use `"CDF"` or `"USD"` — `"NGN"` is not supported for DRC and will be rejected. | | `orderReference` | string | No | A unique identifier you assign to this order, up to 50 characters. If omitted, Nomba generates one. Reusing a reference is rejected with an order-already-exists error, so generate a fresh value per order. | | `callbackUrl` | string | No | The URL Nomba redirects the customer to after payment is completed or abandoned. Nomba appends the `orderReference` as a query parameter. Must be a valid HTTPS URL. | | `customerEmail` | string | No | Customer's email address. Nomba sends a payment receipt to this address on successful payment. Must be a valid email format. | | `customerId` | string | No | Your internal identifier for the customer. Stored on the order and returned in webhooks. | | `accountId` | string | No | The Nomba sub-account ID to credit for this order. If omitted, the authenticated parent account is credited. | | `splitRequest` | object | No | Split payment configuration. See [Split payment](#split-payment) section. | | `orderMetaData` | object | No | Arbitrary key-value metadata to attach to the order. Both keys and values must be strings (e.g. `{"productName": "Premium Plan", "internalRef": "INV-001"}`). Stored on the order and returned in webhook payloads. Pass `"region": "CD"` to route the order through DRC checkout (e.g. a Nigerian merchant accepting DRC MoMo payments). | | `allowedPaymentMethods` | array | No | List of payment methods to display on the checkout page. If omitted, all available methods are shown. | The `orderReference` field in the response is **not** the reference you passed in the request. It contains the Nomba-generated order ID, the same UUID that appears at the end of the `checkoutLink`. Keep your own reference for lookups by `orderReference`; use the response value where an `orderId` is expected (for example `idType=ORDER_ID` on [fetch checkout transaction](/nomba-api-reference/online-checkout/fetch-checkout-transaction)). Both values work for [verification](/docs/products/accept-payment/verify-transactions). ## Supported Currencies | Currency | Code | Availability | | --------------- | ----- | ------------------------------------------ | | Nigerian Naira | `NGN` | Available to all merchants by default | | Congolese Franc | `CDF` | Available for supported DRC checkout flows | | US Dollar | `USD` | Activated on demand | | Euro | `EUR` | Activated on demand | | British Pound | `GBP` | Activated on demand | `NGN` is the default currency and requires no additional setup. `CDF` is available for supported DRC checkout flows. To accept payments in `USD`, `EUR`, or `GBP`, your account must be enabled for foreign currency checkout. Nomba screens merchants and activates these currencies only after the required compliance obligations are met. To request foreign currency activation, contact [Nomba support](https://nomba.com/contact) or reach out to your account manager. Passing a currency that has not been activated on your account will result in an error. Always confirm your enabled currencies before going live with multi-currency checkout. **DRC accounts cannot use `NGN`.** If your account is registered in the DRC region, checkout orders must use `CDF` or `USD`. Sending `NGN` (or any other unsupported currency) from a DRC account will be rejected with a `400 Bad Request` error. This applies to both the dashboard and the API. ## Checkout Link Lifecycle After creating an order, Nomba returns a `checkoutLink`. Display or redirect your customer to this URL to complete payment. * The link remains active until the customer completes payment or the order is explicitly cancelled via [Cancel Order](/docs/products/accept-payment/cancel-checkout-order). * After a successful or failed payment, Nomba redirects the customer to your `callbackUrl` (if provided). * The `orderId` and `orderReference` are appended as query parameters on redirect, e.g. `https://merchant.com/callback?orderId=fd3002af-...&orderReference=90e81e8a-...`. * Nomba also sends a `payment_success` webhook event to your configured webhook URL upon successful payment. ## Split payment The Checkout service allows you to distribute a single payment across multiple accounts. You can define how the order value is shared either as a percentage of the total or as a fixed amount. This is useful when you want to receive inflows in a separate account for a product you are collecting payment for. For example, if you are selling a product for ₦1,000 and 10% of the price is your profit, you may want to separate the profit from the original amount. In this case, you can create a sub-account on the Nomba dashboard, pass the sub-account ID, and set the percentage to 10%. This means that every transaction from checkout will automatically deposit ₦100 into the sub-account. See this [guide](/docs/guides/managing-accounts-with-nomba#create-a-sub-account) to learn how to create a sub-account on Nomba dashboard. To enable this feature, include the optional `splitRequest` parameter when creating the checkout order. * Use `splitType`: **"PERCENTAGE"** to specify shares as percentages of the order value. * Use `splitType`: **"AMOUNT"** to specify exact amounts. If you choose to cover the transaction fee, it will always be deducted from your **primary account**. ```json theme={null} "splitRequest": { "splitType": "PERCENTAGE", "splitList": [ { "accountId": "01a10aeb-d989-460a-bbde-9**********", "value": "65.45" }, { "accountId": "02c20beb-a123-460a-bbde-9**********", "value": "34.55" } ] } ``` ## Allowed Payment Methods You can control which payment methods are displayed to customers on the checkout page by specifying the optional `allowedPaymentMethods` field in the order object. This field accepts a list of payment methods that should be available during checkout. Supported values include: * `Card` * `Transfer` * `Nomba QR` * `USSD` * `Buy Now Pay Later` * `MOMO` * `Intl Card` * `Apple Pay` * `Intl Transfer` (Pay by Bank) If `allowedPaymentMethods` is not provided, all enabled payment methods on your account will be displayed. Payment-method availability is region-aware and configuration-aware. For example: * Supported DRC `CDF` checkout flows can expose `MOMO` * Supported DRC `USD` checkout flows can expose `MOMO`, `Intl Card`, and `Apple Pay` * Nigerian checkout flows can continue to expose methods such as `Card`, `Transfer`, `USSD`, `Nomba QR`, and other enabled local methods * Supported `GBP` and `EUR` checkout flows can expose `Intl Transfer` (Pay by Bank), alongside `Intl Card` and `Apple Pay` For Vendor API integrations, the authenticated account region determines the applicable checkout configuration. Currency alone should not be treated as the business-region source of truth. For DRC collections specifically, Checkout supports: * `MOMO` for both `CDF` and `USD` collections * `Apple Pay` for supported `USD` collections * `Intl Card` for supported `USD` collections For Pay by Bank specifically: * `Intl Transfer` is the value used to request or restrict Pay by Bank * The customer pays in `GBP` or `EUR` from a supported UK or European bank account * It must be enabled on your account — contact support. It is not available to Nigerian `NGN`-only checkout flows * It does not support recurring payments, so it is ignored on recurring payment links See [Pay by Bank](/docs/products/accept-payment/payment-methods#pay-by-bank) for the full customer flow and supported institutions. ### Example ```json theme={null} { "order": { "orderReference": "00000-bc14-4ebf-89c0-0003", "customerId": "221220251907", "callbackUrl": "https://new:port/merchant.com/callback", "customerEmail": "abcdef@gmail.com", "amount": "120.00", "currency": "NGN", "accountId": "01a10aeb-d989-460a-bbde-9**********", "allowedPaymentMethods": ["Card", "Transfer"] } } ``` ### DRC examples ```json DRC CDF theme={null} { "order": { "orderReference": "drc-cdf-order-001", "callbackUrl": "https://merchant.example.com/callback", "customerEmail": "customer@example.com", "amount": "120000.00", "currency": "CDF", "allowedPaymentMethods": ["MOMO"] } } ``` ```json DRC USD theme={null} { "order": { "orderReference": "drc-usd-order-001", "callbackUrl": "https://merchant.example.com/callback", "customerEmail": "customer@example.com", "amount": "25.00", "currency": "USD", "allowedPaymentMethods": ["MOMO", "Intl Card", "Apple Pay"] } } ``` You can also create a DRC USD checkout order with all three supported methods enabled: ```json DRC USD With Multiple Methods theme={null} { "order": { "callbackUrl": "https://merchant.example.com/callback", "customerEmail": "customer@example.com", "amount": "100.98", "currency": "USD", "orderReference": "90e81e8a-bc14-4ebf-89c0-57da752ccb65", "customerId": "customer1234", "accountId": "08a1b86d-9140-4967-9998-29114a9e9421", "allowedPaymentMethods": ["MOMO", "Apple Pay", "Intl Card"] }, "tokenizeCard": true } ``` ### Pay by Bank example ```json GBP Pay by Bank theme={null} { "order": { "orderReference": "pay-by-bank-order-001", "callbackUrl": "https://merchant.example.com/callback", "customerEmail": "customer@example.com", "amount": "45.00", "currency": "GBP", "allowedPaymentMethods": ["Intl Transfer"] } } ``` ## Tokenize Card If you need to support recurring or subscription payments, set the optional parameter `tokenizeCard` to true when creating the order. Include and set the `tokenizeCard` field to true. ```json theme={null} "tokenizeCard": true ``` When the payment is successfully completed, Nomba will send a webhook with the event type `payment_success`. This webhook includes a `tokenizedCardData` object containing the tokenKey and other card details. You should save the `tokenKey`, as it is required to charge the card for future recurring payments. ## Sample Webhook Payload ```bash expandable theme={null} { event_type: 'payment_success', requestId: '1ef33774-6d95-411c-b5*************', data: { merchant: { walletId: '1ef33774-6d95-411c-b5*************', walletBalance: 259.47, userId: '1ef33774-6d95-411c-b5*************' }, terminal: {}, tokenizedCardData: { tokenKey: 'N/A', cardType: 'Visa', tokenExpiryYear: 'N/A', tokenExpiryMonth: 'N/A', cardPan: '4***45**** ****111*' }, transaction: { fee: 2.8, type: 'online_checkout', transactionId: 'WEB-ONLINE_C-69923-2e102708-ee34-4a29-b713-a826ca928a********', cardIssuer: 'Visa', responseCode: '', originatingFrom: 'web', merchantTxRef: '18********', transactionAmount: 202.8, time: '2025-09-11T11:50:05Z' }, customer: { billerId: '418745**** ****1119', productId: '418***' }, order: { amount: 202.8, orderId: '1ef33774-6d95-411c-b5*************', cardType: 'Visa', accountId: '1ef33774-6d95-411c-b5*************', cardLast4Digits: '111*', cardCurrency: 'NGN', customerEmail: 'makurseme@gmail.com', customerId: '7628783*******', isTokenizedCardPayment: 'false', orderReference: '1ef33774-6d95-411c-b5*************', paymentMethod: 'card_payment', callbackUrl: 'https://nomba.com', currency: 'NGN' } } } ``` ## Verify Transaction After receiving the webhook notification, always verify the transaction with Nomba before giving value to your customer. This ensures that the event is genuine and the payment was truly successful. You can verify transactions in two ways: ### Webhook Validation (Recommended) * Compute the webhook hash sent in the request headers. * Compare it against your own generated hash to confirm the integrity of the payload. * Learn how to compute webhook signatures in the [Webhook guide](/docs/api-basics/webhook). ### Verify via API Check here to learn how to [verify transactions](/docs/products/accept-payment/verify-transactions). The API responds with the transaction details and status. While webhooks notify you in real time, it is best practice to **always verify all transactions** with the Nomba API before delivering goods or services. # Direct Debit Source: https://developer.nomba.com/docs/products/accept-payment/direct-debit Understand everything about direct debit in Nomba Get started with creating a direct debit mandate via API reference Check mandate status via API reference. Direct Debit is a payment method that allows businesses to collect funds directly from their customers' bank accounts with their authorization. This method is particularly useful for recurring payments, such as subscriptions or utility bills, as it provides a convenient and automated way to manage payments. Direct Debit transactions are typically initiated by the business, but they require prior consent from the customer, ensuring that the process is secure and transparent. ## Create Direct Debit Mandate To begin with the process of creating a Direct Debit mandate. The customer authorize the business, allowing them to debit their bank account for specified amounts and frequencies. The mandate includes details such as the customer's bank account information, the amount to be debited, start date, end date and the frequency of the debits. In order to authorize the mandate, the customer will transfer an amount (N50) to the NIBSS provided account for validation. It's important to note that the amount should be sent from the customer's account number that is being used for the mandate To create a direct debit mandate, send a [POST request](/nomba-api-reference/direct-debits/create-direct-debit) to this endpoint `/v1/direct-debits`. ```bash expandable Request theme={null} curl --request POST \ --url https://api.nomba.com/v1/direct-debits \ --header 'Authorization: Bearer ' \ --header 'accountId: ' \ --header 'Content-Type: application/json' \ --data'{ "customerAccountNumber": "2334334532", "bankCode": "101", "customerName": "Kolapo Adeoti", "customerAddress": "maryland Ikeja computer village", "customerAccountName": "Kolapo Adeoti", "frequency": "VARIABLE", "narration": "test e mandate response", "customerPhoneNumber": "08022222222", "merchantReference": "12003074001223212", // String containing only numeric characters (0-9) "startDate": "2025-08-29T15:30", "endDate": "2025-08-30T10:40", "customerEmail": "kolapo@domail.com", "startImmediately": true }' ``` ```json expandable Response theme={null} { "code": "00", "description": "SUCCESS", "data": { "mandateId": "c93e1e1b-85f5-461e-8b9b-74ee091d4aa4", "merchantReference": "12003074001", "customerPhoneNumber": "08079914423", "description": "Welcome to NIBSS e-mandate authentication service, a seamless and convenient authentication experience. Kindly proceed with a token payment of N50.00 into account number 9880218357 with Paystack-Titan Bank. This payment will trigger the authentication of your mandate. Thank You" }, "message": "SUCCESS", "status": true } ``` The frequency field determines how often the customer’s account will be debited once the mandate is active. Businesses can choose from multiple options depending on their billing model. | Frequency | Description | | --------------------- | --------------------------------------------------------------------------- | | VARIABLE | The debit amount is not fixed. The business specifies the amount each time. | | WEEKLY | Debit occurs once every week. | | MONTHLY | Debit occurs once every month. | | QUARTERLY | Debit occurs once every three months. | | EVERY\_TWO\_MONTHS | Debit occurs once every two months. | | EVERY\_THREE\_MONTHS | Debit occurs once every three months. | | EVERY\_FOUR\_MONTHS | Debit occurs once every four months. | | EVERY\_FIVE\_MONTHS | Debit occurs once every five months. | | EVERY\_SIX\_MONTHS | Debit occurs once every six months. | | EVERY\_SEVEN\_MONTHS | Debit occurs once every seven months. | | EVERY\_EIGHT\_MONTHS | Debit occurs once every eight months. | | EVERY\_NINE\_MONTHS | Debit occurs once every nine months. | | EVERY\_TEN\_MONTHS | Debit occurs once every ten months. | | EVERY\_ELEVEN\_MONTHS | Debit occurs once every eleven months. | | EVERY\_TWELVE\_MONTHS | Debit occurs once every twelve months (yearly). | Once the mandate is created, it undergoes a verification process to ensure that the provided bank account details are valid and the customer's bank authorizes the request. This step can take up to 72 hours for some banks to authorize the mandate. ## Check Mandate Status The status of the mandate is crucial for managing Direct Debit transactions. The possible statuses include `ACTIVE`, `SUSPENDED`, and `DELETED`. To check a mandate status, send a [GET request](/nomba-api-reference/direct-debits/check-direct-debit-status) to this endpoint `/v1/direct-debits/status?mandateId={mandateId}`. ```bash Request theme={null} curl --request GET \ --url https://api.nomba.com/v1/direct-debits/status?mandateId={mandateId} \ --header 'Authorization: Bearer ' \ --header 'accountId: ' --header 'Content-Type: application/json' \ ``` ```json expandable Response theme={null} { "code": "00", "description": "SUCCESS", "data": { "customerAccountName": "Habib Muhammad", "mandateId": "e50b7835-502c-4cfe-8828-47657633d7a2", "customerAccountNumber": "8079914423", "mandateStatus": "Active", "rejectionReason": null, "mandateAdviceStatus": "Advice Sent" }, "message": "SUCCESS", "status": true } ``` The mandate advice status indicates whether the mandate has been approved by the customer's bank for debit. The possible statuses are `ADVICE_NOT_SENT` and `ADVICE_SENT`. It's essential to check the mandate advice status before initiating any debit transactions to ensure that the mandate is valid and active. ## Debit Mandate After the mandate is verified and activated, the business can initiate Direct Debit transactions according to the agreed schedule. The specified amounts will be automatically debited from the customer's bank account and credited to the business's account. Please not the following : * Only mandates with an `ACTIVE` status can be used for debit transactions. * Only mandates with an ADVICE\_SENT status can be used for debit transactions. To debit a mandate created, send a [GET request](/nomba-api-reference/direct-debits/debit-mandate) to this endpoint `/v1/direct-debits/debit-mandate`. ```bash Request theme={null} curl --request POST \ --url https://api.nomba.com/v1/direct-debits/debit-mandate \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --header 'accountId: ' \ --data '{ "mandateId": "89b0efc0-dde5-49e2-8bde-23ae081c43", "amount": "110.00" }' ``` ```json Success response theme={null} { "code": "00", "description": "SUCCESS", "data": { "mandateId": "89b0efc0-dde5-49e2-8bde-5523ae081c43", "status": "SUCCESS", "amount": "110.00", "message": "Approved or completed successfully" }, "message": "SUCCESS", "status": true } ``` ## GET MANDATE To get a single mandate created, send a GET request to this endpoint `/v1/direct-debits/`, you will pass the mandateID as path parameter. ```bash Request theme={null} curl --request GET \ --url http://api.nomba.com/v1/direct-debits/ \ --header 'Authorization: Bearer ' \ --header 'accountId: ' \ --header 'Content-Type: application/json' \ ``` ```json expandable Response theme={null} { "code": "00", "description": "SUCCESS", "data": { "status": "ACTIVE", "customerAccountNumber": "8079914423", "customerAccountName": "Habib Muhammad", "bankCode": "057", "amount": 100.0, "customerName": "Habib Muhammad", "customerAddress": "maryland Ikeja computer village", "customerEmail": "mobolajihabib@gmail.com", "customerPhoneNumber": "08079914423", "merchantReference": "12003074001", "frequency": "VARIABLE", "startDate": [ 2025, 8, 13, 15, 30], "endDate": [ 2025, 8, 30, 10, 40 ], "mandateAdviceStatus": null, "mandateId": "e50b7835-502c-4cfe-8828-47657633d7a2" }, "message": "SUCCESS", "status": true } ``` ## List Direct debit To list all direct debit created, send a [GET request](/nomba-api-reference/direct-debits/list-direct-debit-mandates) to this endpoint `/v1/direct-debits/mandates`. ```bash Request theme={null} curl --request GET \ --url https://api.nomba.com/v1/direct-debits/mandates?page=0&pageSize=20 \ --header 'Authorization: Bearer ' \ --header 'accountId: ' --header 'Content-Type: application/json' \ ``` ```json expandable Response theme={null} { "code": "00", "description": "SUCCESS", "data": { "items": [ { "status": "SUSPEND", "customerAccountNumber": "085566772", "customerAccountName": "Kolapo Ojo", "bankCode": "057", "amount": 100.0, "customerName": "Kolapo Ojo", "customerAddress": "maryland Ikeja computer village", "customerEmail": "mobolajihabib@gmail.com", "customerPhoneNumber": "08022342232", "merchantReference": "12003074001", "frequency": "VARIABLE", "startDate": [ 2025,8,13,15,30 ], "endDate": [ 2025,8,30,10,40 ], "mandateAdviceStatus": "ADVICE_NOT_SENT", "mandateId": "c93e1e1b-85f5-461e-8b9b-74ee091d4aa4" } ], "page": 0, "pageSize": 20, "totalItems": 4, "totalPages": 1, "hasMore": false }, "message": "SUCCESS", "status": true } ``` ## Update Direct debit Status The status of the mandate can be updated as needed. For instance, if a customer wishes to cancel the mandate, the business can update the mandate status accordingly. To update a direct debit status, send a [PUT request](/nomba-api-reference/direct-debits/update-direct-debit-status) to this endpoint `/v1/direct-debits/update-status`. ```bash Request theme={null} curl --request PUT \ --url https://api.nomba.com/v1/direct-debits/update-status \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --header 'accountId: ' \ --data '{ "mandateId": "c93e1e1b-85f5-461e-8b9b-74ee091d4aa4", "status": "SUSPEND" }' ``` ```json expandable Response theme={null} { "code": "00", "description": "SUCCESS", "data": { "items": [ { "status": "SUSPEND", "customerAccountNumber": "085566772", "customerAccountName": "Kolapo Ojo", "bankCode": "057", "amount": 100.0, "customerName": "Kolapo Ojo", "customerAddress": "maryland Ikeja computer village", "customerEmail": "mobolajihabib@gmail.com", "customerPhoneNumber": "08022342232", "merchantReference": "12003074001", "frequency": "VARIABLE", "startDate": [ 2025,8,13,15,30 ], "endDate": [ 2025,8,30,10,40 ], "mandateAdviceStatus": "ADVICE_NOT_SENT", "mandateId": "c93e1e1b-85f5-461e-8b9b-74ee091d4aa4" } ], "page": 0, "pageSize": 20, "totalItems": 4, "totalPages": 1, "hasMore": false }, "message": "SUCCESS", "status": true } ``` # Overview Source: https://developer.nomba.com/docs/products/accept-payment/overview Get started with Nomba Products. Set up payments, recurring billing, direct debit, virtual accounts, and more. Nomba Accept Payments lets you collect funds across supported regions using hosted checkout, virtual accounts, direct debit, and related payment tools. ### Quick Actions Learn how to create static and dynamic virtual account for accepting payments. Accept payments through Checkout using methods such as bank transfer, card, Apple Pay, International Card, and Mobile Money where supported. Collect recurring payments directly from your customers’ bank accounts. See the full list of supported payment methods and their regional availability. # Payment Methods Source: https://developer.nomba.com/docs/products/accept-payment/payment-methods Explore all supported payment methods in Nomba Checkout Nomba Checkout supports multiple ways for your customers to complete payments.\ Each method is secure, reliable, and designed to give you flexibility when accepting payments. Customers can scan a QR code to complete payments instantly.\ Instant settlement Customers can pay directly from their bank account.\ Instant settlement\ Supports recurring billing Customers split their payment into installments.\ Useful for larger purchases or flexible payment plans. Accept local and international cards, including Apple Pay where supported.\ Can be combined with tokenization for recurring subscriptions. Accept DRC mobile money payments from supported networks such as M-Pesa, Airtel Money, and Orange Money. Customers pay via USSD short codes provided by their bank.\ A reliable method for users without access to cards or internet banking. UK and European customers pay directly from their banking app.\ No card details required. *** ## Nomba QR QR codes generated at checkout allow customers to scan and pay instantly.\ This method supports **instant settlement** and can also be used for **recurring payments**. *** ## Bank Transfer Customers can complete transactions by transferring funds directly into your Nomba account.\ Funds are settled instantly, and transfers can also support recurring setups. *** ## Buy Now, Pay Later Enable flexible payments by allowing customers to split the total amount into scheduled installments.\ This improves affordability and increases conversion for high-value purchases. *** ## Card Payments Checkout supports different card experiences depending on your account, currency, and region: | Method | Description | | ------------------ | -------------------------------------------------------------------------- | | Card | Mastercard, Visa, and Verve debit/credit cards | | International Card | Cross-border card acceptance for supported foreign-currency checkout flows | | Apple Pay | Apple Pay on supported Apple devices | For recurring or subscription billing, you can enable **card tokenization** where applicable. *** ## Mobile Money Mobile Money is available for supported DRC checkout flows.\ Use it to collect payments from customers on supported networks such as **M-Pesa**, **Airtel Money**, and **Orange Money**. For DRC checkout: | Method | Description | | ------------------ | ---------------------------------------------------------------------------------------------- | | Mobile Money | Customer approves payment from a supported mobile money wallet in both USD and CDF collections | | Apple Pay | Available for supported DRC USD checkout experiences | | International Card | Available for supported DRC USD checkout experiences | *** ## USSD Offer customers the option to pay using their bank’s **USSD short code**.\ This method works on any mobile device and does not require internet access. *** ## Pay by Bank Pay by Bank lets customers with supported UK and European bank accounts pay you directly from their banking app. No card details are entered at checkout. The experience differs by device: | Device | Customer experience | | ------- | -------------------------------------------------------------------------------------------------------------------------- | | Desktop | The customer scans a QR code at checkout to continue on their phone, or selects their bank and completes it in the browser | | Mobile | The customer selects their bank and is taken straight into the banking app to complete the payment | Once complete, the customer returns to checkout with a confirmation and the payment is initiated immediately. Supported institutions include **Barclays**, **HSBC**, **Revolut**, **Monzo**, **Lloyds**, and other participating UK and European banks. ### Availability | Condition | Detail | | --------------------- | ---------------------------------------------------------------------------------------------------- | | Customer bank account | UK and European bank accounts at participating institutions | | Currency | The customer pays in `GBP` or `EUR` | | Merchant account | Available on supported foreign-currency checkout flows. Contact support to enable it on your account | Pay by Bank is not a Nigerian local payment method. A Nigerian `NGN`-only checkout flow will not show it, and it is not a substitute for **Bank Transfer**, which settles into a dynamically generated Nigerian account number. ### Requesting it at checkout In the checkout order request, Pay by Bank is represented by the `allowedPaymentMethods` value `Intl Transfer`: ```json theme={null} { "order": { "orderReference": "pay-by-bank-order-001", "callbackUrl": "https://merchant.example.com/callback", "customerEmail": "customer@example.com", "amount": "45.00", "currency": "GBP", "allowedPaymentMethods": ["Intl Transfer"] } } ``` If `allowedPaymentMethods` is omitted, Pay by Bank appears automatically on any checkout where your account and the order currency support it. ### Settlement and recurring * **Settlement** — funds settle into your Nomba `GBP` or `EUR` balance for the currency the customer paid in. * **Recurring** — not supported. Pay by Bank is a one-time payment method, and each payment must be authorised by the customer in their banking app. For recurring or subscription billing, use **Card Payments** with tokenization. *** # Recurring Payments Source: https://developer.nomba.com/docs/products/accept-payment/recurring-payments Learn how to charge tokenized cards with the Nomba API Retrieve all tokenized cards associated with a customer for future payments. Update details of an existing tokenized card to keep it valid for recurring billing. ## Charge a Tokenized Card Recurring or subscription payments can be processed using the `tokenKey` generated when a customer’s card was tokenized during checkout.\ This allows you to charge the customer securely without asking for card details again. Only include `tokenizeCard: true` when creating a checkout order if you intend to use the customer’s card for future payments. The returned `tokenKey` from the webhook will then be required for recurring charges. To charge a tokenize card, send a [POST request](/nomba-api-reference/online-checkout/charge-a-customer-using-tokenized-card-data) to this endpoint `/v1/checkout/tokenized-card-payment`. ```bash Request theme={null} curl --request POST \ --url https://api.nomba.com/v1/checkout/tokenized-card-payment \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --header 'accountId: ' \ --data '{ "order": { "orderReference": "90e81e8a-bc14-4ebf-89c0-57da752cca58", "customerId": "762878332454", "callbackUrl": "https://ip:port/merchant.com/callback", "customerEmail": "abcde@gmail.com", "amount": "10000.00", "currency": "NGN", "accountId": "01a10aeb-d989-460a-bbde-9842f2b4320f", "splitRequest": { "splitType": "PERCENTAGE", "splitList": [ { "accountId": "01a10aeb-d989-460a-bbde-9842f2b4320f", "value": "65.45" } ] } }, "tokenKey": "7628788443" }' ``` ```json Response theme={null} { "code": "00", "description": "Success", "data": { "status": true, "message": "Approved by Financial Insitution" } } ``` Always verify the transaction after charging a tokenized card. You can use webhooks for instant notifications, but it is best practice to confirm the status via the [Verify Transactions](/docs/products/accept-payment/verify-transactions) endpoint before providing value to your customers. # Refund a Checkout Order Source: https://developer.nomba.com/docs/products/accept-payment/refund-checkout-order Learn how to refund checkout transactions using the Nomba API Process full or partial refunds for checkout transactions ## Overview The Refund API allows you to return funds to your customers for completed checkout transactions. You can process full refunds, partial refunds, or refund directly to a customer's bank account via transfer. This API is only available in the **production environment** ## Refund Types The Nomba API supports three types of refunds depending on the parameters you provide: ### 1. Full Refund When you provide only the `transactionId`, the system automatically processes a **full refund** for the entire transaction amount. ```json theme={null} { "transactionId": "WEB-ONLINE_C-69923-2e102708-ee34-4a29-b713-a826ca928a12" } ``` ### 2. Partial Refund To refund a portion of the transaction amount, include the `amount` parameter alongside the `transactionId`. The amount must be less than the original transaction amount. ```json theme={null} { "transactionId": "WEB-ONLINE_C-69923-2e102708-ee34-4a29-b713-a826ca928a12", "amount": 5000.00 } ``` ### 3. Refund via Bank Transfer For instant refunds or when card refunds are not supported, you can refund directly to the customer's bank account by providing `accountNumber` and `bankCode`. ```json theme={null} { "transactionId": "WEB-ONLINE_C-69923-2e102708-ee34-4a29-b713-a826ca928a12", "accountNumber": "0123456789", "bankCode": "058" } ``` You can combine the transfer method with partial refunds by including the `amount` parameter ## Process a Refund To process a refund, send a [POST request](/nomba-api-reference/online-checkout/refund-checkout-transaction) to `/v1/checkout/refund`. ```bash Full Refund Request theme={null} curl --request POST \ --url https://api.nomba.com/v1/checkout/refund \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --header 'accountId: ' \ --data '{ "transactionId": "WEB-ONLINE_C-69923-2e102708-ee34-4a29-b713-a826ca928a12" }' ``` ```bash Partial Refund Request theme={null} curl --request POST \ --url https://api.nomba.com/v1/checkout/refund \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --header 'accountId: ' \ --data '{ "transactionId": "WEB-ONLINE_C-69923-2e102708-ee34-4a29-b713-a826ca928a12", "amount": 5000.00 }' ``` ```bash Transfer Refund Request theme={null} curl --request POST \ --url https://api.nomba.com/v1/checkout/refund \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --header 'accountId: ' \ --data '{ "transactionId": "WEB-ONLINE_C-69923-2e102708-ee34-4a29-b713-a826ca928a12", "amount": 5000.00, "accountNumber": "0123456789", "bankCode": "058" }' ``` ```json Response theme={null} { "code": "00", "description": "Success", "data": { "success": true, "message": "Refund processed successfully" } } ``` ## Important Considerations ### Card Refund Timing Card refunds typically take **T+7 days** (7 business days) for fulfillment. The actual time may vary depending on the customer's card issuer and their processing times. ### Vendor Limitations Some card vendors and issuers do not support automated refunds through their systems. In such cases, the refund request may fail or require manual intervention. ### Recommended Approach For **faster and more reliable refunds**, we recommend using the **bank transfer method** by providing the customer's account number and bank code. This ensures immediate processing and avoids potential vendor limitations. ## Best Practices 1. **Verify Before Refunding**: Always verify that the original transaction was successful before processing a refund. 2. **Keep Records**: Store refund transaction IDs and responses for reconciliation and customer support purposes. 3. **Communicate with Customers**: * For card refunds, inform customers about the T+7 days processing time * For transfer refunds, confirm the account details are correct before processing 4. **Use Transfer for Urgent Refunds**: When customers need immediate refunds, use the bank transfer method instead of card refunds. 5. **Handle Partial Refunds Carefully**: Ensure the refund amount does not exceed the original transaction amount. ## Next Steps Learn how to verify transaction status before processing refunds Get the list of bank codes for transfer refunds # Sandbox Testing Source: https://developer.nomba.com/docs/products/accept-payment/sandbox-testing Test your Nomba Checkout integration end-to-end in the sandbox environment 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](/docs/api-basics/environment) for details. ## Before you start ### Get your sandbox credentials Log in to the [Nomba dashboard](https://dashboard.nomba.com), 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. ```bash theme={null} curl --request POST \ --url https://sandbox.nomba.com/v1/auth/token/issue \ --header 'Content-Type: application/json' \ --header 'accountId: ' \ --data '{ "grant_type": "client_credentials", "client_id": "", "client_secret": "" }' ``` ```json Response theme={null} { "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 ```bash theme={null} curl --request POST \ --url https://sandbox.nomba.com/sandbox/checkout/order \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --header 'accountId: ' \ --data '{ "order": { "orderReference": "test-order-001", "amount": "400000.00", "currency": "NGN", "customerEmail": "test@example.com", "callbackUrl": "https://merchant.com/callback" } }' ``` ```json Response theme={null} { "code": "00", "description": "Success", "data": { "checkoutLink": "https://checkout.nomba.com/sandbox/", "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 Number | Network | Outcome | Next step | | ------------------ | ---------- | ----------------------------------------- | -------------------------------- | | `5434621074252808` | Mastercard | OTP required (T0 response) | Submit OTP to complete | | `4000000000002503` | Visa | 3DS authentication required (S0 response) | Handle 3DS redirect | | `5484497218317651` | Mastercard | Declined — "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: | OTP | Outcome | Message | | ------ | ----------- | ---------------------------------------------------- | | `9999` | Approved | "Approved by Financial Institution" | | `1234` | Timeout | "Your payment has exceeded the time required to pay" | | `5464` | Invalid 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](#webhook-payload) below. *** ### Step 4 — Verify the transaction Use the sandbox-specific fetch endpoint to confirm the transaction result: ```bash theme={null} curl --request GET \ --url 'https://sandbox.nomba.com/sandbox/checkout/transaction?idType=orderReference&id=test-order-001' \ --header 'Authorization: Bearer ' \ --header 'accountId: ' ``` ```json Response theme={null} { "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": "test@example.com" }, "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:** | Header | Description | | --------------------------- | ------------------------------------ | | `nomba-signature` | HMAC-SHA256 signature of the payload | | `nomba-sig-value` | Raw signature value | | `nomba-signature-algorithm` | Always `HmacSHA256` | | `nomba-timestamp` | ISO 8601 UTC timestamp of the event | **Sample card payment webhook payload:** ```json theme={null} { "event_type": "payment_success", "requestId": "550e8400-e29b-41d4-a716-446655440000", "data": { "merchant": { "userId": "" }, "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": "", "customerEmail": "test@example.com", "orderReference": "test-order-001", "paymentMethod": "card_payment", "currency": "NGN" } } } ``` To receive webhooks during local development, use a tunnel tool (e.g. [ngrok](https://ngrok.com)) 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. ```bash theme={null} curl --request POST \ --url https://sandbox.nomba.com/sandbox/checkout/refund \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --header '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 test | How to trigger | | --------------------------- | --------------------------------------------------------------------------- | | Order not found | Use `orderReference: "1234567890"` — returns `404` on all endpoints | | Card declined | Use card `5484497218317651` | | OTP timeout | Submit OTP `1234` | | Invalid OTP | Submit OTP `5464` | | Failed refund | Use transactionId `WEB-ONLINE_C-97922-db88d4c3-a0af-4887-a089-b5d2e51b8f19` | | Failed tokenized card fetch | Use `customerEmail: "test@test.com"` | *** ## Sandbox vs production — what's different | Feature | Sandbox | Production | | ---------------------- | ----------------------------------- | ------------------------------ | | 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 transaction | `GET /sandbox/checkout/transaction` | `GET /v1/checkout/transaction` | | Refund | ✅ | ✅ | | Cancel order | ✅ | ✅ | | Tokenized cards | ✅ Hardcoded mock data | ✅ Real tokens | | Real card validation | ❌ Card number determines outcome | ✅ | | Data persistence | Redis, expires after 48 hours | Permanent | *** ## Next steps Full field reference and production code examples Confirm payment status before delivering value Set up and verify webhook signatures Understand sandbox vs production base URLs # Initialize Charge Source: https://developer.nomba.com/docs/products/accept-payment/server-to-server Learn how to build a customized checkout with the charge API. This section of the documentation provides brief information on how to initiate and complete a charge using the Nomba API. To get the complete API, see [API reference](/nomba-api-reference/charge/get-order-details-based-on-the-generated-order-reference). ## Use case Nomba Charge allows you to build a customized payment experience for your users rather than using the Nomba Checkout. Typically when you create a checkout order, you will get a checkoutLink . This will then be used to complete your payment. Instead of redirecting your users to the checkout page to complete their payment. We expose some of the tools that power our checkout, giving you a bit of control of the payment flow. You therefore want to have your own branded checkout, improve user experience and collect card information. All of this is possible when you build a wrapper around the charge API. ## Quick Action Accept card and bank transfer payments. Learn how to submit customers card details Learn how to confirm the payment OTP sent to the customer’s phones. Get Nomba test card for testing purposes. ## Charge Sequence Flow Diagram When building with Nomba Charge, there are a few things to expect in terms of how it should work. The payment process has been exposed to give you more control. This means that you will do more work by collecting card information, providing device information for 3D secure authentication, and ensuring that the paying customer is the legitimate person using OTP sent to their phone. These are the listed process below to get started. 1. Create online checkout order 2. Submit user card details 3. Verify OTP to complete payment 4. Request to save user card information 5. Use Flash Account option for bank Transfer 6. Verify Transaction Status 7. Cancel Checkout Transaction ## How it works To initialize a payment, make a `POST` request to `/checkout/order` ([Create checkout order](/nomba-api-reference/online-checkout/create-an-online-checkout-order)). `checkoutLink` and `orderReference` are returned as part of the response body. Your `orderReference` can be use to verify transaction status or start a charge process. Once the **checkout order** is created, the next step is to **submit the user's card details**. The customer enters their card information, which is securely processed for payment authorization. If the card details are submitted successfully, the system triggers an **OTP verification to enhance security**. To proceed, you need to verify the OTP to complete the payment by capturing the customer's OTP input and validating it. If the OTP is incorrect or timeout, provide an option to **resend it for verification**. If the customer prefers, they can choose to **save their card information for future transactions**. Before storing the card details, an additional **OTP verification** is required to ensure security. If the customer consents and the OTP is successfully validated, the card details are securely saved. As an alternative to card payments, customers may opt to use the **Flash account option** for a bank transfer. In this case, the system returns a unique Flash account number that the customer can use to complete the payment via bank transfer. After processing the payment, it is important to verify the transaction status. Use the `orderReference` to check the transaction status. If necessary, **fetch transaction details** from the system to provide real-time updates to the customer. In cases where the customer decides not to proceed, they can choose to **cancel the checkout transaction**. To do this, send a request to the cancellation API to terminate the transaction and prevent further processing. # Verify Transactions Source: https://developer.nomba.com/docs/products/accept-payment/verify-transactions Learn how to verify checkout transactions using the Nomba API Look up a transaction using your order reference or the Nomba transaction ID. Retrieve full checkout order details including card and transfer info. ## Which endpoint should I use? There are two ways to verify a checkout transaction. Choose based on your environment and what you need: | Endpoint | Method | Environment | Use when | | ---------------------------------- | ------ | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `/v1/transactions/accounts/single` | GET | Sandbox + Production | You want to confirm `status: SUCCESS` before delivering value. Works with `orderReference`, `orderId`, `transactionRef`, or `merchantTxRef` as query params. | | `/v1/checkout/transaction` | GET | **Production only** | You need full checkout order details (card info, transfer details, order metadata). | Always verify transactions before providing goods or services to your customer — even if you received a webhook. ## Option 1: Verify via `/v1/transactions/accounts/single` This endpoint works in both sandbox and production. Pass the `orderReference` (the reference you supplied on the order), the `orderId` (the value returned as `orderReference` in the create-order response), or the `transactionRef` (the Nomba transaction ID from the webhook) as a query parameter. The key field to check in the response is `data.status`. A successful payment returns `"status": "SUCCESS"`. ```bash Verify by orderReference theme={null} curl --request GET \ --url 'https://api.nomba.com/v1/transactions/accounts/single?orderReference=90e81e8a-bc14-4ebf-89c0-57da801cca68' \ --header 'Authorization: Bearer ' \ --header 'accountId: ' ``` ```bash Verify by transactionRef theme={null} curl --request GET \ --url 'https://api.nomba.com/v1/transactions/accounts/single?transactionRef=WEB-ONLINE_C-69923-ae0f2688-12b1-45b6-9972-06261aa65ef1' \ --header 'Authorization: Bearer ' \ --header 'accountId: ' ``` ```javascript Node.js theme={null} // Verify by orderReference const orderReference = '90e81e8a-bc14-4ebf-89c0-57da801cca68'; const url = new URL('https://api.nomba.com/v1/transactions/accounts/single'); url.searchParams.set('orderReference', orderReference); const response = await fetch(url.toString(), { headers: { 'Authorization': `Bearer ${accessToken}`, 'accountId': accountId, }, }); const { code, data } = await response.json(); if (code !== '00') throw new Error('Transaction not found'); if (data.status === 'SUCCESS') { // Payment confirmed — deliver goods/services } ``` ```python Python theme={null} import requests order_reference = '90e81e8a-bc14-4ebf-89c0-57da801cca68' response = requests.get( 'https://api.nomba.com/v1/transactions/accounts/single', headers={ 'Authorization': f'Bearer {access_token}', 'accountId': account_id, }, params={'orderReference': order_reference}, ) result = response.json() if result['code'] != '00': raise Exception('Transaction not found') if result['data']['status'] == 'SUCCESS': pass # Payment confirmed — deliver goods/services ``` ```json expandable Response (Success) theme={null} { "code": "00", "description": "SUCCESS", "data": { "id": "WEB-ONLINE_C-69923-ae0f2688-12b1-45b6-9972-06261aa65ef1", "status": "SUCCESS", "amount": "202.8", "fixedCharge": "2.8", "source": "web", "type": "online_checkout", "gatewayMessage": "PAYMENT SUCCESSFUL", "customerBillerId": "7373019705", "timeCreated": "2025-09-26T01:07:02.729Z", "timeUpdated": "2025-09-26T01:07:02.989Z", "walletCurrency": "NGN", "walletBalance": "478.97", "billingVendorReference": "68d5e736e414b032b3******", "paymentVendorReference": "09064525092601065923059812******", "userId": "69923f4d-963f-4a2b-b0f5-4da074d0a461", "onlineCheckoutOrderId": "9adcbf44-8cca-4fc6-b3a7-ac2758******", "onlineCheckoutOrderReference": "90e81e8a-bc14-4ebf-89c0-57da801c******", "onlineCheckoutCurrency": "NGN", "onlineCheckoutCustomerEmail": "make@gmail.com", "currency": "NGN", "onlineCheckoutAmount": "202.8", "onlineCheckoutPaymentMethod": "bank_transfer", "entryType": "CREDIT" } } ``` ```json Response (Failed / Not Found) theme={null} { "code": "01", "description": "Transaction not found", "data": null } ``` For sandbox transactions, use the sandbox base URL: `https://sandbox.nomba.com/v1/transactions/accounts/single`. See [Sandbox Testing](/docs/products/accept-payment/sandbox-testing) for details on looking up sandbox transactions. ## Option 2: Get Checkout Transaction (Production only) This endpoint returns full checkout order details including card information, transfer details, and order metadata. It is useful when you need richer data than the basic transaction lookup provides — for example, to display order details on a receipt page. This endpoint is only available in the **production** environment. For sandbox verification, use `POST /v1/transactions/accounts` with the transaction reference — see [Sandbox Testing](/docs/products/accept-payment/sandbox-testing). To fetch a checkout transaction, send a [GET request](/nomba-api-reference/online-checkout/fetch-checkout-transaction) to this endpoint `/v1/checkout/transaction`. ```bash Request theme={null} curl --request GET \ --url 'https://api.nomba.com/v1/checkout/transaction?idType=ORDER_REFERENCE&id=68da39e0-2ce4-4ea6-9def-5*********' \ --header 'Authorization: Bearer ' \ --header 'accountId: ' ``` ```json Response theme={null} { "code": "00", "description": "Success", "data": { "success": "true", "message": "success", "order": { "orderId": "56e03654-0c32-4d3e-bbd6-a9df22994a12", "orderReference": "90e81e8a-bc14-4ebf-89c0-57da752cca58", "customerId": "762878332454", "accountId": "56e03654-0c32-4d3e-bbd6-a9df22994a12", "callbackUrl": "https://ip:port/merchant.com/callback", "customerEmail": "abcde@gmail.com", "amount": "10000.00", "currency": "NGN" }, "transactionDetails": { "transactionDate": "2023-12-06T15:46:43.000Z", "paymentReference": "5844858382134", "paymentVendorReference": "5844858382675493", "tokenizedCardPayment": "true", "statusCode": "Payment approved" }, "transferDetails": { "sessionId": "67584432178569543", "beneficiaryAccountName": "Tope Fade", "beneficiaryAccountNumber": "5844858382", "originatorAccountName": "Femi Fash", "originatorAccountNumber": "3409082834", "narration": "Checkout payment", "destinationInstitutionCode": "true", "paymentReference": "44384586756" }, "cardDetails": { "cardPan": "515123 **** **** 6667", "cardType": "Verve", "cardCurrency": "NGN", "cardBank": "057" } } } ``` # Virtual accounts Source: https://developer.nomba.com/docs/products/accept-payment/virtual-account Learn about creating virtual accounts Generate a unique account number for your customer to receive payment. Update a customer virtual account name and callback URL record. ## Introduction At Nomba, virtual accounts are part of the broader Accounts system. A virtual account can be created for a customer primarily to receive payments. Once created, Nomba generates a unique account number that customers can use to receive bank transfers. ### Types of accounts Nomba supports the following account types: #### Primary Accounts A primary account is automatically created when you set up your business on Nomba. * This is your main account. * All other accounts (virtual or sub-accounts) are linked to it. #### Virtual accounts Virtual accounts are created via API for receiving payments. Funds received are automatically routed to the parent (primary) account. * Virtual accounts do not hold balances themselves * If required, virtual accounts can be linked to a sub-account instead of the primary account buy adding the `subAccountId` as a path to the [endpoint](/nomba-api-reference/virtual-accounts/create-virtual-account-for-sub-account) * You can view all virtual account transactions on your dashboard. #### Sub-accounts Sub-accounts are created from the Nomba Dashboard * They act as separate “pockets” for managing funds * Useful for segmenting funds across teams, operations, or workflows. See this [guide](/docs/guides/managing-accounts-with-nomba) for more details on managing accounts with Nomba. ### Types of Virtual accounts Nomba supports two types of virtual accounts based on their behavior: #### Static Virtual Accounts Static virtual accounts are permanent account numbers assigned to a customer or business. Use a static virtual account when: * You do not want the account to expire * You want your customers to receive multiple payments over time. **Use cases:** * Assigning a dedicated account number to a customer * Supporting recurring payments * When you need a stable, non-expiring account number #### Dynamic Virtual Accounts Dynamic virtual accounts are temporary, purpose-specific account numbers. * Typically used for one-time or time-bound payments * Can be configured with an `expiryDate` to define validity * Dynamic accounts help reduce reconciliation errors for transaction-specific payments. ## Create a virtual account We recommend testing virtual account creation in the Sandbox environment before going live. * Each user can create a maximum of **2 virtual accounts** * Each account is created with an `expectedAmount` of ₦100 and accepts only that exact amount * Transfers can be made from any Nigerian bank. * You can update the expected amount (up to ₦150) using the `expectedAmount` field. * All transfers will trigger webhooks to the Sandbox webhook URL. * Virtual account expiration is not supported in Sandbox. To create a virtual account, please take note of the optional and required fields: * `accountRef` (required): A unique reference you assign to the virtual account. * `accountName` (required): The name associated with the virtual account. * `currency` (required): Currency for the virtual account, e.g NGN. * `bvn` (optional): If not provided, the virtual account will inherit the BVN of the parent account. Only include this if you want to assign a different BVN. * `nin` (optional): The account holder's National Identification Number, exactly 11 digits. You can send it on its own instead of a `bvn`, or alongside `bvn` to record both. If you send neither, the virtual account inherits the BVN of the parent account as described above. * `expectedAmount` (optional): Restricts the account to accept only the specified amount. This is useful for exact payments such as invoice matching or controlled transfers. When omitted, the account will accept any amount since it is not restricted to a specific value. If a sender transfers an amount different from the expectedAmount: * The transaction may be declined by the sender’s bank, or * Automatically reversed, depending on the bank’s handling logic Be cautious when setting the `expectedAmount`. Once set, the account will **only** accept that exact amount. Payments with any other amount will be rejected. * `expiryDate` (optional): Sets how long the virtual account remains valid, this is useful if you intend to create a dynamic virtual account purposely for time-based transactions. If omitted, the virtual account functions as a static (permanent) account. To create a virtual account, send a [POST request](/nomba-api-reference/virtual-accounts/create-virtual-account) to this endpoint `/v1/accounts/virtual`. ```bash Request theme={null} curl --request POST \ --url https://api.nomba.com/v1/accounts/virtual \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --header 'accountId: ' \ --data '{ "accountRef": "1oWbJQQHLyQ************", "accountName": "Daniel Scorsese", "currency": "NGN", "expiryDate": "2024-06-17 04:55:00", "bvn":"12345678901", "expectedAmount": 5000.00, }' ``` ```json Response theme={null} { "code": "00", "description": "Success", "data": { "createdAt": "2024-10-11T14:15:39.376Z", "accountRef": "1oWbJQQHLyQqqf1SwxjSpudeA2q3", "accountHolderId": "8d19d421-85b1-4b61-be90-168dc261gf45", "accountName": "Femi-Testing", "currency": "NGN", "bankAccountNumber": "91714245345", "bankAccountName": "Femi-Testing/Testing mike", "bankName": "Amucha MFB", "bvn": "22122204392", "identifierType": "BVN", "expiryDate": "2024-10-12T12:30:49", "expired": false } } ``` ### Test the account in the Sandbox To confirm the account works, send ₦100 to the `bankAccountNumber` returned above, from any Nigerian bank. To test expected amount usecase, update the account with an `expectedAmount` between ₦100 and ₦150, then transfer exactly that amount. ## Suspend a virtual account You cannot suspend a parent account. The parent account is directly tied to your business and always remains active. Only accounts created via the API (i.e., virtual accounts) can be suspended. To suspend a virtual account, send a PUT request with the accountId of the account you want to suspend to `/v1/accounts/suspend/{accountId}` Virtual accounts are the only accounts that can be created via API. ```bash Request theme={null} curl --request PUT \ --url https://api.nomba.com/v1/accounts/suspend/{accountId} \ --header 'Authorization: Bearer ' \ --header 'accountId: ' ``` ```bash Response theme={null} { "code": "00", "description": "Success", "data": true } ``` ## Perform a virtual account lookup You can look up the details of a virtual account using its account number. This is useful for verifying whether an account is still valid, checking expiry status, or retrieving account details before accepting payments. ```bash Request theme={null} curl --request GET \ --url https://api.nomba.com/v1/accounts/virtual/{virtualAcctNumber} \ --header 'Authorization: Bearer ' \ --header 'accountId: ' ``` ```json Response theme={null} { "code": "00", "description": "SUCCESS", "data": { "createdAt": "2025-05-28T08:23:48.073Z", "bankAccountNumber": "", "bankAccountName": "", "bankName": "Nombank MFB", "accountRef": "created-wed-28-05-2501", "accountHolderId": "", "accountName": "", "currency": "NGN", "bvn": "00***", "expired": false }, "message": "SUCCESS", "status": true } ``` **What’s Next?** After creating a virtual account, there are additional actions you may need to perform: * [Expire a virtual account](/nomba-api-reference/virtual-accounts/expire-a-virtual-account) Set a virtual account to expire at a specific time. * [Filter virtual accounts](/nomba-api-reference/virtual-accounts/filter-virtual-accounts) Retrieve a list of accounts that match specific conditions (e g, expired, by customer account name etc). * [Fetch parent account balance](/nomba-api-reference/accounts/fetch-parent-account-details). # Buy Data Bundle Source: https://developer.nomba.com/docs/products/airtime-and-data/buy-data-bundle How to Buy Data Bundle using this API To successfully buy a data bundle using our endpoints, it is necessary to undergo the following steps: 1. Fetch available data plans — this returns a list of available data plans, each with a `productId`. 2. Buy the data bundle, passing the `productId` of the plan you want in the purchase request. `productId` is required. Purchasing by `amount` alone is deprecated and only still works for merchants already integrated against it. All new integrations must select a plan from step 1 and pass its `productId` — this is the only reliable way to get the exact bundle you intended, since more than one plan on the same network can share the same price. # Fetch Data Plans Source: https://developer.nomba.com/docs/products/airtime-and-data/fetch-data-plans Get a list of available data bundles that can be purchased based on the network or telco # `GET /v1/bill/data-plan/` ```bash Request theme={null} curl --location 'https://api.nomba.com/v1/bill/data-plan/' \ --header 'accountId: ' \ --header 'Authorization: Bearer ' ``` ```json Example Response theme={null} { "data": [ { "plan": "20MB -> 1Day (N50)", "amount": 50, "productId": "example-plan-id-1" }, { "plan": "75MB -> 1Day (N100)", "amount": 100, "productId": "example-plan-id-2" }, { "plan": "200MB -> 3Days (N200)", "amount": 200, "productId": "example-plan-id-3" }, { "plan": "350MB -> 7Days (N300)", "amount": 300, "productId": "example-plan-id-4" }, { "plan": "750MB -> 14Days (N500)", "amount": 500, "productId": "example-plan-id-5" }, { "plan": "1.5GB -> 30Days (N1,000)", "amount": 1000, "productId": "example-plan-id-6" }, { "plan": "3.5GB -> 30Days (N1,500)", "amount": 1500, "productId": "example-plan-id-7" }, { "plan": "5.5GB -> 30Days (N2,500)", "amount": 2500, "productId": "example-plan-id-8" }, { "plan": "6.5GB -> 30Days (N3,000)", "amount": 3000, "productId": "example-plan-id-9" }, { "plan": "9.5GB -> 30Days (N4,000)", "amount": 4000, "productId": "example-plan-id-10" }, { "plan": "12GB -> 30Days (N5,000)", "amount": 5000, "productId": "example-plan-id-11" }, { "plan": "25GB -> 30Days (N10,000)", "amount": 10000, "productId": "example-plan-id-12" }, { "plan": "40GB -> 30Days (N15,000)", "amount": 15000, "productId": "example-plan-id-13" } ], "description": "Successful", "code": 200 } ``` The plans, amounts, and `productId`s above are **illustrative only** — they do not represent real, current plans. This catalog can change at any time (and today is not the same source of truth used internally, so it may drift further as that changes). Never hardcode plan data from this example: always call this endpoint live and use the `productId` it returns in your purchase request. #### Path parameters Telco i.e. network provider for the data plan to be purchased. Typically mtn, airtel, glo or 9mobile #### Response body Response code Response description List of available data plans for the telco supplied The corresponding amount for this plan Plan name The unique identifier for this data plan. Pass this value as `productId` in the [Buy Data Bundle](/nomba-api-reference/airtime-and-data-vending/vend-data-bundles-via-parent-account) request to purchase this exact bundle. # Vend Airtime Source: https://developer.nomba.com/docs/products/airtime-and-data/vend-airtime How to vend Airtime using this API # `POST /v1/bill/topup` ```bash Request theme={null} curl --location 'https://api.nomba.com/v1/bill/topup' \ --header 'accountId: ' \ --header 'Authorization: Bearer ' \ --data '{ "amount": 50, "phoneNumber": "08012345678", "network": "MTN", "merchantTxRef": "test1116", "senderName": "Testing" }' ``` ```json Response theme={null} { "code": "202", "description": "Processing...", "data": { "amount": "50", "meta": { "merchantTxRef": "test1116", "rrn": "240626232937" }, "timeCreated": "2024-06-26T22:29:37.649Z", "type": "topup", "status": "Processing..." } } ``` #### Request body Amount Phone number of the user who is to receive the value Network (e.g. MTN, AIRTEL, GLO, 9MOBILE, etc) Merchant Transaction Reference (a unique reference to identify this transaction on your system) #### Response body Response code Response description Amount Merchant Transaction Reference Retrieval Reference Number (RRN) Date and Time of the transaction The type of this transaction. This is most probably topup in this case # Fetch Betting Providers Source: https://developer.nomba.com/docs/products/bills/fetch-betting-providers Get a list of the available plans from a provider. ## `GET /v1/bill/betting/providers` #### Response body Response code Response description Response message List of available subscription plans The corresponding id for this provider The pretty name for this provider ```bash Request theme={null} curl --location GET \ --url https://api.nomba.com/v1/bill/betting/providers \ --header 'Authorization: Bearer ' \ --header 'accountId: ' ``` ```json Success response theme={null} { "code": "00", "description": "SUCCESS", "data": [ { "lookup_id": "BET9JA", "amount": "", "name": "BET9JA", "biller_id": "bet9ja", "id": "bet9ja" }, { "lookup_id": "BET_1960BET", "amount": "", "name": "1960Bet", "biller_id": "1960bet", "id": "1960bet" } ], "message": "SUCCESS" } ``` # Fetch Cable TV Plans Source: https://developer.nomba.com/docs/products/bills/fetch-cable-tv-plans Get a list of the available plans from a provider. ## `GET /v1/bill/cableTvProduct?cableTvType=dstv` Available Cable TV type: 1. dstv 2. gotv 3. startimes 4. ShowMax #### Response body Response code Response description Response message List of available subscription plans The subscription plan type (e.g., COMPACT, PREMIUM) The amount for the subscription plan ```bash Request theme={null} curl --location 'https://api.nomba.com/v1/bill/cableTvProduct?cableTvType=dstv' \ --header 'Authorization: Bearer ' \ --header 'accountId: ' ``` ```json Success response theme={null} { "code": "00", "description": "SUCCESS", "data": [ { "subScriptionType": "COMPACT", "amount": 19000.0 }, { "subScriptionType": "COMPACT_PLUS", "amount": 30000.0 }, { "subScriptionType": "PREMIUM", "amount": 44500.0 }, { "subScriptionType": "COMPACT_PLUS_EXTRA_VIEW", "amount": 36000.0 }, { "subScriptionType": "PREMIUM_EXTRA_VIEW", "amount": 50500.0 }, { "subScriptionType": "COMPACT_EXTRA_VIEW", "amount": 25000.0 }, { "subScriptionType": "YANGA", "amount": 6000.0 }, { "subScriptionType": "CONFAM", "amount": 11000.0 }, { "subScriptionType": "PADI", "amount": 4400.0 }, { "subScriptionType": "CONFAM_PLUS_EXTRA_VIEW", "amount": 17000.0 }, { "subScriptionType": "YANGA_PLUS_EXTRA_VIEW", "amount": 12000.0 }, { "subScriptionType": "PADI_PLUS_EXTRA_VIEW", "amount": 10400.0 } ], "message": "SUCCESS" } ``` # Fetch Electricity Providers (Discos) Source: https://developer.nomba.com/docs/products/bills/fetch-electricity-providers Get a list of the available electricity providers ## `GET /v1/bill/electricity/discos` #### Response body Response code Response description List of available electricity providers The corresponding id for this provider The pretty name for this provider ```bash Request theme={null} curl --location 'https://api.nomba.com/v1/bill/electricity/discos' \ --header 'accountId: ' \ --header 'Authorization: ' ``` ```json Success response theme={null} { "code": "00", "description": "SUCCESS", "data": [ { "id": "phed", "name": "Port Harcourt (PHED)" }, { "id": "jed", "name": "Jos Electric (JEDC)" }, { "id": "kaduna", "name": "Kaduna Electric (KAEDCO)" }, { "id": "ibedc", "name": "Ibadan Electric (IBEDC)" }, { "id": "eko", "name": "Eko Electric (EKEDC)" }, { "id": "benin", "name": "Benin Electric (BEDC)" }, { "id": "abuja", "name": "Abuja Electric (AEDC)" }, { "id": "kano", "name": "Kano Electric (KEDCO)" }, { "id": "ikeja", "name": "Ikeja Electric (IKEDC)" }, { "id": "enugu", "name": "Enugu Electric (EEDC)" } ] } ``` # Get customer information for a betting payment Source: https://developer.nomba.com/docs/products/bills/name-lookup-for-betting Describes how to get the information of a betting vendor's customer # `GET /v1/bill/betting/lookup` #### Query parameters The code name of the betting provider as gotten when the list of betting providers is fetched e.g. bet9ja The unique identifier of the customer on the provider's platform #### Response body Response code Response description Data containing customer's name if present Response message ```bash Request theme={null} curl --location GET \ --url https://api.nomba.com/v1/bill/betting/lookup \ --header 'accountId: ' \ --header 'Authorization: ' ``` ```json Success response theme={null} { "code": "00", "description": "SUCCESS", "data": "John Doe", "message": "SUCCESS" } ``` # Get customer information from a cable tv provider Source: https://developer.nomba.com/docs/products/bills/name-lookup-for-cabletv Describes how to get the information of a cable tv customer # `GET /v1/bill/cabletv/lookup` #### Query parameters The identifier of the customer The type of the cable tv provider (typically dstv or gotv) #### Response body Response code Response description Data containing customer's name if present ```bash Request theme={null} curl --location 'https://api.nomba.com/v1/bill/cabletv/lookup' \ --header 'accountId: ' \ --header 'Authorization: ' ``` ```json Success response theme={null} { "code": "00", "description": "SUCCESS", "data": "John Doe" } ``` # Get customer information for an electricity payment Source: https://developer.nomba.com/docs/products/bills/name-lookup-for-electricity Describes how to get the information of an electricity vendor's customer # `GET /v1/bill/electricity/lookup` #### Query parameters The code name of the electricity provider as gotten when the list of discos is fetched e.g. phed The unique identifier of the customer on the provider's platform #### Response body Response code Response description Data containing customer's name if present Response message ```bash Request theme={null} curl --location 'https://api.nomba.com/v1/bill/electricity/lookup' \ --header 'accountId: ' \ --header 'Authorization: ' ``` ```json Success response theme={null} { "code": "00", "description": "SUCCESS", "data": "John Doe" } ``` # Pay for Betting Source: https://developer.nomba.com/docs/products/bills/pay-for-betting This describes the process of paying for betting # `POST /v1/bill/betting` #### Request body Amount Betting provider's id (e.g. bet9ja, betKing, scratch2win etc) - This id can be gotten from doing a fetch of available providers Merchant Transaction Reference (a unique reference to identify this transaction on your system) The name of the person to be attached to this transaction An unique id to identify the customer to which this payment belongs. This should be same as verified in the lookup api The phone number of the person to be attached to this transaction #### Response body Response code Response description Amount Merchant Transaction Reference Retrieval Reference Number (RRN) Date and Time of the transaction The type of this transaction. This is most probably phcn in this case The status of this transaction ```bash Request theme={null} curl --location POST \ --url https://api.nomba.com/v1/bill/betting \ --header 'accountId: ' \ --header 'Authorization: Bearer ' \ --data '{ "bettingProvider": "bet9ja", "merchantTxRef": "c006475e-a76f-4533-b2ff-59a67d5e6241", "phoneNumber":"09012345678", "payerName": "John Doe", "amount": 2000, "customerId": "1234567890" }' ``` ```json Success response theme={null} { "code": "00", "description": "SUCCESS", "data": { "amount": 2000, "meta": { "merchantTxRef": "c006475e-a76f-4533-b2ff-59a67d5e6241", "api_client_id": "10422171-9100-4e66-93e1-7f6da894ef89", "api_account_id": "01a10aeb-d989-460a-bbde-9842f2b4320f", "rrn": "240809060134" }, "fee": "", "timeCreated": "2024-08-09T05:01:35.014Z", "id": "API-BETTING-4B8C8-dcc5994c-e110-4035-9017-fc6e497a3baa", "type": "betting", "status": "SUCCESS" } } ``` # Pay for Electricity Source: https://developer.nomba.com/docs/products/bills/pay-for-electricity This describes the process of paying for electricity # `POST /v1/bill/electricity` #### Request body Amount Electricity provider's id (e.g. phed, jed, ibedc etc) - This id can be gotten from doing a fetch of available providers Merchant Transaction Reference (a unique reference to identify this transaction on your system) The name of the person to be attached to this transaction An unique id to identify the customer to which this payment belongs The meter type to of the meter for which this payment is for. Usually PREPAID or POSTPAID #### Response body Response code Response description Amount Merchant Transaction Reference Electricity Units Meter Name Customer's Address Meter Token Prepaid or Postpaid Retrieval Reference Number (RRN) Date and Time of the transaction The type of this transaction. This is most probably phcn in this case The status of this transaction ```bash Request theme={null} curl --location 'https://api.nomba.com/v1/bill/electricity' \ --header 'accountId: ' \ --header 'Authorization: Bearer ' \ --data '{ "disco": "phcn", "merchantTxRef": "c006475e-a76f-4533-b2ff-59a67d5e6241", "payerName": "John Doe", "amount": 2000, "customerId": "1234567890", "meterType": "PREPAID" }' ``` ```json Success response theme={null} { "code": "00", "description": "SUCCESS", "data": { "amount": 2000, "meta": { "merchantTxRef": "c006475e-a76f-4533-b2ff-59a67d5e6241", "phcnCustomerAddress": "52, Ajose Street", "phcnVendUnits": "23.5", "phcnVendToken": "12345678909876543212", "meterName": "John Doe", "meterType": "PREPAID", "api_client_id": "10422171-9100-4e66-93e1-7f6da894ef89", "api_account_id": "01a10aeb-d989-460a-bbde-9842f2b4320f", "rrn": "240809060134" }, "fee": "", "timeCreated": "2026-02-06T05:01:35.014Z", "id": "API-PHCN-4B8C8-dcc5994c-e110-4035-9017-fc6e497a3baa", "type": "phcn", "status": "SUCCESS" } } ``` # Subscribe to Cable TV Source: https://developer.nomba.com/docs/products/bills/subscribe-to-cable-tv This describes the process of subscribing to a Cable TV network # `POST /v1/bill/cabletv` #### Request body Amount The cable tv provider name id usually dstv or gotv Merchant Transaction Reference (a unique reference to identify this transaction on your system) The name of the person to be attached to this transaction An unique id to identify the customer to which this payment belongs #### Response body Response code Response description Amount Merchant Transaction Reference Retrieval Reference Number (RRN) Date and Time of the transaction The type of this transaction. The status of this transaction ```bash Request theme={null} curl --location 'https://api.nomba.com/v1/bill/cabletv' \ --header 'accountId: ' \ --header 'Authorization: Bearer ' \ --data '{ "cableTvType": "dstv", "merchantTxRef": "{{$guid}}", "payerName": "{{$randomFullName}}", "amount": 2000, "customerId": "123909200" }' ``` ```json Success response theme={null} { "code": "00", "description": "SUCCESS", "data": { "amount": 2000, "meta": { "merchantTxRef": "bf6cd7cc-5952-4e66-abff-64032ce1a73a", "api_client_id": "10422171-9100-4e66-93e1-7f6da894ef89", "api_account_id": "01a10aeb-d989-460a-bbde-9842f2b4320f", "rrn": "240803091832" }, "fee": "", "timeCreated": "2024-08-03T08:18:34.201Z", "id": "API-DSTV-C1073-2d10909a-df07-4e95-9851-e5ebd5695040", "type": "dstv", "status": "SUCCESS" } } ``` # Fetch DRC Inflow Providers Source: https://developer.nomba.com/docs/products/global-collections/fetch-drc-inflow-providers List the mobile money providers available for DRC mobile money collections # `GET /v1/global-collection/drc/inflow/providers` Returns the list of mobile money providers supported for DRC inflow. Call this endpoint to discover which providers are available before initiating a collection — use the returned `code` value as the `topupVendor` in the [Initiate Mobile Money Inflow](/docs/products/global-collections/initiate-mobile-money-inflow) request. ```bash Request theme={null} curl --request GET \ --url https://api.nomba.com/v1/global-collection/drc/inflow/providers \ --header 'Authorization: Bearer ' \ --header 'accountId: ' ``` ```json Response theme={null} { "code": "00", "description": "Successful", "data": [ { "code": "MPESA", "displayName": "Mpesa" }, { "code": "AIRTEL", "displayName": "Airtel Money" }, { "code": "ORANGE", "displayName": "Orange Money" } ] } ``` #### Response fields List of mobile money providers available for DRC inflow. The provider code. Pass this value as `topupVendor` when calling [Initiate Mobile Money Inflow](/docs/products/global-collections/initiate-mobile-money-inflow). Human-readable name of the provider (e.g. `Airtel Money`, `Mpesa`). ## Sandbox Use the sandbox endpoint to test provider discovery in your development environment: ```bash Sandbox Request theme={null} curl --request GET \ --url https://api.nomba.com/v1/sandbox/global-collection/drc/inflow/providers \ --header 'Authorization: Bearer ' \ --header 'accountId: ' ``` The sandbox returns the same static list of providers as production. # Fetch Transaction Source: https://developer.nomba.com/docs/products/global-collections/fetch-mobile-money-transaction Retrieve the status of an initiated mobile money collection # `GET /v1/global-collection/transactions/{transactionId}` Retrieve the status of any initiated mobile money transaction. Use this endpoint to confirm whether a collection was successful, pending, or failed — keeping your records accurate and your customers informed. ```bash Request theme={null} curl --request GET \ --url https://api.nomba.com/v1/global-collection/transactions/a822e327-4bcd-40ec-ac61-ed3622eac000 \ --header 'Authorization: Bearer ' \ --header 'accountId: ' ``` ```json Response theme={null} { "code": "00", "description": "Successful", "data": { "transactionId": "a822e327-4bcd-40ec-ac61-ed3622eac000", "coreUserId": "xxxx-xxxx-4402-97c0-6c3824cxxxxx", "account": "0980802918", "status": "SUCCESS", "amount": 10.00, "currency": "CDF", "vendor": "MPESA", "gatewayMessage": "APPROVED", "gatewayCode": "Merchant credited" } } ``` #### Path parameters The `transactionReference` returned when the inflow was initiated. #### Response body The unique collection transaction ID. The Nomba account ID that received the collection. The customer's mobile money account (phone number). Current status of the collection. | Value | Description | | ------------------ | -------------------------------------------------------------------------------------------------------------- | | `PENDING` | Payment prompt sent; awaiting the customer's action. | | `APPROVED` | The charge was approved on the customer's mobile money network. | | `SUCCESS` | The collection completed. | | `FAILED` | The collection did not complete. | | `PENDING_APPROVAL` | No outcome was returned within the polling window, so the collection is unresolved. It can still settle later. | The collected amount. The currency of the collection. The customer's mobile money network, echoing the `topupVendor` you sent. The response from the customer's mobile money network. What that word means, in plain words. | `gatewayMessage` | `gatewayCode` | | ---------------- | -------------------------- | | `ACCEPTED` | Awaiting customer approval | | `APPROVED` | Merchant credited | | `DECLINED` | Payment declined | Those are the three values `gatewayMessage` takes. Anything else leaves `gatewayCode` null. # Initiate Mobile Money Inflow Source: https://developer.nomba.com/docs/products/global-collections/initiate-mobile-money-inflow Trigger a mobile money collection request from a customer # `POST /v1/global-collection/inflow/initiate` Trigger a mobile money collection from your customer. This endpoint initiates an inflow request through the supported mobile money flow, prompting the customer to complete the payment on their end. ```bash Request theme={null} curl --request POST \ --url https://api.nomba.com/v1/global-collection/inflow/initiate \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --header 'accountId: ' \ --data '{ "phoneNumber": "0980802xxx", "callbackUrl": "https://your-server.com/webhook/collection", "amount": 10, "currency": "CDF", "topupVendor": "AIRTEL", "idempotencyKey": "your-unique-key-here" }' ``` ```json Response theme={null} { "code": "00", "description": "Successful", "data": { "transactionReference": "a822e327-4bcd-40ec-ac61-ed3622eac000", "status": "PENDING", "message": "success", "idempotencyKey": "your-unique-key-here" } } ``` #### Idempotency This endpoint supports idempotent requests. You can pass a client-generated `idempotencyKey` in the request body to safely retry a request without risk of duplicate charges. If you omit the key, the server generates a UUID automatically and returns it in the response. Store the `idempotencyKey` from the response and include it on any retry for the same operation. If two requests carrying the same `idempotencyKey` arrive concurrently, the second request receives HTTP 409 with the message "Request with this idempotency key is currently being processed; please retry." #### Errors A rejected initiation returns a non-`00` code with one of these descriptions. | Description | Meaning | What to do | | ------------------------------------------------- | ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | `The phone number is not registered on ` | The number is not on the `topupVendor` you sent. | Send it on the network it belongs to. [Fetch Inflow Providers](/docs/products/global-collections/fetch-drc-inflow-providers) lists the valid values. | | `Failed to initiate mobile money inflow` | The request was rejected for another reason. | Check the request, then retry with a **new** `idempotencyKey`. | | `Please retry later or contact support` | The collection could not be attempted. Nothing was charged. | Retry later with a **new** `idempotencyKey`. | Treat these descriptions as the contract; do not parse anything else out of the response. #### Request body The customer's mobile money phone number. The URL Nomba will POST to when the transaction status changes. Must be publicly accessible. The amount to collect from the customer. ISO 4217 currency code for the collection (e.g., `CDF`). The mobile money network provider (e.g., `AIRTEL`, `MPESA`). A client-generated key used to safely retry the request without risk of duplicate charges. If not provided, the server generates one automatically. #### Response body Unique reference for this collection. Use this with [Fetch Transaction](/docs/products/global-collections/fetch-mobile-money-transaction) to check the status. Initial status of the inflow request (e.g., `PENDING`). A message describing the outcome. The idempotency key used for this request — either the value you provided or a server-generated UUID. Store this and pass it on retry. # Overview Source: https://developer.nomba.com/docs/products/global-collections/introduction Learn how to collect funds from customers across supported mobile money networks with the Nomba DRC Collection API DRC Collection simplifies the process of receiving funds in the DRC, giving you reliable tools to collect money from customers across supported mobile money networks. Whether you're triggering a payment prompt or checking the outcome of a collection, DRC Collection keeps your inflow operations running smoothly. If you want a hosted payment experience instead of a direct collection API, use [Checkout](/docs/products/accept-payment/checkout-overview). Our Checkout solution supports DRC payment methods including Mobile Money in both USD and CDF collections, as well as Apple Pay and International Card for USD collections. ## Quick Actions Trigger a mobile money collection request from your customer. Check the status of an initiated mobile money collection. List the mobile money providers available for DRC inflow to choose the right topupVendor. Use hosted Checkout when you want Nomba to handle the payment page and method selection experience. ## How it works Call the InitiateMobileMoneyInflow endpoint with the customer's phone number, the amount, and a callback URL. This sends a payment prompt to the customer on their mobile money network. The customer approves the payment on their end via their mobile money provider (e.g., M-Pesa, Airtel Money). Nomba sends a webhook event to your callback URL when the transaction status changes. Set up your webhook handler to process the result. Use the FetchMobileMoneyTransaction endpoint with the returned transaction reference to confirm the final status of the collection. ## Reading the outcome A collection is initiated as `PENDING` and settles asynchronously, because the customer still has to approve the charge on their phone. Two fields tell you where it stands. `gatewayMessage` is the response from the customer's mobile money network. `gatewayCode` says what it means: | `gatewayMessage` | `gatewayCode` | | ---------------- | -------------------------- | | `ACCEPTED` | Awaiting customer approval | | `APPROVED` | Merchant credited | | `DECLINED` | Payment declined | See [Fetch Transaction](/docs/products/global-collections/fetch-mobile-money-transaction) for the full field reference. # Authorize Exchange Source: https://developer.nomba.com/docs/products/global-payout/authorize-exchange Transfer funds between your own accounts in different currencies # `POST /v1/global-payout/exchange/authorize` Move funds between your own accounts with ease. AuthExchange is designed for internal transfers, allowing you to shift balances across your accounts in different currencies without the overhead of an external disbursement flow. ```bash Request theme={null} curl --request POST \ --url https://api.nomba.com/v1/global-payout/exchange/authorize \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --header 'accountId: ' \ --data '{ "amount": 1, "sourceCurrency": "USD", "destinationCurrency": "CDF", "senderName": "ADEBUKOLA AKANJI", "receiverName": "ADEBUKOLA AKANJI", "sourceCountryIsoCode": "CD", "destinationCountryIsoCode": "CD", "narration": "Transfer between my accounts" }' ``` ```json Response theme={null} { "code": "00", "description": "Successful", "status": false, "data": { "wtTransactionId": "01kkk8cjk0fpw9jx2n01wd8yfw", "coreTransactionId": "API-P2P-CB9EC-0c2d962e-4730-48e7-b522-d65cac511549", "status": "PROCESSING", "coreStatus": "SUCCESS", "type": "EXCHANGE", "meta": { "wt_transaction_id": "01kkk8cjk0fpw9jx2n01wd8yfw", "source_amount": "1.0", "destination_amount": "2250.0", "source_currency": "USD", "destination_currency": "CDF", "amount_charged": "1.0", "currency_pair_name": "USD/CDF", "destination_country": "CD", "source_country": "CD", "narration": "Transfer between my accounts", "trade_side": "BUY", "spread_amount": "250.0", "spread_currency": "CDF", "transactionCategory": "General" } } } ``` #### Request body Amount to transfer in the source currency. ISO 4217 currency code of the source account (e.g., `USD`). ISO 4217 currency code of the destination account (e.g., `CDF`). Name of the account holder initiating the exchange. Name of the receiving account holder. For own-account exchanges this is typically the same as the sender. ISO 3166-1 alpha-2 country code of the source account (e.g., `CD`). ISO 3166-1 alpha-2 country code of the destination account (e.g., `CD`). Description or memo for the exchange. The `exchangeRateId` from a prior [Fetch Exchange Rates](/docs/products/global-payout/fetch-exchange-rates) call. When provided, the exchange is fulfilled at that exact rate. #### Response body Unique GlobalPayout transaction ID. Use this to track the exchange via [Fetch Transaction](/docs/products/global-payout/fetch-transaction). Internal core transaction reference. Processing status. One of: `PROCESSING`, `COMPLETED`, `FAILED`, `PENDING`. Core system status (e.g., `SUCCESS`). Transaction type. Will be `EXCHANGE` for own-account transfers. Transaction metadata including currency pair details, amounts, and spread info. # Authorize Transfer Source: https://developer.nomba.com/docs/products/global-payout/authorize-transfer Initiate and authorize a cross-border transfer using the Nomba Global Payout API # `POST /v1/global-payout/transfer/authorize` Manage the complete transfer lifecycle with a single endpoint. AuthTransfer walks you through every required step from initiating a transfer to final authorization, ensuring nothing is missed before funds are moved. Before calling this endpoint, use [Fetch Exchange Rates](/docs/products/global-payout/fetch-exchange-rates) for cross-currency transfers, then call [Fetch Payment Methods](/docs/products/global-payout/payment-methods) to get required fields and selectable values for `purposeOfPayment`, `accountType`, and `bankAccountType`. Optionally use [Convert Money](/docs/products/global-payout/convert-money) to calculate the destination amount. To use the rate quoted to your customer, pass the `exchangeRateId` returned by Fetch Exchange Rates as `lockedExchangeRateId` here. ## Payment methods The `paymentMethod` field determines which additional fields are required. Requirements also differ by destination, so the table below is a summary — call [Fetch Payment Methods](/docs/products/global-payout/payment-methods) with `destinationCountryIsoCode` for the exact list your corridor expects. | `paymentMethod` | Required fields | Optional fields | | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | | `BANK` (non-Canada, e.g. DRC) | `accountNumber`, `receiverName`, `institutionName` (bank display name), `institutionCode` (bank code from `/bank/providers`), `accountType` | `narration` | | `BANK` (South Africa) | `accountNumber`, `receiverName`, `institutionCode` (bank code from `/bank/providers`), `institutionName`, `accountType`, `purposeOfPayment`, `beneficiary.beneficiaryAddress`, `beneficiary.beneficiaryCity`, `beneficiary.beneficiaryPostCode` | `beneficiary.beneficiaryState` | | `BANK` (Canada) | `accountNumber`, `receiverName`, `institutionCode` (institution number, 3 digits), `accountType`, `beneficiary.beneficiaryEmail`, `beneficiary.transitNumber` (5 digits), `beneficiary.beneficiaryAddress`, `beneficiary.beneficiaryCity`, `beneficiary.beneficiaryPostCode` | `beneficiary.securityQuestion`, `beneficiary.securityQuestionAnswer`, `beneficiary.beneficiaryState`, `narration` | | `EFT` (Canada) | `accountNumber`, `receiverName`, `institutionCode` (institution number, 3 digits), `accountType`, `beneficiary.beneficiaryEmail`, `beneficiary.transitNumber` (5 digits), `beneficiary.beneficiaryAddress`, `beneficiary.beneficiaryCity`, `beneficiary.beneficiaryPostCode` | `beneficiary.beneficiaryState`, `narration` | | `MobileMoney` | `accountNumber` (recipient phone number), `receiverName`, `institutionName` (provider display name), `accountType` | `narration` | | `INTERAC` | `receiverName`, `accountType`, `beneficiary.beneficiaryEmail` | `beneficiary.securityQuestion`, `beneficiary.securityQuestionAnswer` | | `FASTER_PAYMENTS` | `accountNumber`, `receiverName`, `institutionCode` (sort code, 6 digits), `accountType` | `narration` | | `SEPA` | `accountNumber` (IBAN), `receiverName`, `institutionCode` (SWIFT/BIC), `accountType`, `purposeOfPayment` | `narration` | | `ACH` (United States) | `accountNumber`, `institutionCode`, `institutionName`, `accountType`, `bankAccountType`, `bankAddress`, `bankCity`, `bankState`, `bankZipCode`, `beneficiary`, `purposeOfPayment` | `narration` | | `WIRE` (United States) | `accountNumber`, `institutionName`, `institutionCode`, `accountType`, `bankAccountType`, `beneficiary`, `bankAddress`, `bankCity`, `bankState`, `bankZipCode`, `purposeOfPayment` | `narration` | ```bash MobileMoney (DRC) theme={null} curl --request POST \ --url https://api.nomba.com/v1/global-payout/transfer/authorize \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --header 'accountId: ' \ --data '{ "amount": 250.0, "sourceCurrency": "USD", "destinationCurrency": "USD", "receiverName": "John Cena", "accountNumber": "0903086112", "institutionName": "Mpesa", "sourceCountryIsoCode": "CD", "destinationCountryIsoCode": "CD", "paymentMethod": "MobileMoney", "accountType": "INDIVIDUAL", "narration": "Family support" }' ``` ```bash MobileMoney (Africa) theme={null} curl --request POST \ --url https://api.nomba.com/v1/global-payout/transfer/authorize \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --header 'accountId: ' \ --data '{ "amount": 100.0, "sourceCurrency": "USD", "destinationCurrency": "KES", "receiverName": "Jane Doe", "accountNumber": "0712345678", "institutionName": "M-Pesa", "sourceCountryIsoCode": "NG", "destinationCountryIsoCode": "KE", "paymentMethod": "MobileMoney", "accountType": "INDIVIDUAL", "narration": "Family support" }' ``` ```bash BANK (DRC) theme={null} curl --request POST \ --url https://api.nomba.com/v1/global-payout/transfer/authorize \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --header 'accountId: ' \ --data '{ "amount": 2.0, "sourceCurrency": "USD", "destinationCurrency": "CDF", "accountNumber": "00444555555", "receiverName": "John Doe", "institutionName": "Access Bank", "institutionCode": "access_bank", "sourceCountryIsoCode": "CD", "destinationCountryIsoCode": "CD", "paymentMethod": "Bank", "accountType": "INDIVIDUAL", "narration": "Business payment" }' ``` ```bash INTERAC (Canada) theme={null} curl --request POST \ --url https://api.nomba.com/v1/global-payout/transfer/authorize \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --header 'accountId: ' \ --data '{ "amount": 21.0, "sourceCurrency": "USD", "destinationCurrency": "CAD", "receiverName": "Thomas Doe", "sourceCountryIsoCode": "CD", "destinationCountryIsoCode": "CA", "narration": "Ted", "paymentMethod": "Interac", "accountType": "INDIVIDUAL", "lockedExchangeRateId": "01k7pcakf0t8g03rvny3z5mr1p", "beneficiary": { "beneficiaryEmail": "testtt@yahoo.com", "securityQuestion": "Test", "securityQuestionAnswer": "Test" } }' ``` ```bash BANK (Canada) theme={null} curl --request POST \ --url https://api.nomba.com/v1/global-payout/transfer/authorize \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --header 'accountId: ' \ --data '{ "amount": 2.0, "sourceCurrency": "USD", "destinationCurrency": "CAD", "accountNumber": "234543245433", "receiverName": "Jane Doe", "institutionCode": "34444", "sourceCountryIsoCode": "CD", "destinationCountryIsoCode": "CA", "paymentMethod": "Bank", "accountType": "INDIVIDUAL", "lockedExchangeRateId": "01k7pcakf0t8g03rvny3z5mr1p", "beneficiary": { "beneficiaryEmail": "test@yoop.com", "securityQuestion": "353333" } }' ``` ```bash FASTER_PAYMENTS (UK) theme={null} curl --request POST \ --url https://api.nomba.com/v1/global-payout/transfer/authorize \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --header 'accountId: ' \ --data '{ "amount": 23.0, "sourceCurrency": "USD", "destinationCurrency": "GBP", "accountNumber": "404130729909118", "receiverName": "Ayodeji Abimbola", "institutionCode": "433333", "sourceCountryIsoCode": "CD", "destinationCountryIsoCode": "GB", "narration": "Ted Thomos", "paymentMethod": "FASTER_PAYMENTS", "accountType": "INDIVIDUAL", "lockedExchangeRateId": "01k4a8rfrngw76yfcj3ak1rw71" }' ``` ```bash BANK (South Africa — Individual) theme={null} curl --request POST \ --url https://api.nomba.com/v1/global-payout/transfer/authorize \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --header 'accountId: ' \ --data '{ "amount": 500.0, "sourceCurrency": "USD", "destinationCurrency": "ZAR", "accountNumber": "1234567890", "receiverName": "Jane Doe", "institutionCode": "2763", "institutionName": "Standard Bank", "sourceCountryIsoCode": "NG", "destinationCountryIsoCode": "ZA", "paymentMethod": "Bank", "accountType": "INDIVIDUAL", "purposeOfPayment": "FAMILY_SUPPORT", "beneficiary": { "beneficiaryAddress": "123 Main Street", "beneficiaryCity": "Cape Town", "beneficiaryPostCode": "8001", "beneficiaryState": "Western Cape" } }' ``` ```bash SEPA (Europe) theme={null} curl --request POST \ --url https://api.nomba.com/v1/global-payout/transfer/authorize \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --header 'accountId: ' \ --data '{ "amount": 23.0, "sourceCurrency": "USD", "destinationCurrency": "GBP", "accountNumber": "GB41CLJU04130729909118", "receiverName": "trfff tttt", "institutionCode": "CLJUGB21", "sourceCountryIsoCode": "CD", "destinationCountryIsoCode": "GB", "narration": "Ted", "paymentMethod": "SEPA", "accountType": "INDIVIDUAL", "purposeOfPayment": "MAINTENANCE_EXPENSES", "lockedExchangeRateId": "01k4a8rfrngw76yfcj3ak1rw71" }' ``` ```bash ACH (United States) theme={null} curl --request POST \ --url https://api.nomba.com/v1/global-payout/transfer/authorize \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --header 'accountId: ' \ --data '{ "amount": 40.0, "sourceCurrency": "USD", "destinationCurrency": "USD", "accountNumber": "223456789", "receiverName": "Daniel Brooks", "institutionCode": "021000021", "institutionName": "Chase Bank", "sourceCountryIsoCode": "CD", "destinationCountryIsoCode": "US", "paymentMethod": "ACH", "accountType": "INDIVIDUAL", "bankAccountType": "CHECKING", "bankAddress": "123 Financial Street", "bankCity": "San Francisco", "bankState": "California", "bankZipCode": "94105", "purposeOfPayment": "MAINTENANCE_EXPENSES", "beneficiary": { "beneficiaryAddress": "45 Market Road", "beneficiaryCity": "Austin", "beneficiaryState": "Texas", "beneficiaryPostCode": "78701" } }' ``` ```bash WIRE (United States) theme={null} curl --request POST \ --url https://api.nomba.com/v1/global-payout/transfer/authorize \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --header 'accountId: ' \ --data '{ "amount": 75.0, "sourceCurrency": "USD", "destinationCurrency": "USD", "accountNumber": "987654321", "receiverName": "Morgan Blake", "institutionCode": "026009593", "institutionName": "Bank of America", "sourceCountryIsoCode": "CD", "destinationCountryIsoCode": "US", "paymentMethod": "WIRE", "accountType": "CORPORATE", "bankAccountType": "SAVINGS", "bankAddress": "400 Commerce Avenue", "bankCity": "New York", "bankState": "New York", "bankZipCode": "10001", "purposeOfPayment": "SERVICE_CHARGES", "beneficiary": { "beneficiaryAddress": "10 Business Park", "beneficiaryCity": "Dallas", "beneficiaryState": "Texas", "beneficiaryPostCode": "75201" } }' ``` ```json Response (MobileMoney DRC) theme={null} { "code": "00", "description": "Successful", "status": false, "data": { "wtTransactionId": "01kky197w3xc6wyjenpc5r0tnp", "coreTransactionId": "API-FX_TX_DR-08A1B-6add611a-e538-4e67-bcf9-661c77a16804", "status": "PROCESSING", "coreStatus": "PAYMENT_SUCCESSFUL", "type": "TRANSFER", "meta": { "source_currency": "USD", "destination_country": "CD", "amount_charged": "255.0", "source_amount": "250.0", "wt_transaction_id": "01kky197w3xc6wyjenpc5r0tnp", "spread_currency": "USD", "trade_context": "default", "destination_country_name": "Congo DR", "source_country": "CD", "destination_amount": "250.0", "spread_amount": "0.0", "narration": "Family support", "transactionCategory": "General", "payment_destination_type": "Account", "trade_side": "BUY", "destination_currency": "USD", "currency_pair_name": "USD/USD", "payment_method": "MobileMoney", "tradeType": "FIXED_TRADE" }, "prettyStatus": "Successful" } } ``` The `MobileMoney (Africa)` payload shape applies to all African mobile money corridors. Swap the destination country code, destination currency, account number, and provider `institutionName` for the recipient's market. Supported countries: Ghana (`GH`/`GHS`), Kenya (`KE`/`KES`), Senegal (`SN`/`XOF`), Tanzania (`TZ`/`TZS`), Ethiopia (`ET`/`ETB`), Rwanda (`RW`/`RWF`), Uganda (`UG`/`UGX`), Cameroon (`CM`/`XAF`), Gabon (`GA`/`XAF`), Côte d'Ivoire (`CI`/`XOF`), Niger (`NE`/`XOF`). Call [List Institution Providers](/docs/products/global-payout/mobile-money-providers) with `countryIsoCode` set to the destination country to get valid provider codes. For all mobile money transfers, call [List Institution Providers](/docs/products/global-payout/mobile-money-providers) first to get valid `institutionCode` and `institutionName` values for your destination country. Use `isMobileMoney=true` for mobile money providers and `isMobileMoney=false` for banks. `accountType` is required for Authorize Transfer and must be selected from the `accountTypes` array returned by Fetch Payment Methods. Valid values are `INDIVIDUAL` and `CORPORATE`. ACH supports only `INDIVIDUAL`; WIRE supports `INDIVIDUAL` and `CORPORATE`. `purposeOfPayment` is required for `ACH`, `WIRE`, and `SEPA`. Select it from the `purposeOfPayments` array returned by Fetch Payment Methods; do not send arbitrary text. #### Request body The amount to transfer in the source currency. ISO 4217 currency code of the source account (e.g., `USD`). ISO 4217 currency code of the destination account (e.g., `USD`, `CDF`, `CAD`, `GBP`, `EUR`, `KES`, `ZAR`, `GHS`, `XOF`, `TZS`). Full name of the recipient. ISO 3166-1 alpha-2 country code of the sender (e.g., `CD`). ISO 3166-1 alpha-2 country code of the recipient (e.g., `CD`, `CA`, `GB`, `KE`, `ZA`, `GH`, `SN`, `TZ`). Payment rail to use. One of: `BANK`, `MobileMoney`, `INTERAC`, `FASTER_PAYMENTS`, `SEPA`, `ACH`, `WIRE`. Recipient account number, IBAN, or phone number (for `MobileMoney`). Required for `BANK`, `MobileMoney`, `FASTER_PAYMENTS`, and `SEPA`. Bank or institution routing code. For `BANK` (DRC): bank code from [List Institution Providers](/docs/products/global-payout/mobile-money-providers). For `BANK` (Canada): institution number. For `FASTER_PAYMENTS`: sort code (6 digits). For `SEPA`: SWIFT/BIC code. Bank or provider display name. For `BANK`: the bank display name. For `MobileMoney`: the provider display name (e.g., `Mpesa`). Use the `displayName` from [List Institution Providers](/docs/products/global-payout/mobile-money-providers). Account type of the recipient. Required for Authorize Transfer. Select one of the values returned in `accountTypes` from Fetch Payment Methods. Valid values are `INDIVIDUAL` and `CORPORATE`; ACH supports only `INDIVIDUAL`. Recipient bank account type. Required for `ACH` and `WIRE`. Select one of the values returned in `bankAccountTypes` from Fetch Payment Methods. Valid values are `CHECKING` and `SAVINGS`. Reason for the transfer. Required for `ACH`, `WIRE`, and `SEPA`. Select one of the values returned in `purposeOfPayments` from Fetch Payment Methods; do not send arbitrary text. Description or memo for the transfer. Optional exchange rate ID from [Fetch Exchange Rates](/docs/products/global-payout/fetch-exchange-rates). Use this for the transfer to use the rate quoted to your customer. Bank street address. Required for United States `WIRE`. Bank city. Required for United States `WIRE`. Bank state. Required for United States `WIRE`. Bank ZIP code. Required for United States `WIRE`. Beneficiary details. Required for `INTERAC`; partially required for `BANK` (Canada and South Africa). Recipient email address. Required for `INTERAC` and `BANK` (Canada). Security question for Interac e-Transfer. Answer to the security question. Bank transit number (Canada only). Recipient street address. Required for South Africa. Recipient city. Required for South Africa. Recipient postal code. Required for South Africa. Recipient state or province. Optional. #### Response body Unique GlobalPayout transaction ID. Use this to track the transfer via [Fetch Transaction](/docs/products/global-payout/fetch-transaction). Internal core transaction reference. Processing status. One of: `PROCESSING`, `COMPLETED`, `FAILED`, `PENDING`. Core system status (e.g., `PAYMENT_SUCCESSFUL`). Transaction type. Will be `TRANSFER` for cross-border disbursements. Human-readable status label (e.g., `Successful`, `Processing`). Transaction metadata containing currency details, amounts, and routing info. This is a JSON object — only transaction-relevant fields are present. # Convert Money Source: https://developer.nomba.com/docs/products/global-payout/convert-money Calculate a currency conversion before initiating a transfer # `POST /v1/global-payout/money/convert` When moving funds across currencies, Convert Money calculates the converted amount for you. Call this endpoint when you need to know the destination amount for a source amount before authorizing a transfer. The exchange rate and applicable fees are automatically scoped to the region configured for your authenticated account. ```bash Request theme={null} curl --request POST \ --url https://api.nomba.com/v1/global-payout/money/convert \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --header 'accountId: ' \ --data '{ "amount": 15, "currency": "USD", "destinationCurrency": "EUR", "transactionType": "EXCHANGE" }' ``` ```json Response theme={null} { "code": "00", "description": "Successful", "status": false, "data": { "fromAmount": 15.0, "fromCurrency": "USD", "fromFormatted": "$15.00", "toAmount": 13.04, "toCurrency": "EUR", "toFormatted": "13,04 €", "spreadAmount": 0.12, "spreadCurrency": "EUR", "exchangeRateId": "01kkk4b7rh8pcvtw1s1nxs144s", "currencyPairName": "EUR/USD", "feeAmount": 0.0, "feeCurrency": "USD", "feeExpression": "" } } ``` Convert Money is available only for supported currency corridors. Call [Fetch Exchange Rates](/docs/products/global-payout/fetch-exchange-rates) first to confirm that the pair is available. If a corridor is unavailable, the API returns an error asking you to contact support. #### Request body The amount to convert in the source currency. The ISO 4217 currency code of the source amount (e.g., `USD`). The ISO 4217 currency code to convert into (e.g., `EUR`). The type of transaction. Use `EXCHANGE` for currency conversions. #### Response body The original amount in the source currency. The source currency code. The source amount formatted as a display string (e.g., `$15.00`). The converted amount in the destination currency. The destination currency code. The destination amount formatted as a display string. The spread amount applied to the conversion. The currency the spread is denominated in. The ID of the exchange rate used for this conversion. To have a transfer use the rate quoted to your customer, use the `exchangeRateId` returned by [Fetch Exchange Rates](/docs/products/global-payout/fetch-exchange-rates) as `lockedExchangeRateId` in Authorize Transfer. The currency pair notation (e.g., `EUR/USD`). Any applicable transaction fee. The currency the fee is charged in. # Fetch Exchange Rates Source: https://developer.nomba.com/docs/products/global-payout/fetch-exchange-rates Retrieve the latest exchange rates for a currency pair before initiating a transfer # `GET /v1/global-payout/exchange-rates` Before sending funds in a currency different from your base currency, use this endpoint to retrieve the latest exchange rates. This ensures your customers always see accurate, up-to-date conversion values before a transaction is confirmed. Rates are automatically scoped to the region configured for your authenticated account. ```bash Request theme={null} curl --request GET \ --url 'https://api.nomba.com/v1/global-payout/exchange-rates?from=EUR&to=USD' \ --header 'Authorization: Bearer ' \ --header 'accountId: ' ``` ```json Response theme={null} { "code": "00", "description": "Successful", "status": false, "data": { "rates": [ { "exchangeRateId": "01kkk7pab9mjt70wvk6pzk8mzx", "currencyPairName": "EUR/USD", "bidRate": "$1.13", "askRate": "$1.14", "midRate": "$1.14", "tradeRegion": "", "tradeContext": "", "createdAt": "2026-03-13T09:15:57.161946", "updatedAt": "" } ] } } ``` To have a cross-currency transfer use the rate you quoted to your customer, pass the `exchangeRateId` in the response as `lockedExchangeRateId` in your [Authorize Transfer](/docs/products/global-payout/authorize-transfer) request. #### Query parameters The ISO 4217 currency code to convert from (e.g., `EUR`). The ISO 4217 currency code to convert to (e.g., `USD`). #### Response body A list of exchange rate objects for the requested currency pair. The unique ID of this exchange rate. Pass it as `lockedExchangeRateId` in Authorize Transfer for the transfer to use this rate. The currency pair in standard notation (e.g., `EUR/USD`). The rate at which Nomba buys the base currency. The rate at which Nomba sells the base currency. The mid-market rate between the bid and ask. The timestamp when this rate was recorded. # Fetch Transaction Source: https://developer.nomba.com/docs/products/global-payout/fetch-transaction Track the status of a Global Payout transaction using its transaction ID # `GET /v1/global-payout/transactions/{transactionId}` Track the status of any transaction at any point in its lifecycle. FetchTransaction takes a transaction reference and returns its current state, giving you and your customers full visibility into where funds are at any given time. ```bash Request theme={null} curl --request GET \ --url https://api.nomba.com/v1/global-payout/transactions/01kj9ssfwqd4a97jhdx65gmyqy \ --header 'Authorization: Bearer ' \ --header 'accountId: ' ``` ```json Response theme={null} { "code": "00", "description": "Successful", "status": false, "data": { "transactionId": "01kj9ssfwqd4a97jhdx65gmyqy", "status": "PROCESSING", "coreStatus": "PAYMENT_SUCCESSFUL", "type": "TRANSFER", "createdAt": "2026-03-13T09:15:57.161946" } } ``` #### Path parameters The `wtTransactionId` returned when the transfer or exchange was authorized. #### Response body The GlobalPayout transaction ID. Current processing status of the transaction. | Value | Description | | ------------ | --------------------------------------------- | | `PROCESSING` | The transfer is being processed. | | `COMPLETED` | The transfer has been successfully delivered. | | `FAILED` | The transfer could not be completed. | | `PENDING` | The transfer is awaiting further action. | Core system status (e.g., `PAYMENT_SUCCESSFUL`). Transaction type — `TRANSFER` or `EXCHANGE`. ISO 8601 timestamp of when the transaction was created. # Overview Source: https://developer.nomba.com/docs/products/global-payout/introduction Learn how to process cross-border fund disbursements with the Nomba Global Payout API GlobalPayout enables cross-border fund disbursements, giving you full control over international transfers from initiation to completion. ## Quick Actions Initiate and authorize an international transfer end-to-end. Convert funds between currencies before disbursement. Get the latest exchange rates for a currency pair. Track the status of any global payout transaction. Transfer funds between your own accounts in different currencies. Retrieve available banks and mobile money providers for your destination country. ## How it works For cross-currency transfers, call the exchange rates endpoint to show your customer the current rate before they confirm the transfer. Call `GET /v1/global-payout/payment-methods` to see the available payment rails and the corridors each one serves. Call it again with `destinationCountryIsoCode` to get that corridor's exact required fields and selectable values such as `purposeOfPayment`, `accountType`, and `bankAccountType` — requirements differ by destination, so a corridor-specific call is what tells you exactly what to send. Submit the recipient details, payment method, source and destination currencies, and any required fields returned by Fetch Payment Methods. Use the FetchTransaction endpoint with the returned `wtTransactionId` to poll for the current status of the transfer at any point in its lifecycle. Convert Money is optional. Use it to calculate the destination amount for a source amount. For a cross-currency transfer, pass the `exchangeRateId` returned by Fetch Exchange Rates as `lockedExchangeRateId` in the Authorize Transfer request so the transfer uses the rate you quoted to your customer. # Institution Providers Source: https://developer.nomba.com/docs/products/global-payout/mobile-money-providers Retrieve available banks and mobile money providers for Global Payout transfers # `GET /v1/global-payout/bank/providers` Returns available bank, institution, or mobile money providers. Use the `isMobileMoney` query parameter to switch between bank/institution and mobile money listings. Use the `code` from the response as `institutionCode` and `displayName` as `institutionName` in the [Authorize Transfer](/docs/products/global-payout/authorize-transfer) request. #### Query parameters `false` returns bank or institution providers. `true` returns mobile money providers. ISO 3166-1 alpha-2 destination country code (e.g., `KE`, `ZA`, `GH`, `ET`, `RW`). When provided, takes priority over the region derived from your JWT. Use this when your platform supports multiple destination countries — pass the recipient's country code to get the correct provider list. ```bash Institutions (isMobileMoney=false) theme={null} curl --request GET \ --url 'https://api.nomba.com/v1/global-payout/bank/providers?countryIsoCode=US&isMobileMoney=false' \ --header 'Authorization: Bearer ' \ --header 'accountId: ' ``` ```bash Mobile Money (isMobileMoney=true) theme={null} curl --request GET \ --url 'https://api.nomba.com/v1/global-payout/bank/providers?isMobileMoney=true' \ --header 'Authorization: Bearer ' \ --header 'accountId: ' ``` ```json Response — Institutions theme={null} { "code": "00", "description": "Success", "status": false, "data": [ { "code": "access_bank", "displayName": "Access Bank" }, { "code": "bank_of_africa", "displayName": "Bank Of Africa" }, { "code": "eco_bank", "displayName": "Eco Bank" }, { "code": "equity_bank", "displayName": "Equity Bank" }, { "code": "raw_bank", "displayName": "Raw Bank" }, { "code": "uba", "displayName": "United Bank of Africa" } ] } ``` ```json Response — Institution Providers (Mobile Money) theme={null} { "code": "00", "description": "Success", "status": false, "data": [ { "code": "nomba", "displayName": "Nomba" }, { "code": "airtel", "displayName": "Airtel Money" }, { "code": "mpesa", "displayName": "Mpesa" }, { "code": "orange", "displayName": "Orange" } ] } ``` Always pass `countryIsoCode` when calling this endpoint. Multiple countries share the same currency (e.g., XOF covers Senegal and Côte d'Ivoire; XAF covers Cameroon and Gabon) — the country code is how the API returns the correct provider list for your destination. `code` from this endpoint → `institutionCode` in the transfer request. `displayName` → `institutionName`. ## Providers by Country | Country | ISO Code | Currency | Institution Providers | | ------------- | -------- | --------- | ------------------------------------- | | DR Congo | CD | USD / CDF | Nomba, Airtel Money, M-Pesa, Orange | | Kenya | KE | KES | M-Pesa | | Ghana | GH | GHS | MTN Mobile Money | | South Africa | ZA | ZAR | Bank only — use `isMobileMoney=false` | | Senegal | SN | XOF | Orange Money, Wave | | Côte d'Ivoire | CI | XOF | Orange Money, MTN, Moov, Wave | | Ethiopia | ET | ETB | Safaricom M-Pesa, Ethio Telecom | | Rwanda | RW | RWF | MTN Mobile Money, Airtel Money | | Uganda | UG | UGX | MTN Mobile Money, Airtel Money | | Cameroon | CM | XAF | MTN Mobile Money, Orange Money | | Gabon | GA | XAF | Airtel Money, Moov | | UAE | AE | AED | Bank only — use `isMobileMoney=false` | Provider codes (`institutionCode`) and display names (`institutionName`) returned by this endpoint are the canonical values — always call the API rather than hardcoding them, as they may be updated. #### Response body List of available institutions. The institution code. Use this as `institutionCode` in the [Authorize Transfer](/docs/products/global-payout/authorize-transfer) request. Human-readable institution name. Use this as `institutionName` in the [Authorize Transfer](/docs/products/global-payout/authorize-transfer) request. # Fetch Payment Methods Source: https://developer.nomba.com/docs/products/global-payout/payment-methods Retrieve supported payment methods and method-specific requirements # `GET /v1/global-payout/payment-methods` Returns the payment methods available to you and, for a given corridor, the exact fields an [Authorize Transfer](/docs/products/global-payout/authorize-transfer) request must carry. A payment method's requirements depend on where you are sending to. The same method carries different fields in different corridors — SEPA requires an `institutionCode` in some destinations and not others, and a Canadian bank payout needs routing details a European one does not. The endpoint therefore answers in two ways. **Without a destination country**, it returns the catalogue: which methods exist, and the corridors each one serves. Only the fields that apply to every request are listed. **With `destinationCountryIsoCode`**, it returns that corridor's exact `requiredFields` and `optionalFields`. Start with the catalogue to discover a method and its corridors, then call again with `destinationCountryIsoCode` (and `destinationCurrency` where a country supports more than one) to get the fields you must send. #### Query parameters Optional destination country ISO code, for example `CA`. Supply it to receive that corridor's method-specific `requiredFields` and `optionalFields`. Omit it to receive the catalogue. Optional destination currency code, for example `CAD`. Use it where a country supports more than one currency and the requirements differ between them. Without it, a method configured for several currencies in that country is returned once per currency. Optional payment method code. Use this to retrieve a specific method, for example `EFT`. Optional payment method name. Use this to retrieve a specific method, for example `BANK` or `Wire Transfer`. Supported method codes are `BANK`, `MobileMoney`, `INTERAC`, `FASTER_PAYMENTS`, `SEPA`, `ACH`, `EFT`, and `WIRE`. A method appears only where it is active for at least one corridor. Transaction limits and delivery timelines are documented on the [Supported Countries](/docs/products/global-payout/supported-countries) page — they are not part of this response. ```bash Catalogue request theme={null} curl --request GET \ --url https://api.nomba.com/v1/global-payout/payment-methods \ --header 'Authorization: Bearer ' \ --header 'accountId: ' ``` ```json Catalogue response theme={null} { "code": "00", "description": "Success", "status": true, "data": [ { "code": "BANK", "displayName": "Bank Transfer", "purposeOfPaymentRequired": false, "purposeOfPayments": [], "requiredFields": [ "amount", "sourceCurrency", "destinationCurrency", "receiverName", "sourceCountryIsoCode", "destinationCountryIsoCode", "paymentMethod", "accountType" ], "optionalFields": ["narration", "lockedExchangeRateId"], "accountTypes": [], "bankAccountTypes": [], "supportedCorridors": [ { "countryIsoCode": "ZA", "currency": "ZAR" }, { "countryIsoCode": "AE", "currency": "AED" }, { "countryIsoCode": "CA", "currency": "CAD" } ] }, { "code": "EFT", "displayName": "EFT", "purposeOfPaymentRequired": false, "purposeOfPayments": [], "requiredFields": [ "amount", "sourceCurrency", "destinationCurrency", "receiverName", "sourceCountryIsoCode", "destinationCountryIsoCode", "paymentMethod", "accountType" ], "optionalFields": ["narration", "lockedExchangeRateId"], "accountTypes": [], "bankAccountTypes": [], "supportedCorridors": [{ "countryIsoCode": "CA", "currency": "CAD" }] } ] } ``` ```bash Corridor request theme={null} curl --request GET \ --url 'https://api.nomba.com/v1/global-payout/payment-methods?destinationCountryIsoCode=CA&destinationCurrency=CAD' \ --header 'Authorization: Bearer ' \ --header 'accountId: ' ``` ```json Corridor response theme={null} { "code": "00", "description": "Success", "status": true, "data": [ { "code": "EFT", "displayName": "EFT", "purposeOfPaymentRequired": false, "purposeOfPayments": [], "requiredFields": [ "amount", "sourceCurrency", "destinationCurrency", "receiverName", "sourceCountryIsoCode", "destinationCountryIsoCode", "paymentMethod", "accountType", "accountNumber", "institutionCode", "beneficiary.beneficiaryEmail", "beneficiary.transitNumber", "beneficiary.beneficiaryAddress", "beneficiary.beneficiaryCity", "beneficiary.beneficiaryPostCode" ], "optionalFields": [ "narration", "lockedExchangeRateId", "beneficiary.beneficiaryState" ], "accountTypes": ["CORPORATE", "INDIVIDUAL"], "bankAccountTypes": [], "supportedCorridors": [{ "countryIsoCode": "CA", "currency": "CAD" }] }, { "code": "INTERAC", "displayName": "Interac", "purposeOfPaymentRequired": false, "purposeOfPayments": [], "requiredFields": [ "amount", "sourceCurrency", "destinationCurrency", "receiverName", "sourceCountryIsoCode", "destinationCountryIsoCode", "paymentMethod", "accountType", "beneficiary.beneficiaryEmail", "beneficiary.beneficiaryAddress", "beneficiary.beneficiaryCity", "beneficiary.beneficiaryPostCode" ], "optionalFields": [ "narration", "lockedExchangeRateId", "beneficiary.securityQuestion", "beneficiary.securityQuestionAnswer", "beneficiary.beneficiaryState" ], "accountTypes": ["CORPORATE", "INDIVIDUAL"], "bankAccountTypes": [], "supportedCorridors": [{ "countryIsoCode": "CA", "currency": "CAD" }] } ] } ``` ```bash Filter by code theme={null} curl --request GET \ --url 'https://api.nomba.com/v1/global-payout/payment-methods?code=ACH&destinationCountryIsoCode=US' \ --header 'Authorization: Bearer ' \ --header 'accountId: ' ``` ```bash Filter by display name theme={null} curl --request GET \ --url 'https://api.nomba.com/v1/global-payout/payment-methods?name=Wire%20Transfer' \ --header 'Authorization: Bearer ' \ --header 'accountId: ' ``` #### Reading the field names `requiredFields` and `optionalFields` name fields on the [Authorize Transfer](/docs/products/global-payout/authorize-transfer) request body. A dotted name is a nested field: `beneficiary.transitNumber` means `transitNumber` inside the `beneficiary` object. ```json theme={null} { "amount": 5000, "paymentMethod": "EFT", "receiverName": "Jane Doe", "accountNumber": "1234567", "institutionCode": "001", "beneficiary": { "beneficiaryEmail": "jane@example.com", "transitNumber": "12345" } } ``` #### Response body List of payment methods. On a corridor request, a method configured for more than one currency in that country appears once per currency; `supportedCorridors` identifies which. The payment method code. Use this as the `paymentMethod` value in the [Authorize Transfer](/docs/products/global-payout/authorize-transfer) request. Human-readable label suitable for displaying in a UI selector. Indicates whether `purposeOfPayment` is required for this payment method in this corridor. Selectable purpose-of-payment values, each an object with a `code` and a `displayName`. When `purposeOfPaymentRequired` is `true`, send one of the `code` values as `purposeOfPayment`. Empty on the catalogue response. Fields that must be included when authorizing a transfer with this payment method. On the catalogue response this lists only the fields every request carries; call with `destinationCountryIsoCode` for the method-specific ones. Fields that may be included but are not required. Selectable `accountType` values for this payment method. Empty on the catalogue response. Selectable `bankAccountType` values for this payment method. Empty where the method does not use one. The corridors this entry covers. On the catalogue response, every corridor the method is available in — use these to decide which `destinationCountryIsoCode` and `destinationCurrency` to request next. On a corridor response, the single corridor the entry describes. Destination country ISO code, for example `CA`. Destination currency code, for example `CAD`. # Supported Countries Source: https://developer.nomba.com/docs/products/global-payout/supported-countries View all destination countries, payment methods, limits, and delivery timelines supported by the Nomba Global Payout API Global Payout supports cross-border fund disbursements to a growing list of countries. Each destination has specific payment methods, currency options, transaction limits, and processing timelines. Review the table below before initiating a transfer to ensure the corridor you need is available. For the complete list of supported European Countries refer to the [Supported Countries sheet](https://docs.google.com/spreadsheets/d/1HigahLa7eTfDbFJfgkSyiy3y2FZG4JFK0cL19ZInU9Q/edit?gid=0#gid=0). ## Supported Destinations | Destination Country | ISO Code | Destination Currency | Payment Methods | | ------------------- | -------- | -------------------- | ------------------ | | United States | US | USD | ACH, Wire Transfer | ### Detailed corridor limits | Destination Country | Destination Currency | Payment Method | Minimum | Maximum | Delivery Timeline | | ---------------------------- | -------------------- | --------------- | --------- | --------------- | ------------------------------------------------------ | | Democratic Republic of Congo | USD | Mobile Money | \$1 | \$2,500 | Instant | | Democratic Republic of Congo | USD | Bank | \$1 | \$500,000 | Same day, subject to cut-off at 5pm (UTC +1) | | Democratic Republic of Congo | CDF | Mobile Money | FC 1 | FC 7,500,000 | Instant | | Democratic Republic of Congo | CDF | Bank | FC 3,000 | FC 22,000,000 | Same day, subject to cut-off at 5pm (UTC +1) | | United Arab Emirates | AED | Bank | AED 1 | AED 100,000 | Instant | | South Africa | ZAR | Bank | ZAR 20 | ZAR 1,800,000 | T+1, cut-off at 15:30 (Africa/Johannesburg GMT+02:00). | | Ghana | GHS | Mobile Money | GHS 20 | GHS 15,000 | Instant | | Kenya | KES | Mobile Money | KES 20 | KES 250,000 | Instant | | Senegal | XOF | Mobile Money | XOF 100 | XOF 200,000 | Instant | | Tanzania | TZS | Mobile Money | TZS 100 | TZS 3,000,000 | Instant | | Côte d'Ivoire | XOF | Mobile Money | XOF 100 | XOF 2,000,000 | Instant | | Ethiopia | ETB | Mobile Money | ETB 200 | ETB 50,000 | Instant | | Rwanda | RWF | Mobile Money | RWF 100 | RWF 10,000,000 | Instant | | Uganda | UGX | Mobile Money | UGX 5,500 | UGX 5,000,000 | Instant | | Cameroon | XAF | Mobile Money | XAF 100 | XAF 1,000,000 | Instant | | Gabon | XAF | Mobile Money | XAF 200 | XAF 500,000 | Instant | | Niger | XOF | Mobile Money | XOF 500 | XOF 500,000,000 | Instant | | Canada | CAD | Bank | \$1 | \$25,000 | Processed within 1 to 3 business days | | Canada | CAD | Interac | \$1 | \$25,000 | Instant | | United Kingdom | GBP | Faster Payments | £1 | £1,000,000 | Processed within 1 to 3 hours | | Europe | EUR | SEPA | €1 | €100,000 | Processed within 1 hour | ## Using Exchange Rates Before initiating any cross-currency transfer, use the [Fetch Exchange Rates](/docs/products/global-payout/fetch-exchange-rates) endpoint to get the latest rates for your currency pair. This ensures your customers see accurate conversion values before confirming a transaction. Exchange rates are published periodically by the system. To guarantee that the rate shown to your customer is the exact rate used to fulfil the transaction, pass the `exchangeRateId` returned from the Fetch Exchange Rates response as the `lockedExchangeRateId` field in your Authorize Transfer request. This locks the rate at 5 minutes time and prevents any rate movement from affecting the transaction. ``` Fetch Exchange Rates → receive exchangeRateId → pass as lockedExchangeRateId in Authorize Transfer ``` ## Need Help? If you need a country or corridor that isn't listed, reach out to [transactiondesk@nomba.com](mailto:transactiondesk@nomba.com). # Assigning terminals Source: https://developer.nomba.com/docs/products/terminals/assigning-terminals Learn how to assign terminals to accounts # `POST /v1/terminals/assign` ```bash Request theme={null} curl --request POST \ --url https://api.nomba.com/v1/terminals/assign \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --header 'accountId: ' \ --data '{ "serialNumber": "55555555", "terminalLabel": "Testing" }' ``` ```json Success response theme={null} { "code": "00", "description": "Success", "data": { "terminalId": "201124LM", "serialNumber": "55555555", "accountId": "01a10aeb-d989-460a-bbde-9842f2b4320f", "parentAccountId": "", "merchantName": "trident and rees", "terminalLabel": "Testing", "createdAt": "2020-09-23T10:21:48.789Z", "updatedAt": "2023-09-04T15:23:55.173Z" } } ``` #### Request body Terminal serial number. Terminal label. #### Response body Response code Response description Terminal ID. Serial number. Account ID. Parent account ID. Merchant name. Terminal label. Creation timestamp. Update timestamp. # Introduction Source: https://developer.nomba.com/docs/products/terminals/custom-apps/introduction Build custom apps on Nomba terminals ## Overview Nomba empowers its customers with the capability to build and integrate their applications seamlessly onto the Nomba Android terminals. This opens up a realm of possibilities, allowing businesses to customize their operational processes and enhance functionalities. ## NombaX Application The NombaX application, seamlessly integrated into all Nomba Android terminals, assumes a pivotal role in orchestrating the entire operational process across these terminals. Its responsibilities encompass tasks ranging from device monitoring to facilitating payment acceptance. Engaging with the NombaX application involves initiating an intent that precisely defines the action you intend to execute on the terminal. All Nomba Android terminals run a specific version of the NombaX application. Ensure that your terminal is running the most recent version of the NombaX application, which currently stands at `v1.7.9` ## Quick Guides Learn how to receive card payments from your customers Learn how to receive transfer payments from your customers Learn how to customize receipts with the terminal's printer. ## To enable payment acceptance on terminals, your app triggers an intent, empowering the terminal to handle transactions and seamlessly relay the response to your application. Beyond payment acceptance, various other actions can be initiated, such as printing or retrieving device information. We have curated some comprehensive guides that illustrates the step-by-step process of effectively interacting with the NombaX application. This not only enhances the scope of operations but also provides a robust framework for executing diverse actions tailored to your application's requirements. # Retrieve device info Source: https://developer.nomba.com/docs/products/terminals/custom-apps/retrieve-device-info Learn how to retrieve terminal specific details from your custom application The aim of this document is to assist you in retrieving device information from your custom application running on the Nomba Android terminal. If you encounter any difficulties with this process, feel free to [reach out for support.](/support/reach-out) Retrieve device info - available since NombaX Application `v1.6.2` This following code snippet serves as a foundation for retrieving device information on the Nomba terminal. ```kotlin retrieve_device_info.kt theme={null} import android.app.Activity; import android.content.Intent; import androidx.activity.result.ActivityResultContracts; import androidx.activity.result.ActivityResultLauncher; import androidx.lifecycle.MutableLiveData; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; const val TERMINAL_ID = "terminalId" const val SERIAL_NO = "serialNo" const val DEVICE_INFO_ARGUMENTS = "deviceInfoArguments" const val DEVICE_INFO_RESULT = "deviceInfoResult" const val DEVICE_INFO_INTENT = "com.nomba.pro.feature.device_setup.ACTION_VIEW" val resultString = mutableStateOf("") var deviceInfoResult = HashMap() val gson = GsonBuilder() .setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE) .create() //setup a launcher that would help launch the intent var deviceInfoResultLauncher = registerForActivityResult( ActivityResultContracts .StartActivityForResult() ) { result -> val data: Intent? = result.data if (result.resultCode == Activity.RESULT_OK) { val type = object : TypeToken>() {}.type val resultJson = data?.getStringExtra(DEVICE_INFO_RESULT) deviceInfoResult = gson.fromJson(resultJson, type) val terminalId = deviceInfoResult[TERMINAL_ID] val serialNo = deviceInfoResult[SERIAL_NO] resultString.value = "Terminal Id: $terminalId Serial No: $serialNo" } } //setup an intent to be triggered val intent = Intent(DEVICE_INFO_INTENT) //pass the terminalId and serialNo as extra data intent.putExtra(DEVICE_INFO_ARGUMENTS, "$TERMINAL_ID,$SERIAL_NO") //launch the intent deviceInfoResultLauncher.launch(intent) ``` ```java retrieve_device_info.java theme={null} import android.app.Activity; import android.content.Intent; import java.lang.reflect.Type; import java.util.HashMap; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; public static final String TERMINAL_ID = "terminalId"; public static final String SERIAL_NO = "serialNo"; public static final String DEVICE_INFO_ARGUMENTS = "deviceInfoArguments"; public static final String DEVICE_INFO_RESULT = "deviceInfoResult"; public static final String DEVICE_INFO_INTENT = "com.nomba.pro.feature.device_setup.ACTION_VIEW"; // Assuming you have a mutable state variable similar to mutableStateOf in Java private MutableLiveData resultString = new MutableLiveData<>(); private HashMap deviceInfoResult = new HashMap<>(); private Gson gson = new GsonBuilder() .setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE) .create(); // Setup a launcher that would help launch the intent ActivityResultLauncher deviceInfoResultLauncher = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), result -> { Intent data = result.getData(); if (result.getResultCode() == Activity.RESULT_OK) { Type type = new TypeToken>() {}.getType(); String resultJson = data.getStringExtra(DEVICE_INFO_RESULT); deviceInfoResult = gson.fromJson(resultJson, type); String terminalId = deviceInfoResult.get(TERMINAL_ID); String serialNo = deviceInfoResult.get(SERIAL_NO); resultString.setValue("Terminal Id: " + terminalId + " Serial No: " + serialNo); } } ); // Setup an intent to be triggered Intent intent = new Intent(DEVICE_INFO_INTENT); // Pass the terminalId and serialNo as extra data intent.putExtra(DEVICE_INFO_ARGUMENTS, TERMINAL_ID + "," + SERIAL_NO); // Launch the intent deviceInfoResultLauncher.launch(intent); ``` Your resultString should look like; ``` Terminal Id: 2KUD4AKB Serial No: 1234567890 ``` # Introduction Source: https://developer.nomba.com/docs/products/terminals/custom-apps/trigger-payment/introduction Learn how to receive either card or bank transfer payments from your customers The aim of this document is to assist you in initiating payment acceptance from your custom application running on the Nomba Android terminal. If you encounter any difficulties with this process, feel free to [reach out for support.](/support/reach-out) Trigger payments - available since NombaX Application `v1.6.2` This following code snippet serves as a foundation for triggering payment events on the Nomba terminal. Adjustments to the amount, transaction reference, and other parameters can be easily made based on specific application requirements. ```kotlin trigger_payment.kt theme={null} const val PAYMENT_OPTION_INTENT = "com.nomba.pro.feature.payment_option.ACTION_VIEW" const val AMOUNT_DATA = "amount" const val MERCHANT_TX_REF = "merchantTxRef" const val TXN_RESULT = "txnResultData" const val RECEIPT_OPTIONS = "receiptOptions" const val ARGS_PAYMENT_OPTION_STATE = "ARGS_PAYMENT_OPTION_STATE" const val SDK_PAYMENT_OPTIONS = "SDK_PAYMENT_OPTIONS" val resultString = mutableStateOf("") //setup a launcher that would help launch the intent var paymentOptionLauncher = registerForActivityResult( ActivityResultContracts .StartActivityForResult() ) { result -> val data: Intent? = result.data if (result.resultCode == Activity.RESULT_OK) { resultString.value = data?.getStringExtra(TXN_RESULT) ?: "null" } } //setup an intent to be triggered val intent = Intent(PAYMENT_OPTION_INTENT) //put the amount to be charged intent.putExtra(AMOUNT_DATA, "300") //tie a reference to the payment intent.putExtra(MERCHANT_TX_REF, "1234567890") //handle receipt medium val receiptOptionsMap = hashMapOf( "print" to true, "sms" to false, "email" to false ) val receiptOptionsString = Json.encodeToString(serializer>(), receiptOptionsMap) intent.putExtra(RECEIPT_OPTIONS, receiptOptionsString) //add extras intent.putExtra(ARGS_PAYMENT_OPTION_STATE, SDK_PAYMENT_OPTIONS) //launch the intent paymentOptionLauncher.launch(intent) ``` ```java trigger_payment.java theme={null} public static final String PAYMENT_OPTION_INTENT = "com.nomba.pro.feature.payment_option.ACTION_VIEW"; public static final String AMOUNT_DATA = "amount"; public static final String MERCHANT_TX_REF = "merchantTxRef"; public static final String TXN_RESULT = "txnResultData"; public static final String RECEIPT_OPTIONS = "receiptOptions"; public static final String ARGS_PAYMENT_OPTION_STATE = "ARGS_PAYMENT_OPTION_STATE"; public static final String SDK_PAYMENT_OPTIONS = "SDK_PAYMENT_OPTIONS"; // Assuming you have a mutable state variable similar to mutableStateOf in Java private MutableLiveData resultString = new MutableLiveData<>(); // Setup a launcher that would help launch the intent ActivityResultLauncher paymentOptionLauncher = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), result -> { Intent data = result.getData(); if (result.getResultCode() == Activity.RESULT_OK) { resultString.setValue(data.getStringExtra(TXN_RESULT)); } } ); // Setup an intent to be triggered Intent intent = new Intent(PAYMENT_OPTION_INTENT); // Put the amount to be charged intent.putExtra(AMOUNT_DATA, "300"); // Tie a reference to the payment intent.putExtra(MERCHANT_TX_REF, "1234567890"); //handle receipt medium HashMap receiptOptionsMap = new HashMap<>(); receiptOptionsMap.put("print", true); receiptOptionsMap.put("sms", false); receiptOptionsMap.put("email", false); String receiptOptionsString = Json.encodeToString(serializer(HashMap.class, Boolean.class), receiptOptionsMap); intent.putExtra(RECEIPT_OPTIONS, receiptOptionsString); //add extras intent.putExtra(ARGS_PAYMENT_OPTION_STATE, SDK_PAYMENT_OPTIONS); // Launch the intent paymentOptionLauncher.launch(intent); ``` Please ensure to pass the amount as `kobo` i.e. `200` will charge your customer `NGN 2.00` Your resultString should look like; ``` { responseCode=00, responseCodeMeaning="Completed successfully", terminalId="2KUD2XFU", rrn="240117080003", formattedAmountString="₦3.00", txnType="PURCHASE", dateTime="2024-01-17 8:00:03", cardPan="559441******5882", stan="575780", expiryDate="2606", cardName="00002220", merchantName="Etrack Systems", providerTid="2KUD2XFU", cardScheme="Debit Mastercard" } ``` Please note that the following details will make reference to the kotlin code snippet #### Constants | | Description | | ----------------------- | ---------------------------------------------------------------------------------------------------- | | `PAYMENT_OPTION_INTENT` | Defines the action string for the intent, indicating the type of action to be performed. | | `AMOUNT_DATA` | Represents the key for passing the amount to be charged during the payment process. | | `MERCHANT_TX_REF` | Represents the key for tying a reference to the payment, often used for tracking and record-keeping. | | `TXN_RESULT` | Represents the key for extracting transaction result data from the intent. | #### State Variable | | Description | | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | | `resultString` | A mutable state variable initialized as an empty string, which is intended to store the transaction result received from the launched intent. | #### Intent Setup | | Description | | -------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | | `val intent = Intent(PAYMENT_OPTION_INTENT)` | Creates an instance of Intent with the specified action `PAYMENT_OPTION_INTENT`. | | `intent.putExtra(AMOUNT_DATA, "300")` | Adds extra data to the intent, including the amount to be charged `AMOUNT_DATA` and a reference to the payment `MERCHANT_TX_REF`. | #### Launching the intent | | Description | | -------------------------------------- | ----------------------------------------------------------------------------------------------- | | `paymentOptionLauncher.launch(intent)` | Initiates the intent, triggering the Android system to display the payment options to the user. | #### Result Handling Inside the result callback, the code retrieves the transaction result from the received intent and updates the `resultString` variable. # Trigger bank transfer payments Source: https://developer.nomba.com/docs/products/terminals/custom-apps/trigger-payment/trigger-bank-transfer-payments Learn how to receive bank transfer payments from your customers The aim of this document is to assist you in initiating bank transfer payment from your custom application running on the Nomba Android terminal. If you encounter any difficulties with this process, feel free to [reach out for support.](/support/reach-out) Trigger bank transfer payments - available since NombaX Application `v1.6.2` This following code snippet serves as a foundation for triggering bank transfer payment events on the Nomba terminal. Adjustments to the amount, transaction reference, and other parameters can be easily made based on specific application requirements. ```kotlin trigger_bank transfer_payment.kt theme={null} const val PAY_BY_TRANSFER_INTENT = "com.nomba.pro.feature.pay_by_transfer.ACTION_VIEW" const val AMOUNT_DATA = "amount" const val TXN_RESULT = "txnResultData" const val RECEIPT_OPTIONS = "receiptOptions" val resultString = mutableStateOf("") //setup a launcher that would help launch the intent var payByTransferLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> val data: Intent? = result.data if (result.resultCode == Activity.RESULT_OK) { resultString.value = data?.getStringExtra(TXN_RESULT) ?: "null" } } //setup an intent to be triggered val intent = Intent(PAY_BY_TRANSFER_INTENT) //put the amount to be charged intent.putExtra(AMOUNT_DATA, "300") //handle receipt medium val receiptOptionsMap = hashMapOf( "print" to true, "sms" to false, "email" to false ) val receiptOptionsString = Json.encodeToString(serializer>(), receiptOptionsMap) intent.putExtra(RECEIPT_OPTIONS, receiptOptionsString) //launch the intent payByTransferLauncher.launch(intent) ``` ```java trigger_bank_transfer_payment.java theme={null} public static final String PAY_BY_TRANSFER_INTENT = "com.nomba.pro.feature.pay_by_transfer.ACTION_VIEW"; public static final String AMOUNT_DATA = "amount"; public static final String TXN_RESULT = "txnResultData"; public static final String RECEIPT_OPTIONS = "receiptOptions"; // Assuming you have a mutable state variable similar to mutableStateOf in Java private MutableLiveData resultString = new MutableLiveData<>(); // Setup a launcher that would help launch the intent ActivityResultLauncher payByTransferLauncher = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), result -> { Intent data = result.getData(); if (result.getResultCode() == Activity.RESULT_OK) { resultString.setValue(data.getStringExtra(TXN_RESULT)); } } ); // Setup an intent to be triggered Intent intent = new Intent(PAY_BY_TRANSFER_INTENT); // Put the amount to be charged intent.putExtra(AMOUNT_DATA, "300"); //handle receipt medium HashMap receiptOptionsMap = new HashMap<>(); receiptOptionsMap.put("print", true); receiptOptionsMap.put("sms", false); receiptOptionsMap.put("email", false); String receiptOptionsString = Json.encodeToString(serializer(HashMap.class, Boolean.class), receiptOptionsMap); intent.putExtra(RECEIPT_OPTIONS, receiptOptionsString); // Launch the intent payByTransferLauncher.launch(intent); ``` Please note that the following details will make reference to the kotlin code snippet #### Constants | | Description | | ------------------------ | ---------------------------------------------------------------------------------------- | | `PAY_BY_TRANSFER_INTENT` | Defines the action string for the intent, indicating the type of action to be performed. | | `AMOUNT_DATA` | Represents the key for passing the amount to be charged during the payment process. | | `TXN_RESULT` | Represents the key for extracting transaction result data from the intent. | #### State Variable | | Description | | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | | `resultString` | A mutable state variable initialized as an empty string, which is intended to store the transaction result received from the launched intent. | #### Intent Setup | | Description | | --------------------------------------------- | --------------------------------------------------------------------------------- | | `val intent = Intent(PAY_BY_TRANSFER_INTENT)` | Creates an instance of Intent with the specified action `PAY_BY_TRANSFER_INTENT`. | | `intent.putExtra(AMOUNT_DATA, "300")` | Adds extra data to the intent, including the amount to be charged `AMOUNT_DATA`. | #### Launching the intent | | Description | | -------------------------------------- | ----------------------------------------------------------------------------------------------- | | `payByTransferLauncher.launch(intent)` | Initiates the intent, triggering the Android system to display the payment options to the user. | #### Result Handling Inside the result callback, the code retrieves the transaction result from the received intent and updates the `resultString` variable. # Trigger card payments Source: https://developer.nomba.com/docs/products/terminals/custom-apps/trigger-payment/trigger-card-payment Learn how to receive card payments from your customers The aim of this document is to assist you in initiating card payment acceptance from your custom application running on the Nomba Android terminal. If you encounter any difficulties with this process, feel free to [reach out for support.](/support/reach-out) Trigger card payments - available since NombaX Application `v1.6.0` This following code snippet serves as a foundation for triggering card payment events on the Nomba terminal. Adjustments to the amount, transaction reference, and other parameters can be easily made based on specific application requirements. ```kotlin trigger_card_payment.kt theme={null} const val PAYMENT_OPTION_INTENT = "com.nomba.pro.feature.payment_option.ACTION_VIEW" const val AMOUNT_DATA = "amount" const val MERCHANT_TX_REF = "merchantTxRef" const val TXN_RESULT = "txnResultData" const val RECEIPT_OPTIONS = "receiptOptions" val resultString = mutableStateOf("") //setup a launcher that would help launch the intent var paymentOptionLauncher = registerForActivityResult( ActivityResultContracts .StartActivityForResult() ) { result -> val data: Intent? = result.data if (result.resultCode == Activity.RESULT_OK) { resultString.value = data?.getStringExtra(TXN_RESULT) ?: "null" } } //setup an intent to be triggered val intent = Intent(PAYMENT_OPTION_INTENT) //put the amount to be charged intent.putExtra(AMOUNT_DATA, "300") //tie a reference to the payment intent.putExtra(MERCHANT_TX_REF, "1234567890") //handle receipt medium val receiptOptionsMap = hashMapOf( "print" to true, "sms" to false, "email" to false ) val receiptOptionsString = Json.encodeToString(serializer>(), receiptOptionsMap) intent.putExtra(RECEIPT_OPTIONS, receiptOptionsString) //launch the intent paymentOptionLauncher.launch(intent) ``` ```java trigger_card_payment.java theme={null} public static final String PAYMENT_OPTION_INTENT = "com.nomba.pro.feature.payment_option.ACTION_VIEW"; public static final String AMOUNT_DATA = "amount"; public static final String MERCHANT_TX_REF = "merchantTxRef"; public static final String TXN_RESULT = "txnResultData"; public static final String RECEIPT_OPTIONS = "receiptOptions"; // Assuming you have a mutable state variable similar to mutableStateOf in Java private MutableLiveData resultString = new MutableLiveData<>(); // Setup a launcher that would help launch the intent ActivityResultLauncher paymentOptionLauncher = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), result -> { Intent data = result.getData(); if (result.getResultCode() == Activity.RESULT_OK) { resultString.setValue(data.getStringExtra(TXN_RESULT)); } } ); // Setup an intent to be triggered Intent intent = new Intent(PAYMENT_OPTION_INTENT); // Put the amount to be charged intent.putExtra(AMOUNT_DATA, "300"); // Tie a reference to the payment intent.putExtra(MERCHANT_TX_REF, "1234567890"); //handle receipt medium HashMap receiptOptionsMap = new HashMap<>(); receiptOptionsMap.put("print", true); receiptOptionsMap.put("sms", false); receiptOptionsMap.put("email", false); String receiptOptionsString = Json.encodeToString(serializer(HashMap.class, Boolean.class), receiptOptionsMap); intent.putExtra(RECEIPT_OPTIONS, receiptOptionsString); // Launch the intent paymentOptionLauncher.launch(intent); ``` Please ensure to pass the amount as `kobo` i.e. `200` will charge your customer `NGN 2.00` The result of your payment action would be similar to this structure. We’ve migrated from using hash maps to json strings for more flexibility and usage. ```bash expandable theme={null} { "transactionResultType": "CARD_TRANSACTION", "statusCode": "00", "statusCodeMeaning": "Completed successfully", "tid": "2UP1N329", "rrn": "250917135704", "amountString": "₦1.00", "amountHeldString": "", "txnType": "PURCHASE", "dateTime": "17 Sep 25 | 01:57 PM", "cardPan": "537010******4203", "stan": "161681", "expiryDate": "2709", "cardName": "DAMILOLA/ADEKUNLE", "merchantName": "Etrack Systems", "providerTid": "2KUD2XFU", "cardScheme": "Debit MasterCard", "waiterName": "", "tipAmount": "", "paymentOptionState": "SDK_PAYMENT_OPTIONS", "transactionRef": "", "internationalChargeAmount": "", "internationalChargeFee": "", "internationalChargeFeePercent": "", "loyaltyPointDiscount": 0.0, "amountPaid": 0.0, "loyaltyPointEarned": 0, "bookingId": "", "orderId": "", "responseCode": "00", "responseMessage": "Completed successfully" } ``` This an old sample of payment actions using an hash map to represent the result. Kindly update your implementation if you’re running on v1.9.x+. ```bash expandable theme={null} { responseCode=00, responseCodeMeaning="Completed successfully", terminalId="2KUD2XFU", rrn="240117080003", formattedAmountString="₦3.00", txnType="PURCHASE", dateTime="2024-01-17 8:00:03", cardPan="559441******5882", stan="575780", expiryDate="2606", cardName="00002220", merchantName="Etrack Systems", providerTid="2KUD2XFU", cardScheme="Debit Mastercard" } ``` Please note that the following details will make reference to the kotlin code snippet #### Constants | | Description | | ----------------------- | ---------------------------------------------------------------------------------------------------- | | `PAYMENT_OPTION_INTENT` | Defines the action string for the intent, indicating the type of action to be performed. | | `AMOUNT_DATA` | Represents the key for passing the amount to be charged during the payment process. | | `MERCHANT_TX_REF` | Represents the key for tying a reference to the payment, often used for tracking and record-keeping. | | `TXN_RESULT` | Represents the key for extracting transaction result data from the intent. | #### State Variable | | Description | | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | | `resultString` | A mutable state variable initialized as an empty string, which is intended to store the transaction result received from the launched intent. | #### Intent Setup | | Description | | -------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | | `val intent = Intent(PAYMENT_OPTION_INTENT)` | Creates an instance of Intent with the specified action `PAYMENT_OPTION_INTENT`. | | `intent.putExtra(AMOUNT_DATA, "300")` | Adds extra data to the intent, including the amount to be charged `AMOUNT_DATA` and a reference to the payment `MERCHANT_TX_REF`. | #### Launching the intent | | Description | | -------------------------------------- | ----------------------------------------------------------------------------------------------- | | `paymentOptionLauncher.launch(intent)` | Initiates the intent, triggering the Android system to display the payment options to the user. | #### Result Handling Inside the result callback, the code retrieves the transaction result from the received intent and updates the `resultString` variable. # Trigger receipt printing Source: https://developer.nomba.com/docs/products/terminals/custom-apps/trigger-receipt-printing Learn how to trigger receipt printing from your custom application The aim of this document is to assist you in triggering receipt printing from your custom application running on the Nomba Android terminal. If you encounter any difficulties with this process, feel free to [reach out for support.](/support/reach-out) Trigger receipt printing - available since NombaX Application `v1.6.2` Please note the the Nomba Pro terminals do not come with a built-in printer, but they can be connected to any Bluetooth printer. To establish a Bluetooth connection, you need to grant the permissions `ACCESS_FINE_LOCATION_PERMISSION` and `ACCESS_COARSE_LOCATION_PERMISSION`. Please make sure to grant these permissions before testing on the Nomba Pro. Currently, the NombaX application parses an Arraylist of HashMaps to print receipts. The HashMap is to be structured as follows Currently, the NombaX application parses an Arraylist of HashMaps to print receipts. The HashMap is to be structured as follows ```kotlin snippet.kt theme={null} import android.content.Context import android.graphics.Bitmap import android.os.Bundle import android.util.Log import androidx.annotation.DrawableRes import androidx.core.content.ContextCompat import androidx.core.graphics.drawable.toBitmap // Constants const val ARGS_PRINT_DATA = "args_print_data" const val ARGS_PRINT_BITMAP_DATA = "args_print_bitmap_data" fun main() { // For Image/Icon (i.e, Logo) val logoMap: HashMap = hashMapOf() logoMap["content"] = "imageBitmap" logoMap["contentType"] = "IMAGE" logoMap["alignment"] = "CENTER | LEFT | RIGHT" val textMap: HashMap = hashMapOf() // For Text textMap["content"] = "text" textMap["contentType"] = "TEXT" textMap["alignment"] = "CENTER | LEFT | RIGHT" textMap["fontSize"] = "NORMAL | LARGE | SMALL | BIG | BIG2 | BIG3 | BIG4 | BIG5 | BIG6 | TALL | WIDE" textMap["isBold"] = true // or false // Create an ArrayList of the above maps val dataList = ArrayList>() // Add the maps to the ArrayList dataList.add(logoMap) dataList.add(textMap) // Create a bundle to be packaged with the intent val bundle = Bundle() // Pass the ArrayList to the intent bundle.putSerializable(ARGS_PRINT_DATA, dataList) // Convert drawable of your logo to bitmap val bitmap = convertDrawableResToBitmap(context, R.drawable.nombalogo) // Pass the bitmap to the intent bundle.putParcelable(ARGS_PRINT_BITMAP_DATA, bitmap) } // Convert drawable resource to bitmap fun convertDrawableResToBitmap(context: Context, @DrawableRes drawableRes: Int): Bitmap? { return ContextCompat.getDrawable(context, drawableRes)?.toBitmap() } ``` ```java snippet.java theme={null} import android.content.Context; import android.graphics.Bitmap; import android.os.Bundle; import androidx.annotation.DrawableRes; import androidx.core.content.ContextCompat; import androidx.core.graphics.drawable.BitmapDrawableCompat; import java.util.ArrayList; import java.util.HashMap; // Constants public class YourClass { public static final String ARGS_PRINT_DATA = "args_print_data"; public static final String ARGS_PRINT_BITMAP_DATA = "args_print_bitmap_data"; public static void main(String[] args) { // For Image/Icon (i.e, Logo) HashMap logoMap = new HashMap<>(); logoMap.put("content", "imageBitmap"); logoMap.put("contentType", "IMAGE"); logoMap.put("alignment", "CENTER | LEFT | RIGHT"); HashMap textMap = new HashMap<>(); // For Text textMap.put("content", "text"); textMap.put("contentType", "TEXT"); textMap.put("alignment", "CENTER | LEFT | RIGHT"); textMap.put("fontSize", "NORMAL | LARGE | SMALL | BIG | BIG2 | BIG3 | BIG4 | BIG5 | BIG6 | TALL | WIDE"); textMap.put("isBold", true); // or false // Create an ArrayList of the above maps ArrayList> dataList = new ArrayList<>(); // Add the maps to the ArrayList dataList.add(logoMap); dataList.add(textMap); // Create a bundle to be packaged with the intent Bundle bundle = new Bundle(); // Pass the ArrayList to the intent bundle.putSerializable(ARGS_PRINT_DATA, dataList); // Convert drawable of your logo to bitmap Bitmap bitmap = convertDrawableResToBitmap(context, R.drawable.nombalogo); // Pass the bitmap to the intent bundle.putParcelable(ARGS_PRINT_BITMAP_DATA, bitmap); } // Convert drawable resource to bitmap private static Bitmap convertDrawableResToBitmap(Context context, @DrawableRes int drawableRes) { return BitmapDrawableCompat.create(context.getResources(), context.getDrawable(drawableRes), null).getBitmap(); } } ``` Please follow the code below to see how to customise the receipt before you release them to be printed out. ```kotlin snippet.kt theme={null} import android.content.Context import android.content.Intent import android.graphics.Bitmap import android.os.Bundle import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult import androidx.activity.result.ActivityResultLauncher import androidx.compose.runtime.mutableStateOf import androidx.core.content.ContextCompat import androidx.core.graphics.drawable.toBitmap const val PRINT_REQUEST_CODE = 100 const val ARGS_PRINT_DATA = "ARGS_PRINT_DATA" const val ARGS_PRINT_BITMAP_DATA = "ARGS_PRINT_BITMAP_DATA" const val PRINT_RESULT = "PRINT_RESULT" const val ARGS_PRINT_RECEIPT_EVENT = 1944 const val PRINT_RECEIPT_INTENT = "com.nomba.pro.core.print_receipt.ACTION_VIEW" val resultString = mutableStateOf("") //setup a launcher that would help launch the intent var printReceiptLauncher = registerForActivityResult( ActivityResultContracts .StartActivityForResult() ) { result -> val data: Intent? = result.data if (result.resultCode == ARGS_PRINT_RECEIPT_EVENT) { resultString.value = data?.getStringExtra(PRINT_RESULT) } } fun sampleReceipt(): ArrayList> { val dataList = ArrayList>() val imageData: HashMap = hashMapOf() imageData["content"] = "imageBitmap" imageData["contentType"] = "IMAGE" imageData["alignment"] = "CENTER" dataList.add(imageData) //----------------------------------------------------------- val reprintText: HashMap = hashMapOf() reprintText["content"] = "REPRINT" reprintText["contentType"] = "TEXT" reprintText["alignment"] = "CENTER" reprintText["fontSize"] = "NORMAL" dataList.add(reprintText) //----------------------------------------------------------- val merchantCopy: HashMap = hashMapOf() merchantCopy["content"] = "MERCHANT COPY" merchantCopy["contentType"] = "TEXT" merchantCopy["alignment"] = "CENTER" merchantCopy["fontSize"] = "NORMAL" dataList.add(merchantCopy) //----------------------------------------------------------- val merchantName: HashMap = hashMapOf() merchantName["content"] = "MERCHANT NAME: The Horseman" merchantName["contentType"] = "TEXT" merchantName["alignment"] = "LEFT" merchantName["fontSize"] = "NORMAL" dataList.add(merchantName) //----------------------------------------------------------- val terminalId: HashMap = hashMapOf() terminalId["content"] = "TERMINAL ID: 2044RMCY" terminalId["contentType"] = "TEXT" terminalId["alignment"] = "LEFT" terminalId["fontSize"] = "NORMAL" dataList.add(terminalId) //----------------------------------------------------------- val txnType: HashMap = hashMapOf() txnType["content"] = "CARD PAYMENT" txnType["contentType"] = "TEXT" txnType["alignment"] = "CENTER" txnType["fontSize"] = "LARGE" txnType["isBold"] = true dataList.add(txnType) //----------------------------------------------------------- val amount: HashMap = hashMapOf() amount["content"] = "AMOUNT: NGN 5000" amount["contentType"] = "TEXT" amount["alignment"] = "LEFT" amount["fontSize"] = "NORMAL" dataList.add(amount) //----------------------------------------------------------- val dateTime: HashMap = hashMapOf() dateTime["content"] = "DATE/TIME: 2021-09-09 12:00:00" dateTime["contentType"] = "TEXT" dateTime["alignment"] = "LEFT" dateTime["fontSize"] = "NORMAL" dataList.add(dateTime) //----------------------------------------------------------- val RRN: HashMap = hashMapOf() RRN["content"] = "RRN: 1234567890" RRN["contentType"] = "TEXT" RRN["alignment"] = "LEFT" RRN["fontSize"] = "NORMAL" dataList.add(RRN) //----------------------------------------------------------- val stan: HashMap = hashMapOf() stan["content"] = "STAN: 423257" stan["contentType"] = "TEXT" stan["alignment"] = "LEFT" stan["fontSize"] = "NORMAL" dataList.add(stan) //----------------------------------------------------------- val cardScheme: HashMap = hashMapOf() cardScheme["content"] = "CARD SCHEME: VISA" cardScheme["contentType"] = "TEXT" cardScheme["alignment"] = "LEFT" cardScheme["fontSize"] = "NORMAL" dataList.add(cardScheme) //----------------------------------------------------------- val status: HashMap = hashMapOf() status["content"] = "APPROVED" status["contentType"] = "TEXT" status["alignment"] = "CENTER" status["fontSize"] = "LARGE" status["isBold"] = true dataList.add(status) //----------------------------------------------------------- val responseCode: HashMap = hashMapOf() responseCode["content"] = "RESPONSE CODE: 00" responseCode["contentType"] = "TEXT" responseCode["alignment"] = "LEFT" responseCode["fontSize"] = "NORMAL" dataList.add(responseCode) //----------------------------------------------------------- val meaning: HashMap = hashMapOf() meaning["content"] = "MEANING: Approved or successfully completed" meaning["contentType"] = "TEXT" meaning["alignment"] = "LEFT" meaning["fontSize"] = "NORMAL" dataList.add(meaning) //----------------------------------------------------------- val deviceID: HashMap = hashMapOf() deviceID["content"] = "DEVICE ID: 2KUD2XFU" deviceID["contentType"] = "TEXT" deviceID["alignment"] = "LEFT" deviceID["fontSize"] = "NORMAL" dataList.add(deviceID) //----------------------------------------------------------- val mobileNumber: HashMap = hashMapOf() mobileNumber["content"] = "MOBILE NUMBER: 08012345678" mobileNumber["contentType"] = "TEXT" mobileNumber["alignment"] = "LEFT" mobileNumber["fontSize"] = "NORMAL" dataList.add(mobileNumber) //----------------------------------------------------------- val appVersion: HashMap = hashMapOf() appVersion["content"] = "APP VERSION: 1.6.2" appVersion["contentType"] = "TEXT" appVersion["alignment"] = "LEFT" appVersion["fontSize"] = "NORMAL" dataList.add(appVersion) //----------------------------------------------------------- val decoration = HashMap() decoration["content"] = "*".repeat(32) decoration["contentType"] = "TEXT" decoration["alignment"] = "CENTER" dataList.add(decoration) //----------------------------------------------------------- val nombaWebsite = HashMap() nombaWebsite["content"] = "www.nomba.com" nombaWebsite["contentType"] = "TEXT" nombaWebsite["alignment"] = "CENTER" dataList.add(nombaWebsite) //----------------------------------------------------------- dataList.add(decoration) //----------------------------------------------------------- val whiteSpace = HashMap() whiteSpace["content"] = "" whiteSpace["contentType"] = "TEXT" whiteSpace["alignment"] = "CENTER" dataList.add(whiteSpace) return dataList } fun convertDrawableResToBitmap(context: Context, @DrawableRes drawableRes: Int): Bitmap? { return ContextCompat.getDrawable(context, drawableRes)?.toBitmap() } val bitmap = convertDrawableResToBitmap(context, R.drawable.nombalogo) //setup an intent to be triggered val intent = Intent(PRINT_RECEIPT_INTENT) //setup a bundle to be packaged with the intent val bundle = Bundle() //pass necessary details to bundle bundle.putSerializable(ARGS_PRINT_DATA, sampleReceipt()) bundle.putParcelable(ARGS_PRINT_BITMAP_DATA, bitmap) //pass the data bundle to the intent intent.putExtras(bundle) //launch the intent printReceiptLauncher.launch(intent) ``` ```java snippet.java theme={null} import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.os.Bundle; import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult; import androidx.core.content.ContextCompat; import androidx.core.graphics.drawable.BitmapDrawableCompat; import java.util.ArrayList; import java.util.HashMap; // Constants public static final int PRINT_REQUEST_CODE = 100; public static final String ARGS_PRINT_DATA = "ARGS_PRINT_DATA"; public static final String ARGS_PRINT_BITMAP_DATA = "ARGS_PRINT_BITMAP_DATA"; public static final String PRINT_RESULT = "PRINT_RESULT"; public static final int ARGS_PRINT_RECEIPT_EVENT = 1944; public static final String PRINT_RECEIPT_INTENT = "com.nomba.pro.core.print_receipt.ACTION_VIEW"; // State private String resultString = ""; // Setup a launcher that would help launch the intent private ActivityResultLauncher printReceiptLauncher = registerForActivityResult( new StartActivityForResult(), result -> { Intent data = result.getData(); if (result.getResultCode() == ARGS_PRINT_RECEIPT_EVENT) { resultString = data.getStringExtra(PRINT_RESULT); } } ); public static void main(String[] args) { YourClass yourClass = new YourClass(); yourClass.launchPrintReceiptIntent(); } public void launchPrintReceiptIntent() { ArrayList> dataList = sampleReceipt(); // Convert drawable of your logo to bitmap Bitmap bitmap = convertDrawableResToBitmap(context, R.drawable.nombalogo); // Setup an intent to be triggered Intent intent = new Intent(PRINT_RECEIPT_INTENT); // Setup a bundle to be packaged with the intent Bundle bundle = new Bundle(); // Pass necessary details to bundle bundle.putSerializable(ARGS_PRINT_DATA, dataList); bundle.putParcelable(ARGS_PRINT_BITMAP_DATA, bitmap); // Pass the data bundle to the intent intent.putExtras(bundle); // Launch the intent printReceiptLauncher.launch(intent); } public ArrayList> sampleReceipt() { // Implement sampleReceipt() as in the Kotlin code // ... return dataList; } public Bitmap convertDrawableResToBitmap(Context context, int drawableRes) { return BitmapDrawableCompat.create(context.getResources(), context.getDrawable(drawableRes), null).getBitmap(); } ``` # Push Payment to Terminal Source: https://developer.nomba.com/docs/products/terminals/push-payment-request How to initiate and process payments using the Nomba payment terminal This integration enables you to initiate payments directly on a Nomba physical payment terminal from your backend system. It allows seamless coordination between your client, server, and a Nomba terminal for in-person payments. ## API Docs ## How It Works ### Flow Description 1. **Customer Orders an Item**\ The customer initiates a purchase through your client application. 2. **Client Sends Order to Server**\ Your frontend sends the order details (including `orderId`, `amount`, and `currency`) to your backend. 3. **Server Sends Payment Request to Nomba**\ Your backend uses the `POST /v1/terminals/payment-request/{terminalId}` endpoint to trigger a payment on the specific terminal. #### Endpoint: `POST /v1/terminals/payment-request/{terminalId}` **Request Body Schema**: `TerminalPaymentRequest` ```json theme={null} { "merchantTxRef": "55555555", "amount": 1000, "currency": "NGN" } ``` 4. **Nomba Pushes Payment to Terminal**\ The terminal receives a payment prompt and displays the amount to the customer. 5. **Customer Makes Payment on Terminal**\ The customer completes the payment using a supported payment method. 6. **Nomba Sends Webhook to Your Server**\ Upon successful payment, Nomba sends a webhook to your server with the payment confirmation and metadata. ## Webhook Notification Your server must be able to receive webhook notifications from Nomba. Ensure your webhook endpoint is secured and reliable. *** # Balance Check Source: https://developer.nomba.com/docs/products/terminals/terminal-actions/balance-check Intercept balance check requests to apply validation or custom logic Customize or approve payout transactions before they are processed. ```json Request theme={null} { "action_type" : "pre-balance-check-auth", "action_id" : "q6cf8t96-7fg8-432e-98c8-d4cb8f5b", "version": "v1.1.0", "data" : { "terminal" : { "terminalId" : "2KUD1234", "serialNo" : "91201008993212", "pin": "0000", "signature": "plainKeyPassedByUserAndHashedWithMerchantSecretKey" } } } ``` ```json Response theme={null} { "data": { "user": { "balance": 154567.78, "currency": "NGN" } } } ``` #### Passed Data Object The type of terminal action to perform (e.g., `pre-balance-check-auth`). A unique identifier for this terminal action request. API version to use (e.g., `v1.1.0`). Contains details about the terminal making the request. Unique identifier for the terminal. Serial number of the terminal. PIN entered by the user. HMAC hash of the plain key signed with the merchant’s secret key. *** #### Expected response Contains user balance information. Current balance of the user’s account. Currency of the returned balance (e.g., `NGN`). *** # Introduction Source: https://developer.nomba.com/docs/products/terminals/terminal-actions/introduction Learn how to create middlewares for Terminals ## Overview Terminal action allows developers to insert custom decision making logic to extend Nomba Terminal features behaviour during different transaction scenarios. Imagine your terminal is about to: • Check balance • Make a payout • Perform another financial action Instead of instantly completing the action, Terminal action pulse the process, send the transaction data to your backend system and wait for your system's approval to either reject or continue the process. After your system's instruction(based on your business rule) it sends a response back to the terminal to: • Proceed with the transaction • Modify some parameters • Cancel or reject the action Think of it as **middleware for your terminal** — it gives your infrastructure control over what happens next in real time. *** ## Quick Action Intercept balance check requests to apply validation or custom logic. Customize or approve payout transactions before they are processed. ## Terminal Actions Scenarios Terminal actions can be triggered at different stages of a transaction to allow custom business logic to run before proceeding. Below are examples of supported scenarios, their action precedence, types, and execution modes. | **Scenario** | **Action Type** | **Mode** | | ----------------- | ------------------------ | ----------- | | **Payout** | `pre-payout-auth` | Synchronous | | **Balance Check** | `pre-balance-check-auth` | Synchronous | **Synchronous Mode**:\ In synchronous mode, the terminal will wait for your backend to respond before moving forward with the transaction. *** ## Precedence **Precedence** defines the exact point in the transaction pipeline where a terminal action is triggered.\ It determines **when your custom logic is executed** relative to the terminal’s built-in process — such as before showing a balance or after requesting a PIN. This lets you: • Enforce business rules before the terminal proceeds • Reject unauthorized actions early • Run validations like balance checks and similar actions *** 1. `pre-payout-auth`: Triggered when a user is about to initiate a payout transaction, immediately after the terminal requests a PIN. This allows you to validate the transaction, apply rules, or reject it before processing. 2. `pre-balance-check-auth`: Triggered when a user attempts to check their wallet or account balance. This provides an opportunity to authorize or restrict access based on custom logic. *** ## Reason Code List Terminal Action responses include a `reasonCode` that indicates the **outcome** of your custom logic and guides the terminal on what to do next. These codes help standardize system responses, making them easy to interpret programmatically. ### What is a `reasonCode`? A `reasonCode` is a **status flag** returned in your response to indicate **whether the transaction should proceed or not**, and why It is paired with `shouldActionProceed: true/false` to clearly guide the terminal's next step. ```javascript theme={null} { "shouldActionProceed": true, "reasonCode": "00" } ``` *** ### Reason Code Reference | **Code** | **Meaning** | **Description** | | -------- | ------------------------- | ----------------------------------------------------------------------- | | `00` | **SUCCESS** | The action passed all checks — proceed with the transaction. | | `01` | **FAILED** | A generic failure occurred — stop the transaction. | | `02` | **BLACKLISTED** | The terminal or customer is blacklisted and cannot perform this action. | | `03` | **TERMINAL\_NOT\_FOUND** | The terminal making the request does not exist in your system. | | `04` | **ACCOUNT\_NOT\_FOUND** | The associated account could not be located. | | `05` | **INVALID\_PIN** | The PIN provided is incorrect or unauthorized. | | `06` | **LIMIT\_EXCEEDED** | The transaction amount exceeds the allowable limit. | | `07` | **INSUFFICIENT\_BALANCE** | The account does not have enough funds to complete the transaction. | # Payout Transaction Source: https://developer.nomba.com/docs/products/terminals/terminal-actions/payout-transaction Customize or approve payout transactions before they are processed Intercept balance check requests to apply validation or custom logic. ```json Request theme={null} { "action_type" : "pre-payout-auth", "action_id" : "d4cb8f5b-8ae5-432e-82c8-c17d6607bf2c", "version": "v1.1.0", "data" : { "terminal" : { "terminalId" : "2KUD1234", "serialNo" : "91201008993212", "pin": "0000", "signature": "plainKeyPassedByUserAndHashedWithMerchantSecretKey" }, "transaction" : { "amount": 5000, "currency": "NGN", "source": "pos", "type": "transfer", "customerBillerId": "", "productId": "", "billerAccountName": "" "rrn": "***" }, "account" : { "balance": 5000, "currency": "NGN", "id": "9ee1586d-3b14-4fcc-b9cf-4226d50f26de" } } } ``` ```json Response theme={null} { "data": { "transaction": { "shouldActionProceed": true, "reasonCode": "00" } } } ``` #### Passed Data Object The type of terminal action to perform (e.g., `pre-payout-auth`). A unique identifier for this terminal action request. API version to use (e.g., `v1.1.0`). Contains the terminal, transaction, and account data for evaluation. Unique identifier for the terminal. Serial number of the terminal. PIN entered by the user. HMAC signature generated using the merchant's secret key. The payout amount. Currency code (e.g., `NGN`). Origin of the transaction (e.g., `pos`). Type of transaction (e.g., `transfer`). Customer's biller identifier (if applicable). Identifier for the product involved in the transaction. Name on the biller account. Retrieval Reference Number used to trace the transaction. Current account balance. Currency of the account balance. Account ID. *** #### Expected response Contains the decision outcome for the transaction. Indicates whether the terminal should proceed with the payout. Response code explaining the decision (e.g., `00` for success). *** `reasonCode` is a standard response identifier used in the Terminal Action API to communicate the outcome of a custom logic check. To see all of the supported reason code [check here](/docs/products/terminals/terminal-actions/introduction#reason-code-list). # Unassigning terminals Source: https://developer.nomba.com/docs/products/terminals/unassigning-terminals Learn how to unassign terminals from accounts # `POST /v1/terminals/unassign` ```bash Request theme={null} curl --request POST \ --url https://api.nomba.com/v1/terminals/unassign \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --header 'accountId: ' \ --data '{ "serialNumber": "55555555", "terminalLabel": "Testing" }' ``` ```json Response theme={null} { "code": "00", "description": "Success", "data": { "terminalId": "201124LM", "serialNumber": "55555555", "accountId": "01a10aeb-d989-460a-bbde-9842f2b4320f", "parentAccountId": "", "merchantName": "trident and rees", "terminalLabel": "Testing", "createdAt": "2020-09-23T10:21:48.789Z", "updatedAt": "2023-09-04T15:23:55.173Z" } } ``` #### Request body Terminal serial number. Terminal label. #### Response body Response code Response description Terminal ID. Serial number. Account ID. Parent account ID. Merchant name. Terminal label. Creation timestamp. Update timestamp. # Fetch Transactions Source: https://developer.nomba.com/docs/products/transactions/fetch-transactions Learn how to fetch transactions associated with an account. ## Overview You may need to check the status of a transaction or retrieve a list of transactions for reconciliation purposes. Nomba provides multiple APIs for fetching different types of transactions—for example, debit/credit, virtual account, or parent account transactions. Depending on your use case, you can explore the relevant fetch transaction endpoint. Transaction APIs are paginated. We recommend reviewing the [pagination guide](/docs/api-basics/pagination) to understand how to work with paginated endpoints or trying out live API interactions to see how it works in practice. ## Fetch Account Transactions To fetch account transactions within a specific timeframe, make a [GET request](/nomba-api-reference/transactions/fetch-transactions-on-the-parent-account) to `/v1/transactions/accounts` or see the sample request and response below:You can pass a query param to specify a timeframe by passing `dateFrom` and `dateTo` as part of the request. You can also set a limit, as it's a paginated endpoint. To learn how Nomba handles pagination, [check here.](/docs/api-basics/pagination) ```bash Request theme={null} curl --request GET \ --url https://api.nomba.com/v1/transactions/accounts?limit=10&dateFrom=2023-01-01T00%3A00%3A00&dateTo=2025-01-01T00%3A00%3A00' \ --header 'Authorization: Bearer ' \ --header 'accountId: ' ``` ```json expandable Response theme={null} { "code": "00", "description": "Success", "data": { "results": [ { "id": "POS-WITHDRAW-DFC05-693cd007-cd1e-4ea6-8b79-5f5c4d7a83ea", "status": "SUCCESS", "amount": 4000, "fixedCharge": 123, "source": "pos", "type": "withdrawal", "gatewayMessage": "SUCCESS", "customerBillerId": "539983 **** **** 5118", "timeCreated": "2023-09-08T19:26:34.657000Z", "posTid": "2KUD4AKB", "terminalId": "2KUD4AKB", "providerTerminalId": "2KUD4AKB", "rrn": "230908202632", "posSerialNumber": "91230309116826", "posTerminalLabel": "KEB MUSA ABUBAKAR", "stan": "556734", "paymentVendorReference": "2KUD4AKB230908202632", "userId": "dfc05ca1-4e75-41dd-8e41-2d362d565893", "posRrn": "230908202632", "merchantTxRef": "c90d-4b25-ad0f" } ], "cursor": "xchbaVFsjdsbaADddd" } } ``` ## Fetch Bank Transactions To fetch debit or credit transactions associated with an account, make a [GET Request](/nomba-api-reference/transactions/fetch-creditdebit-transactions-on-the-parent-account) to `/v1/transactions/bank`. ```bash Request theme={null} curl --request GET \ --url https://api.nomba.com/v1/transactions/bank \ --header 'Authorization: Bearer ' \ --header 'accountId: ' ``` ```json expandable Response theme={null} { "code": "00", "description": "Success", "data": { "results": [ { "amount": 7000, "currency": "NGN", "meta": { "billerId": "API_FCIR5UQFMYS", "terminalActionId": "", "productId": "p2p", "fee": 0, "type": "p2p", "transactionId": "API-P2P-84026-d8a4d658-6747-418d-a7e2-37bc6290310d", "rrn": "", "parentAccountId": "01a10aeb-d989-460a-bbde-9842f2b4320f", "terminalLabel": "", "accountId": "890022ce-bae0-45c1-9b9d-ee7872e6ca27", "merchantTxRef": "", "transactionAmount": 7000, "mCollectionsId": "" }, "status": "SUCCESS", "timeUpdated": "2023-09-08T19:05:21.000Z", "walletBalance": 285951, "transactionType": "DEBIT" } ], "cursor": "xchbaVFsjdsbaADddd" } } ``` ## Fetch Virtual Account Transactions To fetch transactions on a virtual account, make a GET request to `/v1/transactions/virtual`. Pass the virtual\_account query parameter with the account number. You can also filter by `dateFrom` and `dateTo`. ```bash Request theme={null} curl --request GET \ --url'https://api.nomba.com/v1/transactions/virtual?virtual_account=8578228675&dateFrom=2025-06-24&dateTo=2025-06-25' \ --header 'accountId: ' \ --header 'Authorization: Bearer ' ``` ```json expandable Response theme={null} { "code": "00", "description": "SUCCESS", "data": { "cursor": "", "results": [ { "id": "API-VACT_TRA-FFCBE-9eb634eb-4dc5-46a9-bb65-7d03d6b88c1c", "status": "SUCCESS", "amount": "100.0", "fixedCharge": "0.5", "source": "api", "type": "vact_transfer", "customerBillerId": "8065219824", "timeCreated": "2025-06-24T11:31:35.017Z", "timeUpdated": "2025-06-24T11:31:35.107Z", "posTid": "", "posSerialNumber": "", "walletCurrency": "NGN", "walletBalance": "457.0", "billingVendorReference": "685a8c973ccb33995cbefc1f", "paymentVendorReference": "038309078367093226893790137012", "userId": "***", "ktaSenderName": "John doe", "ktaSenderAccountNumber": "8068952954", "ktaSenderBankCode": "Paycom (Opay)", "recipientAccountNumber": "8578228675", "recipientAccountType": "VIRTUAL", "senderName": "John Doe", "currency": "NGN", "bankCode": "305", "productId": "305", "isAgentTransaction": true, "isInternational": false, "customerCommission": "0.00", "recipientAccountName": "Clean/Agboola Oyenike", "sessionId": "100004250624113131135397696024", "accountNumber": "8028952054", "bankName": "Paycom (Opay)", "entryType": "CREDIT", "transactionCategory": "Income", "narration": "Transfer from John Doe", "receiptTerminalId": "" } ] }, "status": false } ``` ## Transaction Requery Use this endpoint to confirm the status of a transaction using its `sessionId`. To obtain a session ID, first filter through virtual account transactions to locate the transaction you want to requery. ```bash Request theme={null} curl --request GET \ --url https://api.nomba.com/v1/transactions/requery/ \ --header 'Authorization: Bearer ' \ --header 'accountId: ' ``` ```json expandable Response theme={null} { "code": "00", "description": "Requery Successful", "data": { "id": "API-VACT_TRA-185C7-01964b64-5c0a-4c91-81b6-zxv7a421862b", "status": "SUCCESS", "amount": "200.0", "fixedCharge": "1.0", "source": "api", "type": "vact_transfer", "customerBillerId": "0122408496", "timeCreated": "2024-07-11T16:12:49.656Z", "walletBalance": "1648.79", "billingVendorReference": "029004810da38748e93ca4a9", "paymentVendorReference": "000132891359184717316165338085", "userId": "185c75d9-6ae0-675r-950e-425666184ed6", "ktaSenderName": "Smart Hamzat", "ktaSenderAccountNumber": "0122408496", "ktaSenderBankCode": "Amucha MFB (Nomba)", "recipientAccountNumber": "0014701211", "recipientAccountType": "VIRTUAL", "senderName": "Smart Hamzat", "bankCode": "090645", "productId": "090645", "isAgentTransaction": true, "isInternational": false, "customerCommission": 0, "recipientAccountName": "John Amazing Doe", "sessionId": "000132891359184717316165338085", "accountNumber": "0122408496", "bankName": "Amucha (Nomba)" } } ``` # Overview Source: https://developer.nomba.com/docs/products/transactions/introduction Learn how to fetch all types of transactions ## Quick Actions Retrieve a history of all transactions carried out from your main Nomba account. View and track transfers and payments made directly to and from bank accounts. Get transaction details for payments received through virtual accounts. Confirm the latest status of a specific transaction using its reference. # Bank account lookup Source: https://developer.nomba.com/docs/products/transfers/bank-account-lookup Verify a recipient bank account before initiating a transfer Perform a bank account lookup before processing bank transfer payments You can use [this](/docs/products/transfers/fetch-bank-codes-and-names) to retrieve the specific `bankCode` for any desired bank. Always verify a recipient account before initiating a transfer. This confirms the account exists and returns the account holder's name — which you should display to your user for confirmation before sending funds. # `POST /v1/transfers/bank/lookup` ```bash cURL theme={null} curl --request POST \ --url https://api.nomba.com/v1/transfers/bank/lookup \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --header 'accountId: ' \ --data '{ "accountNumber": "0554772814", "bankCode": "053" }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api.nomba.com/v1/transfers/bank/lookup', { method: 'POST', headers: { 'Authorization': `Bearer ${accessToken}`, 'Content-Type': 'application/json', 'accountId': accountId, }, body: JSON.stringify({ accountNumber: '0554772814', bankCode: '053', }), }); const { code, data } = await response.json(); if (code !== '00') { throw new Error('Account lookup failed — check account number and bank code'); } // Show the account name to the user before proceeding with transfer console.log(`Recipient: ${data.accountName} (${data.accountNumber})`); ``` ```python Python theme={null} import requests response = requests.post( 'https://api.nomba.com/v1/transfers/bank/lookup', headers={ 'Authorization': f'Bearer {access_token}', 'Content-Type': 'application/json', 'accountId': account_id, }, json={ 'accountNumber': '0554772814', 'bankCode': '053', }, ) result = response.json() if result['code'] != '00': raise Exception('Account lookup failed — check account number and bank code') # Show the account name to the user before proceeding with transfer print(f"Recipient: {result['data']['accountName']} ({result['data']['accountNumber']})") ``` ```json Response theme={null} { "code": "00", "description": "Success", "data": { "accountNumber": "0554772814", "accountName": "M.A Animashaun" } } ``` #### Request body The account number to be looked up. The code of the bank that the account number belongs to. Obtain this from [`GET /v1/transfers/banks`](/docs/products/transfers/fetch-bank-codes-and-names). #### Response body Response code. `"00"` indicates a valid account was found. Response description. The verified account number. The name on the account. Display this to the user before confirming the transfer. # Fetch bank codes Source: https://developer.nomba.com/docs/products/transfers/fetch-bank-codes-and-names Retrieve bank codes and names for all supported Nigerian banks Fetch the bank codes and names tied to all banks You need the `bankCode` when performing [bank account lookups](/docs/products/transfers/bank-account-lookup) and [bank transfers](/docs/products/transfers/transfer-to-banks). Call this endpoint once and cache the result — bank codes rarely change. # `GET /v1/transfers/banks` ```bash cURL theme={null} curl --request GET \ --url https://api.nomba.com/v1/transfers/banks \ --header 'Authorization: Bearer ' \ --header 'accountId: ' ``` ```javascript Node.js theme={null} const response = await fetch('https://api.nomba.com/v1/transfers/banks', { headers: { 'Authorization': `Bearer ${accessToken}`, 'accountId': accountId, }, }); const { code, data } = await response.json(); if (code !== '00') throw new Error('Failed to fetch bank codes'); const banks = data; // Example: find GTBank const gtbank = banks.find(b => b.code === '058'); console.log(gtbank); // { name: 'GTBank', code: '058', nipCode: null, logo: 'https://...' } ``` ```python Python theme={null} import requests response = requests.get( 'https://api.nomba.com/v1/transfers/banks', headers={ 'Authorization': f'Bearer {access_token}', 'accountId': account_id, }, ) result = response.json() if result['code'] != '00': raise Exception('Failed to fetch bank codes') banks = result['data'] # Example: build a lookup dict bank_map = {b['name']: b['code'] for b in banks} ``` ```json Response theme={null} { "code": "00", "description": "SUCCESS", "message": "SUCCESS", "status": true, "data": [ { "name": "GTBank", "code": "058", "nipCode": null, "logo": "https://firebasestorage.googleapis.com/v0/b/business-banking-93cc1.appspot.com/o/bankLogos%2FGroup%209.png?alt=media&token=98bde9e8-1862-495d-9046-bd3d96465970" }, { "name": "First Bank of Nigeria", "code": "011", "nipCode": null, "logo": "https://firebasestorage.googleapis.com/v0/b/business-banking-93cc1.appspot.com/o/bankLogos%2FGroup%201.png?alt=media&token=06a3a300-dafe-49db-b3d3-049371bf1173" }, { "name": "United Bank for Africa", "code": "033", "nipCode": null, "logo": "https://firebasestorage.googleapis.com/v0/b/business-banking-93cc1.appspot.com/o/bankLogos%2FGroup%2025.png?alt=media&token=a2a144de-9c8b-4811-8278-7666746486ee" }, { "name": "Addosser Microfinance Bank", "code": "090160", "nipCode": null, "logo": "" } ] } ``` #### Response body Response code. `"00"` indicates success. Response description. List of all supported banks. The bank's code. Use this as `bankCode` in transfer and lookup requests. The bank's display name. The bank's NIP institution code. May be `null`. URL of the bank's logo image. An empty string when no logo is available. # Overview Source: https://developer.nomba.com/docs/products/transfers/introduction Learn how to process bank transfers with the Nomba API Bank transfers form the backbone of modern financial services, enabling swift and secure movement of funds. You can initiate bank transfers effortlessly with our APIs. We prioritize the highest standards of security and compliance, ensuring your financial transactions are handled with the utmost care. ## Quick Action Use the Nomba API to do account lookups. Initiate account transfers with the Nomba API. Initiate P2P transfers within Nomba. To successfully execute bank transfers using our endpoints, it is necessary to undergo the following steps: First get the bank code of the recepient using this endpoint. `Request` ```bash theme={null} curl --request GET \ --url https://api.nomba.com/v1/transfers/bank \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --header 'accountId: ' ``` `Response` ```json theme={null} { "code": "00", "description": "SUCCESS", "message": "SUCCESS", "status": true, "data": [ { "name": "First Bank of Nigeria", "code": "011", "nipCode": null, "logo": "https://firebasestorage.googleapis.com/v0/b/business-banking-93cc1.appspot.com/o/bankLogos%2FGroup%201.png?alt=media&token=06a3a300-dafe-49db-b3d3-049371bf1173" }, { "name": "3LINE CARD MANAGEMENT LIMITED", "code": "110005", "nipCode": null, "logo": "" } ], } ``` Before initiating bank transfers, it's advisable to inform your customers about the recipient. The bank account lookup endpoint requires an `accountNumber` and the associated `bankCode` (a unique code representing the bank) as input. `Request` ```bash theme={null} curl --request POST \ --url https://api.nomba.com/v1/transfers/bank/lookup \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --header 'accountId: ' \ --data '{ "accountNumber": "3554772814", "bankCode": "011" }' ``` `Response` ```json theme={null} { "code": "00", "description": "Success", "data": { "accountNumber": "0554772814", "accountName": "M.A Animashaun" } } ``` Initiate a bank transfer from Nomba to an external bank. This endpoint requires details such as the `amount` to be transferred, a `merchantTxRef` for later transaction reconciliation, as well as the recipient's `accountNumber` and `bankCode`. `Request` ```bash theme={null} curl --request POST \ --url https://api.nomba.com/v2/transfers/bank \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --header 'accountId: ' \ --data '{ "amount": 3500, "accountNumber": "3554772814", "accountName": "M.A Animashaun", "bankCode": "011", "merchantTxRef": "UNQ_123abGGhh5546", "senderName": "Nightly Post" }' ``` `Response` ```json theme={null} { "code": "00", "description": "Success", "data": { "amount": 5502, "meta": { "merchantTxRef": "3JVW2xJCjj443oannREBuTaXDdji", "api_client_id": "6a7bed88-7c93-4a1c-a445-f88edbca6489", "api_account_id": "01a10aeb-d989-460a-bbde-9842f2b4320f", "rrn": "230908151711" }, "fee": 50, "timeCreated": "2023-09-08T14:17:13.634Z", "id": "API-TRANSFER-C24AD-a6443bf0-011c-4bc2-b739-4a2e33e2a27b", "type": "transfer", "status": "SUCCESS" } } ``` # Transfer between accounts Source: https://developer.nomba.com/docs/products/transfers/transfer-between-accounts Learn how to use the Nomba API to move money between accounts The movement of funds between accounts, commonly known as P2P, refers to the internal transfer of funds within the network. This direct transfer bypasses external processors, ensuring rapid and efficient handling solely by Nomba. # `POST /v2/transfers/wallet` ```bash cURL theme={null} curl --request POST \ --url https://api.nomba.com/v2/transfers/wallet \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --header 'accountId: ' \ --data '{ "amount": 3500, "receiverAccountId": "890022ce-bae0-45c1-9b9d-ee7872e6ca27", "merchantTxRef": "UNQ_123abGGhh5546", "senderName": "Nightly Post", "narration": "Nice one" }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api.nomba.com/v2/transfers/wallet', { method: 'POST', headers: { 'Authorization': `Bearer ${accessToken}`, 'Content-Type': 'application/json', 'accountId': accountId, }, body: JSON.stringify({ amount: 3500, receiverAccountId: '890022ce-bae0-45c1-9b9d-ee7872e6ca27', merchantTxRef: 'UNQ_123abGGhh5546', senderName: 'Nightly Post', narration: 'Nice one', }), }); const { code, data } = await response.json(); if (code !== '00') throw new Error(`Wallet transfer failed: ${code}`); // P2P transfers complete synchronously — no PENDING_BILLING status ``` ```python Python theme={null} import requests response = requests.post( 'https://api.nomba.com/v2/transfers/wallet', headers={ 'Authorization': f'Bearer {access_token}', 'Content-Type': 'application/json', 'accountId': account_id, }, json={ 'amount': 3500, 'receiverAccountId': '890022ce-bae0-45c1-9b9d-ee7872e6ca27', 'merchantTxRef': 'UNQ_123abGGhh5546', 'senderName': 'Nightly Post', 'narration': 'Nice one', }, ) result = response.json() if result['code'] != '00': raise Exception(f"Wallet transfer failed: {result['code']}") # P2P transfers complete synchronously — no PENDING_BILLING status ``` ```json Response theme={null} { "code": "00", "description": "Success", "data": { "amount": 5502, "meta": { "merchantTxRef": "3JVW2xJCjj443oannREBuTaXDdji", "api_client_id": "6a7bed88-7c93-4a1c-a445-f88edbca6489", "api_account_id": "01a10aeb-d989-460a-bbde-9842f2b4320f", "rrn": "230908151711" }, "fee": 50, "timeCreated": "2023-09-08T14:17:13.634Z", "id": "API-P2P-C24AD-a6443bf0-011c-4bc2-b739-4a2e33e2a27b", "type": "p2p", "status": "SUCCESS" } } ``` #### Request body The amount to be transferred. The receiver's accountId.

Unique reference used to track a transaction from an external process.

This is an idempotency key and must be unique per transaction. It cannot be reused once a transfer has been initiated.

The sender's name. The narration for this transfer (NB: This will be appended to the normal system generated narration). #### Response body Response code Response description The transfer data. The transfer amount. The transaction meta data. Merchant transaction reference. API client ID. API account ID. RRN (Retrieval Reference Number). The transfer fee. The creation timestamp. The transfer ID. The transaction type. The transaction status. # Transfer to banks Source: https://developer.nomba.com/docs/products/transfers/transfer-to-banks Learn how to perform bank transfers using the Nomba API # `POST /v2/transfers/bank` > ⚠️ **Rate Limit Notice:**\ > Users are restricted to **5 bank transfers to the same recipient per minute**. ```bash cURL theme={null} curl --request POST \ --url https://api.nomba.com/v2/transfers/bank \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --header 'accountId: ' \ --data '{ "amount": 3500, "accountNumber": "055472814", "accountName": "M.A Animashaun", "bankCode": "058", "merchantTxRef": "UNQ_123abGGhh5546", "senderName": "Nightly Post", "narration": "Nice One" }' ``` ```javascript Node.js theme={null} const response = await fetch('https://api.nomba.com/v2/transfers/bank', { method: 'POST', headers: { 'Authorization': `Bearer ${accessToken}`, 'Content-Type': 'application/json', 'accountId': accountId, }, body: JSON.stringify({ amount: 3500, accountNumber: '055472814', accountName: 'M.A Animashaun', bankCode: '058', merchantTxRef: 'UNQ_123abGGhh5546', senderName: 'Nightly Post', narration: 'Nice One', }), }); const { code, data } = await response.json(); if (code !== '00') throw new Error(`Transfer failed: ${code}`); if (data.status === 'PENDING_BILLING') { // Poll or wait for webhook with data.id } else if (data.status === 'REFUND') { throw new Error('Transfer refunded. Safe to retry.'); } ``` ```python Python theme={null} import requests response = requests.post( 'https://api.nomba.com/v2/transfers/bank', headers={ 'Authorization': f'Bearer {access_token}', 'Content-Type': 'application/json', 'accountId': account_id, }, json={ 'amount': 3500, 'accountNumber': '055472814', 'accountName': 'M.A Animashaun', 'bankCode': '058', 'merchantTxRef': 'UNQ_123abGGhh5546', 'senderName': 'Nightly Post', 'narration': 'Nice One', }, ) result = response.json() if result['code'] != '00': raise Exception(f"Transfer failed: {result['code']}") status = result['data']['status'] if status == 'PENDING_BILLING': pass # Poll or wait for webhook with result['data']['id'] elif status == 'REFUND': raise Exception('Transfer refunded. Safe to retry.') ``` ```json Response theme={null} { "code": "200", "description": "SUCCESS", "message": "Success", "status": true, "data": { "id": "API-TRANSFER-11EC4-45990eb5-7b0f-4845-87f8-xxxxxxxxxxxx", "status": "PENDING_BILLING", "type": "transfer", "amount": 1.0, "source": "api", "sourceUserId": "11ec45a1-1fe5-44f5-8baf-cxxxxxxxxxx", "customerBillerId": "010784xxxx", "productId": "058", "meta": { "api_rrn": "25120913xxxxx", "narration": "Testing", "recipientName": "John Doe", "sender_name": "Nightly Post", "rrn": "251209131319", "api_account_id": "670353d1-158a-4257-8f0b-xxxxxxxxxxx", "api_client_id": "651ab1c3-c703-4cc3-86ac-xxxxxxxxxxx", "user_id": "670353d1-158a-4257-8f0b-xxxxxxxxxxx", "merchantTxRef": "testingTxV2ForMerchant", "allowDuplicate": true, "idempotentKey": "670353d1-158a-4257-8f0b-d06d1fed3c35_testixxxxxxxxxxx", "pos_withdrawal_id": "670353d1-158a-4257-8f0b-d06d1fed3c35_testingxxxxxxxxxxx", "userName": "Code Trik Nigeria Enterprises", "isCorporate": "true", "currency": "NGN", "hooksEligible": "true", "banking_entity_id": 19787017, "banking_entity_user_id": 19787014, "banking_entity_type": "CORPORATE", "self_transaction": true, "transactionCategory": "Family & Kids", "accountNumber": "0107841806", "bankName": "GTBank", "bankCode": "058", "sessionId": "", "user_referral_code": "HABI76702", "amount_charged": "21.0", "paymentVendor": "wallet", "wallet_balance": "5.38", "wallet_currency": "NGN", "paymentVendorReference": "6938125f6e98e9ace8df850e", "agent_commission": "0.0", "useV2Fulfilment": "true" }, "userId": "670353d1-158a-4257-8f0b-xxxxxxxxxx", "timeCreated": "2025-12-09 12:13:19" } } ``` # `POST /v2/transfers/bank/{subAccountId}` If your usecase requires transferring funds from a specific sub-account, you can use the sub-account transfer endpoint. This is useful where you manage multiple balances or wallets under your main account. Sub-accounts can only be created from your Nomba dashboard. > 📢 **Feature Notice:**\ > Sub-account transfers must be enabled by us before you can use this endpoint. ```bash cURL theme={null} curl --request POST \ --url https://api.nomba.com/v2/transfers/bank/{subAccountId} \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --header 'accountId: ' \ --data '{ "amount": 3500, "accountNumber": "055472814", "accountName": "M.A Animashaun", "bankCode": "058", "merchantTxRef": "UNQ_123abGGhh5546", "senderName": "Nightly Post", "narration": "Nice One" }' ``` ```javascript Node.js theme={null} const subAccountId = 'your-sub-account-id'; const response = await fetch( `https://api.nomba.com/v2/transfers/bank/${subAccountId}`, { method: 'POST', headers: { 'Authorization': `Bearer ${accessToken}`, 'Content-Type': 'application/json', 'accountId': accountId, }, body: JSON.stringify({ amount: 3500, accountNumber: '055472814', accountName: 'M.A Animashaun', bankCode: '058', merchantTxRef: 'UNQ_123abGGhh5546', senderName: 'Nightly Post', narration: 'Nice One', }), } ); const { code, data } = await response.json(); if (code !== '00') throw new Error(`Transfer failed: ${code}`); ``` ```python Python theme={null} import requests sub_account_id = 'your-sub-account-id' response = requests.post( f'https://api.nomba.com/v2/transfers/bank/{sub_account_id}', headers={ 'Authorization': f'Bearer {access_token}', 'Content-Type': 'application/json', 'accountId': account_id, }, json={ 'amount': 3500, 'accountNumber': '055472814', 'accountName': 'M.A Animashaun', 'bankCode': '058', 'merchantTxRef': 'UNQ_123abGGhh5546', 'senderName': 'Nightly Post', 'narration': 'Nice One', }, ) result = response.json() if result['code'] != '00': raise Exception(f"Transfer failed: {result['code']}") ``` ```json Response theme={null} { "code": "200", "description": "SUCCESS", "message": "Success", "status": true, "data": { "id": "API-TRANSFER-11EC4-45990eb5-7b0f-4845-87f8-xxxxxxxxxxxx", "status": "PENDING_BILLING", "type": "transfer", "amount": 1.0, "source": "api", "sourceUserId": "11ec45a1-1fe5-44f5-8baf-cxxxxxxxxxx", "customerBillerId": "010784xxxx", "productId": "058", "meta": { "api_rrn": "25120913xxxxx", "narration": "Testing", "recipientName": "John Doe", "sender_name": "Nightly Post", "rrn": "251209131319", "api_account_id": "670353d1-158a-4257-8f0b-xxxxxxxxxxx", "api_client_id": "651ab1c3-c703-4cc3-86ac-xxxxxxxxxxx", "user_id": "670353d1-158a-4257-8f0b-xxxxxxxxxxx", "merchantTxRef": "testingTxV2ForMerchant", "allowDuplicate": true, "idempotentKey": "670353d1-158a-4257-8f0b-d06d1fed3c35_testixxxxxxxxxxx", "pos_withdrawal_id": "670353d1-158a-4257-8f0b-d06d1fed3c35_testingxxxxxxxxxxx", "userName": "Code Trik Nigeria Enterprises", "isCorporate": "true", "currency": "NGN", "hooksEligible": "true", "banking_entity_id": 19787017, "banking_entity_user_id": 19787014, "banking_entity_type": "CORPORATE", "self_transaction": true, "transactionCategory": "Family & Kids", "accountNumber": "0107841806", "bankName": "GTBank", "bankCode": "058", "sessionId": "", "user_referral_code": "HABI76702", "amount_charged": "21.0", "paymentVendor": "wallet", "wallet_balance": "5.38", "wallet_currency": "NGN", "paymentVendorReference": "6938125f6e98e9ace8df850e", "agent_commission": "0.0", "useV2Fulfilment": "true" }, "userId": "670353d1-158a-4257-8f0b-xxxxxxxxxx", "timeCreated": "2026-03-08T12:13:19Z" } } ``` ## **Understanding Transfer Responses & Lifecycle** When you call the transfer endpoint `POST /v2/transfers/bank`, you will immediately receive a response if your request is valid (e.g., sufficient balance, correct payload structure, etc.). #### **Immediate Response Status** You will receive a successful API response with one of the following values in `data.status` **Example 1 — Transfer immediately successful** ```json theme={null} { "successful": true, "status": "SUCCESS", "message": "Success", "data": { "id": "API-TRANSFER-02145-XXXXX-8857-417f-a954-1234", "status": "SUCCESS" } } ``` **Example 2 — Transfer processing** ```json theme={null} { "successful": true, "status": "SUCCESS", "message": "Success", "data": { "id": "API-TRANSFER-02415-XXXX-8857-417f-1234", "status": "PENDING_BILLING" } } ``` **Example 3 — Transfer processing** ```json theme={null} { "successful": true, "status": "SUCCESS", "message": "Success", "data": { "id": "API-TRANSFER-02415-XXXX-8857-417f-1234", "status": "NEW" } } ``` #### **What `data.status` Means** * SUCCESS: Transfer completed successfully * PENDING\_BILLING: Transfer is being processed and will soon be completed * NEW: Transfer is being processed and will be completed #### **Tracking Transaction Status** Once the transaction is completed, a webhook notification will be sent to your system. If you prefer polling, use the transaction ID (`data.id`) returned in the response to query the transaction status. #### Requery Endpoints * If you are transferring from a parent account, use [this](/nomba-api-reference/requery/fetch-a-single-transaction-on-the-parent-account) ```bash theme={null} GET /v1/transactions/accounts/single?transactionRef=API-TRANSFER-XXX-XXX ``` * If you are transferring from a sub account, use [this](/nomba-api-reference/requery/fetch-a-single-transaction-on-a-sub-account) ```bash theme={null} GET /v1/transactions/accounts/{subAccountId}/single?transactionRef=API-TRANSFER-XXX-XXX ``` * If you use both parent and sub account to carry out transfers, use [this](/nomba-api-reference/requery/transaction-requery) ```bash theme={null} GET /v1/transactions/transaction-requery/{sessionId} ``` * Transactions **may not** be immediately available to requery (e.g., within 1 second). * Some transactions may take up to **3 minutes** due to NIBSS processing delays. * If you love polling, use **interval-based retries (up to \~3 minutes and few secs)**. * Nomba-to-Nomba transfers **do not include a sessionId** use the parent or sub-account endpoints for requery. #### **Handling a 201 Response** A `201` HTTP status code means the transfer request was received but the final outcome is not yet available. The transaction will be processed. ```json theme={null} { "code": "201", "description": "PROCESSING", "message": "Unable to process response, please rely on web hook", "status": false, "data": { "status": "PENDING_BILLING" } } ``` When you receive a 201, you should: 1. Mark the transaction as pending in your system 2. Keep the original `merchantTxRef` — do not generate a new one 3. Wait for the webhook notification for the final status (`SUCCESS` or `REFUND`) 4. Use the requery endpoints if you need to poll for status rather than waiting for the webhook #### **Handling Failed Transactions** * If a transaction fails, your account will be automatically refunded and a refund webhook notification will be sent. * If you love polling, query the endpoint like we previously discussed, look out for `data.status = REFUND`. It means the transaction failed and has been refunded. * You can safely retry the transaction after a refund using a new `merchantTxRef`. ```json theme={null} { "code": "00", "description": "SUCCESS", "status": false, "data": { "id": "API-TRANSFER-02415-XXXX-8857-417f-1234", "status": "REFUND" } } ``` #### **How To Prevent Double Disbursement** Funds transfers are sensitive. To prevent duplicate payouts, follow these best practices: **1. Use Idempotent Transaction References** * Always send a unique `merchantTxRef` per transaction * Reuse the same reference when retrying a request **2. Handle Pending Responses Correctly** * If a transaction returns `PENDING`, do NOT re-initiate the transfer with a different reference * The transaction may still be processed successfully **3. Retry Safely** * Only retry using the same `merchantTxRef` * Do NOT generate a new reference for the same transaction, if it is still pending **4. Verify Transaction Status** * Use the Requery endpoint discussed earlier to confirm the final status * Do not rely solely on the initial response **5. Use Webhooks (Recommended)** * Subscribe to [webhook](docs/api-basics/webhook) notifications for real-time updates * Webhooks provide the final and authoritative transaction status **6. When in Doubt** * Treat unknown responses as `PENDING` * If you receive an unexpected status or code, pause and contact us before retrying * A list of all status codes can be found [here](/nomba-api-reference/transfers/perform-bank-account-transfer-from-the-parent-account) #### **Summary** * Every transaction is being processed * We have a retry mechanism to ensure it is successful * A refund will happen immediately it fails. #### Request body The amount to be transferred. The destination bank account number. The name on the account. The code of the recipient bank.

Unique reference used to track a transaction from an external process.

This is an idempotency key and must be unique per transaction. It cannot be reused once a transfer has been initiated.

The sender's name. The narration for this transfer (NB: This will be appended to the normal system generated narration). #### Response body The transfer ID. The transaction status. The transaction type. The transfer amount. The transfer fee. Payment source (e.g., “api”). The user who initiated the transfer. The biller account ID. Product code for the transfer. Additional transaction metadata. Merchant transaction reference. API client ID. API account ID. Retrieval Reference Number. Associated user ID. Creation timestamp. # Product Update Source: https://developer.nomba.com/nomba-api-changelog/api/updates Keep track of changes and upgrades to the Nomba API. We are constantly making changes to the Nomba API. We recommend reviewing this changelog to stay updated on what’s new, improved, or deprecated. This ensures you remain aligned with our product. ### August 2026 * **Checkout** `docs` – Documented **Pay by Bank**, which lets customers with supported UK and European bank accounts authorise a payment directly in their banking app, with no card details entered at checkout. Use the `allowedPaymentMethods` value `Intl Transfer` to request or restrict it. It is available on supported `GBP` and `EUR` checkout flows, must be enabled on your account, and does not support recurring payments. See [Payment Methods](/docs/products/accept-payment/payment-methods#pay-by-bank). ### July 2026 * **Buy Data Bundle** `updated` – Added a new `productId` field to [Fetch Data Plans](/docs/products/airtime-and-data/fetch-data-plans) and [Buy Data Bundle](/nomba-api-reference/airtime-and-data-vending/vend-data-bundles-via-parent-account). Use the `productId` returned by Fetch Data Plans to select an exact bundle when purchasing — this removes ambiguity when multiple plans on the same network share the same price. Purchasing by `amount` alone is now **deprecated** and kept only for backward compatibility; new integrations should always use `productId`. The purchase response now also includes `productId` and `plan`, so you can confirm exactly which bundle was vended. ### April 2026 * [Transfer](/docs/products/transfers/transfer-to-banks) `docs` – We have added a detailed explanation of how transfers work. ### March 2026 * **Transfer** `docs` – You can now carry out transfers using your sub account. See update here [Transfer](/docs/products/transfers/transfer-to-banks). * **Checkout** `docs` – Introduced the optional `allowedPaymentMethods` field in the checkout order request, enabling merchants to restrict the payment methods shown on the checkout page (e.g., `Card`, `Transfer`). See update in [Checkout](/docs/products/accept-payment/create-checkout-order). * **Global Payout** `updated` – Updated the Authorize Transfer request fields: `bankCode` has been renamed to `institutionCode`, and `bankName` has been renamed to `institutionName`. The `phoneNumber` field has been removed; for `MOBILE_MONEY` transfers, pass the recipient's phone number in `accountNumber` instead. Canada bank transfer (`BANK` with `destinationCountryIsoCode: "CA"`) is now documented as a supported payment method. See the [Authorize Transfer](/docs/products/global-payout/authorize-transfer) page for the full required-fields breakdown per payment method. * **Global Payout** `added` – New endpoint `GET /v1/global-payout/bank/providers` returns the list of institution providers available for DRC transfers (Mpesa, Airtel Money, Orange Money). Use the returned `code` and `displayName` as `institutionCode` and `institutionName` in the Authorize Transfer request. See [Institution Providers](/docs/products/global-payout/mobile-money-providers). ### February 2026 * **Webhooks** `added` – Introduced support for replaying webhook events. See updates in [Debug webhooks](/docs/api-basics/troubleshoot-webhooks). * **Transfer V2** `docs` – Improved the documentation with clearer explanations of transfer status values. ### September 2025 * **Documentation Improvements** `docs` – We have improved the navigation structure for Accept Payments and Checkout. This includes grouping related items (e.g., Verify Transaction, Create Order, Charge) into a single section for better discoverability. We also refreshed quick-start examples to reduce setup time. See updates in [Accept Payments docs](/docs/products/accept-payment/overview). * **Direct Debit API** `added` – Introduced a new Direct Debit API, allowing businesses to pull funds directly from customer accounts with prior authorization. This feature enables recurring billing and scheduled payments with minimal friction. [Learn more about Direct Debit](/docs/products/accept-payment/direct-debit). * **Verify Sandbox and Production Transactions** `added` – A new endpoint is now available to verify transactions in both sandbox and production environments. This helps ensure consistent testing and seamless migration to live payments. [View Verify Transactions docs](/docs/products/accept-payment/verify-transactions). * **Create Sub-Account on Web** `docs` – Added step-by-step documentation for creating sub-accounts directly from the dashboard to support split settlements. This makes it easier to configure revenue sharing without writing additional code. [View Sub-Account Creation Guide](/docs/guides/managing-accounts-with-nomba#create-a-sub-account). ### June 2025 * **Perform lookup on virtual accounts** `added` – We have added documentation for performing lookup on a virtual account, click here to learn more about it. [View Virtual account lookup](/docs/products/transactions/introduction). * **Improvements to Create Virtual Account** `updated` We've updated the documentation for performing a virtual account lookup. The update includes support for BVN verification and the ability to specify an expected amount for incoming transfers, [view updates](/docs/products/accept-payment/virtual-account#create-a-virtual-account). * **Fetch virtual account transactions** `added` You can now retrieve the list of transactions made to a virtual account. This new addition lets you fetch all incoming payment records tied to a specific virtual account. [View Fetch Virtual Account Transactions docs](/docs/products/transactions/fetch-transactions#fetch-virtual-account-transactions). * **Terminal Actions** `added` – We've added documentation for Terminal Actions, allowing developers to inject custom logic at specific transaction stages (e.g., pre-payout validation, pre-balance checks). [Learn more about Terminal Actions](/docs/products/terminals/terminal-actions/introduction). ### May 2025 * **Betting API** `added` – We have added documentation for Betting API, click here to learn more about it. [View Betting API](/docs/products/bills/fetch-betting-providers). * **Webhook payment success** `updated` – We have made some changes to the webhook `payment_success` payload , click here to learn more about it. [View Changes](/docs/api-basics/webhook). ### April 2025 * **Signature verification** `docs` – we have updated the documentation structure to improve readability when working with webhook signature verification. we have also added a new `PHP` code sample. [view the updates](/docs/api-basics/webhook). * **Transaction Requery Title Fix** `docs` – Fixed a title mismatch and clarified the content on the transaction requery page. check [this page](/nomba-api-reference/transactions/transaction-requery) to see the updates. * **React SDKs** `added` – Added documentation for the React SDK. [check it out](/developer-resources/plugins-and-sdks). * **Flutter SDKs** `added` – Added documentation for the Flutter SDK [View SDK](/developer-resources/plugins-and-sdks). * **Fetch CableTv Plan** `added` – We have added documentation for fetching cable Tv based on cable Tv type. [Click to learn more](/docs/products/bills/fetch-cable-tv-plans). ### March 2025 * **Webhook Re-push** `added` – We have added documentation for the Webhook Re-push API. [Learn more](/docs/api-basics/troubleshoot-webhooks#repush). ### February 2025 * **Sub-Account API** `deprecated` – This API is deprecated but remains functional for existing users. We recommend that new customers should explore [Virtual Account](/docs/products/accept-payment/virtual-account) option for account creation. # Fetch parent account balance Source: https://developer.nomba.com/nomba-api-reference/accounts/fetch-parent-account-balance get /v1/accounts/balance You can use this endpoint to get the balance of the parent account. # Fetch parent account details Source: https://developer.nomba.com/nomba-api-reference/accounts/fetch-parent-account-details get /v1/accounts/parent You can use this endpoint to get details of the parent account. # Fetch sub account balance Source: https://developer.nomba.com/nomba-api-reference/accounts/fetch-sub-account-balance get /v1/accounts/{subAccountId}/balance You can use this endpoint to get the balance of a sub account # Fetch sub account details Source: https://developer.nomba.com/nomba-api-reference/accounts/fetch-sub-account-details get /v1/accounts/sub-account-details You can use this endpoint to get details of a sub account. *** # Fetch terminals assigned to a sub account Source: https://developer.nomba.com/nomba-api-reference/accounts/fetch-terminals-assigned-to-a-sub-account get /v1/accounts/{accountId}/terminals You can use this endpoint to fetch terminals linked to a sub account. # Fetch terminals assigned to the parent account Source: https://developer.nomba.com/nomba-api-reference/accounts/fetch-terminals-assigned-to-the-parent-account get /v1/accounts/terminals You can use this endpoint to fetch terminals linked to the parent account. # Fetch data plans available on a telco (network provider) Source: https://developer.nomba.com/nomba-api-reference/airtime-and-data-vending/fetch-data-plans-available-on-a-telco-network-provider get /v1/bill/data-plan/{telco} You can use this endpoint to fetch data plans available on a telco (network provider) # Make airtime purchases via parent account Source: https://developer.nomba.com/nomba-api-reference/airtime-and-data-vending/make-airtime-purchases-via-parent-account post /v1/bill/topup You can use this endpoint to make airtime purchases via parent account # Vend data bundles via parent account Source: https://developer.nomba.com/nomba-api-reference/airtime-and-data-vending/vend-data-bundles-via-parent-account post /v1/bill/data You can use this endpoint to vend data via parent account # Obtain access token Source: https://developer.nomba.com/nomba-api-reference/authenticate/obtain-access-token post /v1/auth/token/issue You can use this endpoint to authenticate with Nomba. # Refresh an expired token Source: https://developer.nomba.com/nomba-api-reference/authenticate/refresh-an-expired-token post /v1/auth/token/refresh You can use this endpoint to refresh an expired `access_token`. # Revoke an access_token Source: https://developer.nomba.com/nomba-api-reference/authenticate/revoke-an-access_token post /v1/auth/token/revoke You can use this endpoint to revoke an `access_token`. # Fetch betting providers Source: https://developer.nomba.com/nomba-api-reference/bills/fetch-betting-providers get /v1/bill/betting/providers You can use this endpoint to fetch betting providers # Fetch discos/electricity providers Source: https://developer.nomba.com/nomba-api-reference/bills/fetch-electricity-providers get /v1/bill/electricity/discos You can use this endpoint to fetch electricity providers/discos # Fetch customer information from a betting provider Source: https://developer.nomba.com/nomba-api-reference/bills/name-lookup-for-betting get /v1/bill/betting/lookup This endpoint is for fetching customer information data from a bet vending provider # Fetch customer information from a cable tv provider Source: https://developer.nomba.com/nomba-api-reference/bills/name-lookup-for-cabletv get /v1/bill/cabletv/lookup This endpoint is for fetching customer information data # Fetch customer information from an electricity provider Source: https://developer.nomba.com/nomba-api-reference/bills/name-lookup-for-electricity get /v1/bill/electricity/lookup This endpoint is for fetching customer information data from an electricity vending provider # Vend betting via parent account Source: https://developer.nomba.com/nomba-api-reference/bills/pay-for-betting-via-parent-account post /v1/bill/betting You can use this endpoint to vend betting via parent account # Vend electricity via parent account Source: https://developer.nomba.com/nomba-api-reference/bills/pay-for-electricity-via-parent-account post /v1/bill/electricity You can use this endpoint to vend electricity via parent account # CableTv subscription via parent account Source: https://developer.nomba.com/nomba-api-reference/bills/subscribe-to-cabletv-via-parent-account post /v1/bill/cabletv You can use this endpoint to make cable tv subscription via parent account # Cancel Checkout transaction Source: https://developer.nomba.com/nomba-api-reference/charge/cancel-checkout-transaction post /v1/checkout/transaction/cancel Use this endpoint to Cancel an incomplete checkout transaction # Fetch checkout Flash account number for transfer payment Source: https://developer.nomba.com/nomba-api-reference/charge/fetch-checkout-flash-account-number-for-transfer-payment get /v1/checkout/get-checkout-kta/{orderReference} Use this endpoint to Get a flash account number which the customer can use to make a transfer payment. # Fetch checkout transaction details Source: https://developer.nomba.com/nomba-api-reference/charge/fetch-checkout-transaction-details post /v1/checkout/confirm-transaction-receipt Use this endpoint to fetch the checkout transaction details and get the status of the transaction after OTP is submitted or transfer is made # Get Order details based on the generated Order reference Source: https://developer.nomba.com/nomba-api-reference/charge/get-order-details-based-on-the-generated-order-reference get /v1/checkout/order/{orderReference} Use this endpoint to fetch a single checkout order, using the order reference that was returned when the Order was created # Get user saved cards Source: https://developer.nomba.com/nomba-api-reference/charge/get-user-saved-cards get /v1/checkout/user-card/{orderReference} Use this endpoint to Get a user's saved cards. Requires user OTP send to the user after calling /checkout/user-card/saved-card/auth # Request OTP before saving a user's card Source: https://developer.nomba.com/nomba-api-reference/charge/request-user-otp post /v1/checkout/user-card/auth Use this endpoint to request an OTP to be sent to be sent to the users phone number to authenticate the user before saving the card. This endpoint is called after payment is successful, and the user requested to save their card for later. # Request OTP to validate a user before fetching saved cards Source: https://developer.nomba.com/nomba-api-reference/charge/request-user-otp-1 post /v1/checkout/user-card/saved-card/auth Use this endpoint to request an OTP to be sent to a user's phone number to authenticate before retrieving the saved cards mapped to the user's email. Use this endpoint when the Order details endpoint indicates the user already has saved cards. # Resend OTP to customer's phone Source: https://developer.nomba.com/nomba-api-reference/charge/resend-otp-to-customers-phone post /v1/checkout/resend-otp Use this endpoint to resend the payment OTP to the customer's phone # Submit customer card details Source: https://developer.nomba.com/nomba-api-reference/charge/submit-customer-card-details post /v1/checkout/checkout-card-detail Use this endpoint to submit the customers card details # Submit customer card OTP Source: https://developer.nomba.com/nomba-api-reference/charge/submit-customer-card-otp post /v1/checkout/checkout-card-otp Use this endpoint to submit the payment OTP sent to the customer's phones from the payment gateway # Submit user OTP Source: https://developer.nomba.com/nomba-api-reference/charge/submit-user-otp post /v1/checkout/user-card Use this endpoint to submit the user OTP send to the user's mobile number. This will result in the user's card being saved for later use. # Get Mandate Status Source: https://developer.nomba.com/nomba-api-reference/direct-debits/check-direct-debit-status get /v1/direct-debits/status?mandateId={mandateId} Fetches the status of a specific mandate by mandateId. # Create a Direct Debit Mandate Source: https://developer.nomba.com/nomba-api-reference/direct-debits/create-direct-debit post /v1/direct-debits Creates a new direct debit mandate for a customer. # Debit a mandate Source: https://developer.nomba.com/nomba-api-reference/direct-debits/debit-mandate post /v1/direct-debits/debit-mandate Debits a customer's account using an active mandate. # Get mandates by filters Source: https://developer.nomba.com/nomba-api-reference/direct-debits/list-direct-debit-mandates get /v1/direct-debits/mandates # Update mandate status Source: https://developer.nomba.com/nomba-api-reference/direct-debits/update-direct-debit-status put /v1/direct-debits/update-status Updates the status of a direct debit mandate (e.g., SUSPEND, ACTIVE). # Get API Keys Source: https://developer.nomba.com/nomba-api-reference/get-api-keys We are excited to have you here. You can effortlessly create your API keys within your Nomba dashboard. Navigate to your settings and click on the `API Keys` tab. You will find an interface similar to the image below. Kindly follow the steps illustrated in the above image to generate your API Key. Once the API Keys are generated, you can copy them for integration with the Nomba API. After copying, make an effort to [Obtain a token.](/docs/getting-started/get-api-keys) # Fetch drc inflow providers Source: https://developer.nomba.com/nomba-api-reference/global-collections/fetch-drc-inflow-providers get /v1/global-collection/drc/inflow/providers Returns the list of mobile money providers supported for DRC inflow. Use the returned code values as the topupVendor in the Initiate Mobile Money Inflow request. # Fetch mobile money transaction Source: https://developer.nomba.com/nomba-api-reference/global-collections/fetch-mobile-money-transaction get /v1/global-collection/transactions/{transactionId} Retrieve the status of an initiated mobile money collection. # Initiate mobile money inflow Source: https://developer.nomba.com/nomba-api-reference/global-collections/initiate-mobile-money-inflow post /v1/global-collection/inflow/initiate Trigger a mobile money collection request from a customer. # Authorize exchange Source: https://developer.nomba.com/nomba-api-reference/global-payout/authorize-exchange post /v1/global-payout/exchange/authorize Transfer funds between your own accounts in different currencies. # Authorize transfer Source: https://developer.nomba.com/nomba-api-reference/global-payout/authorize-transfer post /v1/global-payout/transfer/authorize Initiate and authorize a cross-border transfer. Manages the complete transfer lifecycle from initiation to final authorization. Supports BANK, MobileMoney, INTERAC, FASTER_PAYMENTS, SEPA, ACH, and WIRE payment methods. # Convert money Source: https://developer.nomba.com/nomba-api-reference/global-payout/convert-money post /v1/global-payout/money/convert Calculate a currency conversion and lock an exchange rate before initiating a transfer. # Fetch account Source: https://developer.nomba.com/nomba-api-reference/global-payout/fetch-account get /v1/global-payout/accounts/{accountId} Retrieve the details and balance of a single Global Payout account by its account ID. # Fetch account sandbox Source: https://developer.nomba.com/nomba-api-reference/global-payout/fetch-account-sandbox get /v1/sandbox/global-payout/accounts/{accountId} Sandbox version of Fetch Global Payout Account. Returns canned account details and balance for the given account ID, for use in testing. # Fetch accounts Source: https://developer.nomba.com/nomba-api-reference/global-payout/fetch-accounts get /v1/global-payout/accounts Retrieve all of your currency wallets and their balances (e.g. CAD, USD) under your parent accountId. Use this to check a non-NGN balance instead of the NGN-only parent account endpoint. # Fetch accounts sandbox Source: https://developer.nomba.com/nomba-api-reference/global-payout/fetch-accounts-sandbox get /v1/sandbox/global-payout/accounts Sandbox version of Fetch Global Payout Accounts. Returns canned multi-currency account data for use in testing. # Fetch exchange rates Source: https://developer.nomba.com/nomba-api-reference/global-payout/fetch-exchange-rates get /v1/global-payout/exchange-rates Retrieve the latest exchange rates for a currency pair before initiating a transfer. # Fetch transaction Source: https://developer.nomba.com/nomba-api-reference/global-payout/fetch-transaction get /v1/global-payout/transactions/{transactionId} Track the status of any Global Payout transaction using its transaction ID. # Mobile money providers Source: https://developer.nomba.com/nomba-api-reference/global-payout/mobile-money-providers get /v1/global-payout/bank/providers Returns available bank, institution, or mobile money providers. Use isMobileMoney=false for bank/institution providers and isMobileMoney=true for mobile money providers. Use code as institutionCode and displayName as institutionName in Authorize Transfer. # Payment methods Source: https://developer.nomba.com/nomba-api-reference/global-payout/payment-methods get /v1/global-payout/payment-methods Returns all supported payment methods and their method-specific requirements. Filter by code or name to retrieve a specific method. # Introduction Source: https://developer.nomba.com/nomba-api-reference/introduction Interact with all our available API endpoints Feel free to conduct direct testing on this website. We strongly encourage and recommend utilizing this feature as an efficient means to promptly test functionalities and configurations on your end. **No account? No problem.** You can test Transfer, Virtual Account, and Checkout endpoints right now without a bearer token or accountId. Open any endpoint, click **Try it**, select **Sandbox** from the base URL dropdown, leave the auth fields blank, and send. [Learn more →](/docs/guides/try-the-api) ## Welcome While we advocate for leveraging the testing capability offered on this website, we recognize that you may also wish to create client SDKs tailored to your use case. We recommend utilizing [Nomba's OpenAPI Spec](https://github.com/kudi-inc/vendor-openapi-spec/blob/main/openapi3_0_v_1_0_0.json) along with the [well-known Swagger tool](https://swagger.io/tools/swagger-codegen/) for generating client SDKs. This method ensures a seamless and convenient validation process, providing you with the flexibility to refine and optimize your implementations with ease. Incorporating client SDKs into your workflow enhances the overall development experience and promotes efficiency in handling various aspects of API integration for your specific needs. ## Quick Action Authenticate with the Nomba API. Create a checkout payment link. Initiate money transfer transactions. ## OpenAPI Spec View the OpenAPI specification file ## Authentication Nomba streamlines the authentication of API calls through the utilization of [OAuth2 HTTP bearer tokens](http://tools.ietf.org/html/rfc6750). The authentication process encompasses two distinct methods, namely the [Client-credentials method](https://www.rfc-editor.org/rfc/rfc6749) and the [PKCE (Proof key for code exchange)](https://www.rfc-editor.org/rfc/rfc7636) method. In each method, an access\_token is generated, serving as the key to authenticate your API requests seamlessly. To furnish your API requests with the requisite access\_token, employ the `"Authorization"` HTTP header, as illustrated: `Authorization: {access_token}`. This robust and secure authentication mechanism ensures the integrity of your interactions with Nomba's API. For an in-depth comprehension of Nomba's authentication flow, explore further insights and details [available here](/docs/introduction/welcome-to-nomba). These resources offer a comprehensive guide to navigating the intricacies of our authentication processes, empowering you to harness the full potential of Nomba's capabilities for your API calls. ## IP Whitelisting Access to Nomba API endpoints in the production environment requires IP whitelisting. To get your IPs whitelisted, send a maximum of **3 static IPv4 addresses** to [docs@nomba.com](mailto:docs@nomba.com) and our team will process your request. ## Cross-Origin Resource Sharing The API incorporates Cross-Origin Resource Sharing (CORS) in accordance with the [W3C](https://w3.org/TR/cors) specifications. CORS support is essential, facilitating calls from the request maker embedded within the API documentation. This adherence to CORS standards enhances the versatility of the API, ensuring seamless and secure communication with the API docs request maker, thereby contributing to an optimal developer experience. # Cancel Checkout Order Source: https://developer.nomba.com/nomba-api-reference/online-checkout/cancel-checkout-order post /v1/checkout/order/cancel Use this endpoint to cancel an incomplete or pending checkout order. # Charge a customer using tokenized card data Source: https://developer.nomba.com/nomba-api-reference/online-checkout/charge-a-customer-using-tokenized-card-data post /v1/checkout/tokenized-card-payment You can use this endpoint to charge a customer's card using the tokenized card details. # Create an online checkout order Source: https://developer.nomba.com/nomba-api-reference/online-checkout/create-an-online-checkout-order post /v1/checkout/order You can use this endpoint to create an online checkout order. Load the URL returned in 'checkoutLink' property in a browser to allow your customer initiate payment. # Delete tokenized card data Source: https://developer.nomba.com/nomba-api-reference/online-checkout/delete-tokenized-card-data delete /v1/checkout/tokenized-card-data Delete a tokenized card details # Fetch checkout transaction Source: https://developer.nomba.com/nomba-api-reference/online-checkout/fetch-checkout-transaction get /v1/checkout/transaction Fetch checkout transaction # List tokenized cards Source: https://developer.nomba.com/nomba-api-reference/online-checkout/list-tokenized-cards get /v1/checkout/tokenized-card-data Fetch list of merchant's tokenized cards # Refund checkout transaction Source: https://developer.nomba.com/nomba-api-reference/online-checkout/refund-checkout-transaction post /v1/checkout/refund You can use this endpoint to refund a checkout transaction. # Update tokenized card data Source: https://developer.nomba.com/nomba-api-reference/online-checkout/update-tokenized-card-data post /v1/checkout/tokenized-card-data Update a tokenized card details # Fetch a single transaction on a sub account Source: https://developer.nomba.com/nomba-api-reference/requery/fetch-a-single-transaction-on-a-sub-account get /v1/transactions/accounts/{subAccountId}/single You can use this endpoint to fetch a single transaction on a sub account # Fetch a single transaction on the parent account Source: https://developer.nomba.com/nomba-api-reference/requery/fetch-a-single-transaction-on-the-parent-account get /v1/transactions/accounts/single You can use this endpoint to fetch a single transaction on the parent account. # Confirm a transaction's status by sessionId Source: https://developer.nomba.com/nomba-api-reference/requery/transaction-requery get /v1/transactions/requery/{sessionId} This endpoint is for fetching (requerying) a transaction status. # Assign a terminal to a sub account Source: https://developer.nomba.com/nomba-api-reference/terminals/assign-a-terminal-to-a-sub-account post /v1/terminals/assign/{subAccountId} You can use this endpoint to assign a terminal to an sub account. # Assign a terminal to the parent account Source: https://developer.nomba.com/nomba-api-reference/terminals/assign-a-terminal-to-the-parent-account post /v1/terminals/assign You can use this endpoint to assign a terminal to the parent account. # Send payment request to terminal Source: https://developer.nomba.com/nomba-api-reference/terminals/push-payment-request post /v1/terminals/payment-request/{terminalId} You can use this endpoint to trigger a payment request on a nomba terminal # Un-assign a terminal from the parent account Source: https://developer.nomba.com/nomba-api-reference/terminals/un-assign-a-terminal-from-the-parent-account post /v1/terminals/unassign You can use this endpoint to un-assign a terminal from the parent account. # Un-assign terminal from a sub account Source: https://developer.nomba.com/nomba-api-reference/terminals/un-assign-a-terminal-from-the-sub-account post /v1/terminals/unassign/{subAccountId} You can use this endpoint to un-assign a terminal from a sub account. # Fetch credit/debit transactions on the parent account Source: https://developer.nomba.com/nomba-api-reference/transactions/fetch-creditdebit-transactions-on-the-parent-account get /v1/transactions/bank You can use this endpoint to fetch credit/debit transactions on the parent account. # Fetch transactions on the parent account Source: https://developer.nomba.com/nomba-api-reference/transactions/fetch-transactions-on-the-parent-account get /v1/transactions/accounts You can use this endpoint to fetch transactions on the parent account. # Fetch transactions on a sub account Source: https://developer.nomba.com/nomba-api-reference/transactions/fetch-transactions-on-the-sub-account get /v1/transactions/accounts/{subAccountId} You can use this endpoint to fetch transactions on a sub account. # Filter parent account transactions Source: https://developer.nomba.com/nomba-api-reference/transactions/filter-parent-account-transactions post /v1/transactions/accounts You can use this endpoint to filter transactions on the parent account. # Filter sub account transactions Source: https://developer.nomba.com/nomba-api-reference/transactions/filter-sub-account-transactions post /v1/transactions/accounts/{subAccountId} You can use this endpoint to filter transactions on a sub account. # Fetch bank codes and names Source: https://developer.nomba.com/nomba-api-reference/transfers/fetch-bank-codes-and-names get /v1/transfers/banks Retrieve all supported Nigerian banks with their codes and names. Cache this response — bank codes rarely change. Use the `code` field as `bankCode` in transfer and account lookup requests. # Perform bank account lookup Source: https://developer.nomba.com/nomba-api-reference/transfers/perform-bank-account-lookup post /v1/transfers/bank/lookup Verify a recipient bank account number before initiating a transfer. Returns the account holder's name. Always call this before a bank transfer so users can confirm the recipient. # Perform bank account transfer from the parent account Source: https://developer.nomba.com/nomba-api-reference/transfers/perform-bank-account-transfer-from-the-parent-account post /v2/transfers/bank Initiate a bank transfer from the parent account to an external Nigerian bank. Returns immediately with a `data.status` of `SUCCESS` or `PENDING_BILLING`. Listen for webhook notifications for final status, or poll using the returned `data.id`. On failure, the account is auto-refunded and status becomes `REFUND`. # Perform bank account transfer from the sub account Source: https://developer.nomba.com/nomba-api-reference/transfers/perform-bank-account-transfer-from-the-sub-account post /v2/transfers/bank/{subAccountId} Initiate a bank transfer from a specific sub-account. Useful when managing multiple balances under your main account. Sub-account transfers must be enabled by Nomba before use. Sub-accounts can only be created from the Nomba dashboard. # Perform wallet transfer from a sub account Source: https://developer.nomba.com/nomba-api-reference/transfers/perform-wallet-transfer-from-a-sub-account post /v2/transfers/wallet/{subAccountId} Transfer funds from a specific sub-account to another Nomba account (P2P). Near-instant settlement with no external processor. Sub-account transfers must be enabled by Nomba before use. # Perform wallet transfer from the parent account Source: https://developer.nomba.com/nomba-api-reference/transfers/perform-wallet-transfer-from-the-parent-account post /v2/transfers/wallet Transfer funds between Nomba accounts (P2P). Bypasses external processors for near-instant settlement. Returns synchronously with `data.status: SUCCESS`. Note: wallet transfers do not return a `sessionId` — use the parent account requery endpoint for status checks. # Create virtual account Source: https://developer.nomba.com/nomba-api-reference/virtual-accounts/create-virtual-account post /v1/accounts/virtual You can use this endpoint to create a virtual account to receive payments. # Create virtual account for a sub account Source: https://developer.nomba.com/nomba-api-reference/virtual-accounts/create-virtual-account-for-sub-account post /v1/accounts/virtual/{subAccountId} You can use this endpoint to create a virtual account to receive payments for a sub account. Funds sent to the virtual account is collected in the sub account specified # Expire a virtual account Source: https://developer.nomba.com/nomba-api-reference/virtual-accounts/expire-a-virtual-account delete /v1/accounts/virtual/{identifier} You can use this endpoint to expire a virtual account. # Fetch a virtual account Source: https://developer.nomba.com/nomba-api-reference/virtual-accounts/fetch-a-virtual-account get /v1/accounts/virtual/{identifier} You can use this endpoint to fetch a virtual account. # Filter virtual accounts Source: https://developer.nomba.com/nomba-api-reference/virtual-accounts/filter-virtual-accounts post /v1/accounts/virtual/list You can use this endpoint to filter your virtual accounts. # Update a virtual account Source: https://developer.nomba.com/nomba-api-reference/virtual-accounts/update-a-virtual-account put /v1/accounts/virtual/{identifier} You can use this endpoint to update a virtual account.