Skip to main content

Overview

The Money Transfer API sends funds from your Hyparrow wallet to any Nigerian bank account over the bank network. The flow is always the same: list the supported banks, resolve the recipient’s account name from their account number, initiate the transfer, then poll for the final status. When you initiate a transfer, Hyparrow debits the principal from your wallet before calling the bank network, then books the fee as a separate debit only after the network accepts the transfer. If the network rejects the transfer, the principal debit is automatically reversed, so a rejected transfer never leaves your wallet short. If the network does not answer (a timeout), the transfer is treated as submitted, never reversed on a guess, and its outcome comes by webhook. See Unknown outcome.
Base URL: https://api.hyparrow.cloud/api/v1Auth: every request requires X-API-Key and X-API-Secret headers.Sandbox: point at https://sandbox.hyparrow.cloud/api/v1 and use your pk_test_ key. Simulate outcomes with magic amounts, an amount ending in .01 is rejected at submission (the send returns 400, the principal is reversed, no fee is charged and transfer.reversed fires), and .99 stays pending (accepted, never settles) so you can test status polling. Everything else is accepted and later settles, firing transfer.settled.
Amounts are in kobo. All transfer amounts are integers in minor units passed as strings, "500000" means ₦5,000.00. Fees are quoted in Naira and charged on top of the principal.

The transfer flow

1

List banks

GET /money-transfer/banks returns supported banks. Each entry has a bankCode, use this exact value for inquiry and send.
2

Resolve the account name

POST /money-transfer/account-inquiry (or GET) with the account number and bank code returns the registered account name. Show it to the user to confirm.
3

Send

POST /money-transfer/send debits the wallet (principal first, then fee on success) and initiates the transfer over the bank network.
4

Poll status

GET /money-transfer/status?reference=<transferCode|clientReference> (or POST) returns the current status until it settles.

List banks

List banks
Response
Always use the bankCode field (the CBN code) for account-inquiry and send. The separate code field is an internal identifier and is not used for transfers.

Resolve the account name

Confirm the recipient before you send. Supply the accountNumber and the bankCode from the bank list. This endpoint accepts both GET (query params) and POST (JSON body).
Account inquiry (GET)
Account inquiry (POST)
Response
The accountName you get back is what you pass as recipientName when you send.
Account couldn’t be resolved. If the name lookup fails on every network, you get a 503 with a retry-friendly message instead of an error code. Do not proceed to send, re-check the account number and bank, then retry shortly:

Send a transfer

POST /money-transfer/send initiates the transfer. The wallet is checked for the principal plus the fee up front; the principal is debited before the bank network is called, and the fee is debited only after the network accepts.

Request body

Send a clientReference.Without one, the only handle on a transfer is the transferCode we return, so a send whose response you never receive (a timeout, a dropped connection, a crash between the call and your database write) leaves you holding nothing we can look up. GET /money-transfer/status answers 404 Transfer not found for a transfer that may well have been delivered, and from your side a settled payout is indistinguishable from one that never happened.With one, the transfer is resolvable by a reference you generated before the call, so it is recoverable no matter what happens to the response. It is stored against the transaction, echoed on the transfer.settled, transfer.failed and transfer.reversed webhooks, and accepted by the status endpoint in place of the transferCode.

Idempotency

A clientReference names exactly one transfer, for good. It is never expired or reused. A replay returns the transfer as it stands, including Status: "reversed" if the first attempt was rejected. To try again after a rejection, send a new clientReference.
409 Response
You can also send an Idempotency-Key header, which works across all money routes. A key is remembered for 24 hours; a repeat with the identical body replays the first successful response, and a repeat with a different body gets 422 IDEMPOTENCY_KEY_REUSED. Only successful responses are remembered, so a request refused with a 4xx (for example insufficient balance) can be retried with the same key once the cause is fixed. For transfers, clientReference is the stronger guarantee: it never expires and it holds across keys.
Send
Response
Status: "pending" means accepted and not yet settled. The final outcome arrives on transfer.settled or transfer.failed, normally within about 10 minutes. Keep data.TransferCode, it is the reference you use to check status. If you sent a clientReference, you can check status with that instead and do not need to have received this response at all.

Wallet debit and fees

The total debited is principal + fee:
  • The wallet must cover the principal and the fee, or the send is rejected before anything is charged.
  • The principal is debited first (atomically, with a row lock) so funds can’t leak if the network call partially fails.
  • The fee is a flat amount based on your transfer fee class and the amount tier. It is booked as a separate debit and only after the network accepts the transfer, a failed or reversed transfer is never charged a fee.
data.Fee is the fee in kobo, data.FeeClass is the fee class applied, and data.WalletBalance is your remaining balance after principal + fee.

Fee schedule

GET /money-transfer/fee-class returns the fee ladder for your own account, so you can quote the fee before sending and reconcile it after.
Fee class
Response
Tiers come back ordered ascending: to price a transfer, convert the principal to Naira and take the fee of the first band whose max is null or >= amount. A ₦5,000 transfer on the response above costs ₦25; a ₦200,000 transfer costs ₦77.
Read the ladder, don’t hardcode it. Fee tiers are tunable at runtime and your class can change, so a copied table will silently drift. Fetch this endpoint (cache it briefly if you like) and quote from the response. Note the unit switch: transfer amounts are in kobo, but the fee ladder is in Naira, data.Fee on the send response is in kobo.

Check status

GET /money-transfer/status?reference=<transferCode> (or POST with a JSON body) returns both Hyparrow’s local transaction record and the latest network status. reference accepts either the transferCode from the send response or the clientReference you sent with the transfer. Both are scoped to the calling merchant: you can only ever read your own transfers, by either name for them. Looking up by clientReference is what makes a transfer recoverable when the send response was lost.
Status
Response
Read settlementStatus to know where the money is: status is the ledger row’s own state and reads success from the moment of the debit, so it does not tell you whether the transfer landed. provider is the network’s live answer, fetched on each call.

Edge cases

Insufficient balance. If the wallet can’t cover principal + fee, the send is rejected before any debit, and the error spells out the shortfall:
Rejected transfer is reversed. If the bank network refuses the transfer at submission, Hyparrow credits the principal back to your wallet straight away (a reversal transaction referenced REV_<code>), charges no fee, sends transfer.reversed, and returns 400 (or 502 if the request never left Hyparrow). The transfer’s settlementStatus is reversed.

Unknown outcome (202)

If the bank network does not answer (a timeout, a dropped connection, a 5xx), the transfer may or may not have gone through, and refunding on a guess is how a payout ends up sent twice. So Hyparrow treats it as submitted: the principal and fee stay debited and you get 202 Accepted with the transferCode.
202 Response
Do not resend. Wait for the webhook or poll status. If the network never received it, the transfer is failed and reversed (principal and fee) after review, and transfer.reversed tells you.
A pending transfer (a .99 amount in sandbox, or a slow settlement in production) has been accepted but not yet settled. Poll /money-transfer/status until settlementStatus moves to delivered, failed or reversed, or wait for the webhook. The principal stays debited while pending.