PaymonetraDocs

Transfers

Money out of your balance to any Nigerian bank account.

Pay any Nigerian bank account from your balance, such as your users' withdrawals.

  • Off by default. Test keys work now. Live transfers are switched on per business by Paymonetra, with a per-transfer and a daily limit; until then 403 transfers_not_enabled.
  • Only from your servers. Live calls must come from the server IPs listed on the dashboard (Developers, API transfers), otherwise 403 ip_not_allowed.
  • Fee on top. The recipient gets amount; your balance falls by total. Transfers use the ready figure from GET /balance.
  • Sender name. The recipient's bank shows your registered business name, which for a sole trader is usually the owner's name. Put your brand in narration.

#The order to call them in

  1. GET /banks for the code. Do not keep your own list.
  2. POST /transfers/resolve to see whose account it is, and show that name to your user.
  3. POST /transfers with your own reference, and pass account_name so a wrong number is refused rather than paid.
  4. Take the webhook, or poll GET /transfers/{reference}.

#List banks

GEThttps://api.paymonetra.com/v1/banksSecret key
JSON
{ "banks": [ { "bank_code": "000013", "bank_name": "Guaranty Trust Bank" } ] }

Use these codes, not your own list.

#Resolve an account

POSThttps://api.paymonetra.com/v1/transfers/resolveSecret key

Look up an account's name before paying it.

JSON
{ "bank_code": "000013", "account_number": "0123456789" }
JSON
{ "account_name": "ADEBAYO OLUWASEUN", "account_number": "0123456789",
  "bank_code": "000013", "bank_name": "Guaranty Trust Bank" }

422 account_not_found if the bank does not recognise it. Live keys need transfers switched on and a listed IP, as for sending.

#Send a transfer

POSThttps://api.paymonetra.com/v1/transfersSecret key
JSON
{
  "reference": "wd_8f2c91",
  "amount": 25000,
  "bank_code": "000013",
  "account_number": "0123456789",
  "account_name": "Adebayo Oluwaseun",
  "narration": "Wallet withdrawal"
}
fieldrequirednotes
referenceyesyour unique id, up to 100 letters, digits, . - _. Reusing it returns the first transfer.
amountyesnaira, minimum 100
bank_codeyesfrom GET /banks
account_numberyesten digits
account_namenothe name you expect. If it does not match the bank's, nothing is sent (name_mismatch). Recommended.
narrationnoup to 100 characters, on the recipient's statement

Answers 201 with the transfer, or 200 with the existing one when the reference was used before:

JSON
{
  "reference": "wd_8f2c91",
  "transfer_reference": "PMT-3F9A1C22B7D0",
  "status": "success",
  "amount": 25000, "fee": 50, "stamp_duty": 50, "total": 25100, "currency": "NGN",
  "recipient": { "account_name": "ADEBAYO OLUWASEUN", "account_number": "0123456789",
                 "bank_code": "000013", "bank_name": "Guaranty Trust Bank" },
  "narration": "Wallet withdrawal",
  "reason": null,
  "source": "api",
  "mode": "live",
  "created_at": "2026-09-28T12:30:00+01:00",
  "completed_at": "2026-09-28T12:30:04+01:00",
  "reversed_at": null
}

status, the one field to branch on:

statusmeanswhat to do
successit arrivedmark your withdrawal paid
processingsent, not yet confirmed by the bankwait for the webhook or poll. Do not resend under a new reference.
failedit did not go; reason says whythe money is back in your balance; retry with a new reference
reversedit arrived, then the receiving bank sent it backthe whole total is back in your balance

A transfer we accepted that then failed still returns 201 with status: "failed". A 4xx means nothing was created:

codehttpmeans
invalid_request422field names the problem
name_mismatch422the account belongs to somebody else; the message names them
account_not_found422the bank does not recognise the account
amount_over_limit422above your per-transfer limit
daily_limit422today's API transfers, fees included, would pass your daily limit; carries remaining_today
insufficient_ready422your ready balance does not cover total
transfers_not_enabled403live transfers are not switched on for this business
ip_not_allowed403the call did not come from a listed server
provider_error502we could not reach the bank; nothing was sent, retry the same reference

Test mode. Transfers succeed, except to account 0000000000, which fails.

#Fetch transfers

GEThttps://api.paymonetra.com/v1/transfers/{reference}Secret key
GEThttps://api.paymonetra.com/v1/transfersSecret key

By your reference or our transfer_reference. The list is newest first, limit (up to 100) and offset.

#Webhooks

transfer.success, transfer.failed and transfer.reversed, to your webhook URL, signed like every other event, with the transfer above as data. Each is sent once per transfer. Transfers made on the dashboard send them too.

Signed like every other event. The recipe is on webhooks.