Skip to main content

Documentation Index

Fetch the complete documentation index at: https://developer.nomba.com/llms.txt

Use this file to discover all available pages before exploring further.

Perform bank transfers from the parent account

Perform bank transfers from the sub-account

POST /v2/transfers/bank

⚠️ Rate Limit Notice:
Users are restricted to 5 bank transfers to the same recipient per minute.
curl --request POST \
  --url https://api.nomba.com/v2/transfers/bank \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --header 'accountId: <accountid>' \
  --data '{
    "amount": 3500,
    "accountNumber": "055472814",
    "accountName": "M.A Animashaun",
    "bankCode": "058",
    "merchantTxRef": "UNQ_123abGGhh5546",
    "senderName": "Nightly Post",
    "narration": "Nice One"
  }'

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.
curl --request POST \
  --url https://api.nomba.com/v2/transfers/bank/{subAccountId} \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --header 'accountId: <accountid>' \
  --data '{
    "amount": 3500,
    "accountNumber": "055472814",
    "accountName": "M.A Animashaun",
    "bankCode": "058",
    "merchantTxRef": "UNQ_123abGGhh5546",
    "senderName": "Nightly Post",
    "narration": "Nice One"
  }'

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
{
   "successful": true,
  "status": "SUCCESS",
  "message": "Success",
  "data": {
    "id": "API-TRANSFER-02145-XXXXX-8857-417f-a954-1234",
    "status": "SUCCESS"
  }
}
Example 2 β€” Transfer processing
{
  "successful": true,
  "status": "SUCCESS",
  "message": "Success",
  "data": {
    "id": "API-TRANSFER-02415-XXXX-8857-417f-1234",
    "status": "PENDING_BILLING"
  }
}
Example 3 β€” Transfer processing
{
  "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

1

Wait for Webhook (Recommended)

Once the transaction is completed, a webhook notification will be sent to your system.
2

Poll for Status (Optional)

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
GET /v1/transactions/accounts/single?transactionRef=API-TRANSFER-XXX-XXX
  • If you are transferring from a sub account, use this
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
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.
{
  "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.
{
  "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 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

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

amount
number
required
The amount to be transferred.
accountNumber
string
required
The destination bank account number.
accountName
string
required
The name on the account.
bankCode
string
required
The code of the recipient bank.
merchantTxRef
string
required

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.

senderName
string
required
The sender’s name.
narration
string
The narration for this transfer (NB: This will be appended to the normal system generated narration).

Response body

id
string
required
The transfer ID.
status
string
required
The transaction status.
type
string
required
The transaction type.
amount
number
required
The transfer amount.
fee
number
The transfer fee.
source
string
Payment source (e.g., β€œapi”).
sourceUserId
string
The user who initiated the transfer.
customerBillerId
string
The biller account ID.
productId
string
Product code for the transfer.
meta
object
required
Additional transaction metadata.
userId
string
Associated user ID.
timeCreated
string
required
Creation timestamp.