Overview
The Payroll API turns a list of staff and salaries into a single approved disbursement. It exists so you stop looping overPOST /money-transfer/send once per employee, which gives you
no batch-level total, no way to check funding before you start, and no way to
stop halfway.
The flow is always the same: build a batch, let Hyparrow validate every
beneficiary against their bank, confirm the wallet covers it, then approve once.
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. Sandbox batches run the full lifecycle — reserve, send, settle,
webhook — without touching a live bank, so you can exercise an entire payroll
end to end.How the money moves
This is the part worth reading before you integrate, because it differs from a single transfer.1
Approval reserves the whole batch at once
When you approve, Hyparrow debits principal + fees for the entire batch
from your wallet in one atomic operation and holds it as a reservation. Your
balance drops immediately; the held amount appears as reservedBalance.2
Each payment draws from the reservation
Beneficiary transfers are submitted one at a time, each drawing its own
principal and fee out of the reservation. Each gets its own transfer code
while staying linked to the batch reference.
3
Anything that never leaves is released
A beneficiary the bank rejects is reversed back into the reservation. When the
batch closes, everything unspent is released to your spendable balance.
Quickstart
Create a batch with beneficiaries inline. Hyparrow validates every row and resolves every account name before returning.Response
reference is the batch-level reference every payment links back to. Send your
own clientReference too: it is stored verbatim and echoed on every payroll
webhook, so a create call whose response you never received still leaves you
holding a key Hyparrow recognises.
Validation
Every row is checked before a batch can be approved. Nothing is ever silently corrected — a row that cannot be paid is returned markedinvalid with the
reasons in validationErrors, and the merchant fixes it.
Account name matching
Hyparrow resolves every account number with the bank and compares the returned name against the name on the row. The result is innameMatch:
Uploading a file
POST /payroll/batches/upload accepts a CSV or XLSX file as multipart form data
under the file field. GET /payroll/template returns a ready-made CSV template.
Account Number, account_number, Acct No
and NUBAN all resolve to the same field — and the header row is located even
when the export opens with a company name or a title. Currency symbols, thousands
separators and the leading apostrophe Excel adds to preserve a leading zero are
all handled.
A row whose amount is unreadable is still returned, marked invalid with the
reason, so you see every problem in one pass rather than one per re-upload. Limits:
5 MB, .csv / .xlsx.
Checking funding
CallGET /payroll/batches/{id}/funding before you prompt anyone for a code.
data, so you can tell the merchant exactly how much to
add without parsing an error string.
Approving
skipped and never paid. The response returns immediately with the
batch in approved; submission continues in the background.
Send exactly one of code or mandateId. Sending both, or neither, is a 400.
API approval mandates
If your product assembles payroll and your customer (the employer) approves it in your product, your server cannot type the Hyparrow owner’s TOTP code, and it should not hold their authenticator secret. An approval mandate covers this. The owner arms it once from the dashboard with their code, and it then lets one API key approve the batches that key creates, within limits the owner sets.1
The owner arms a mandate in the dashboard
Under Payroll → Approval mandates, the owner picks the API key, sets the
limits, and confirms with their authenticator code. The mandate’s
id is what
your integration sends. Arming is dashboard-only: no API key can arm a
mandate, including its own.2
Your integration creates and validates the batch with that key
Use the normal batch endpoints. A mandate only ever approves batches created
with the same API key it is bound to.
3
Approve with the mandate and name your approver
Send
mandateId plus externalApproval, which records who approved the
payroll in your product. It is stored on the batch and echoed on
payroll.batch.approved, so every run is attributable to a person at the
employer.What a mandate bounds
Your account limits still apply on top. Name-mismatch rows still need
acknowledgeNameMismatches: true, exactly as with a code. A mandate is spent
atomically with the approval: two approvals racing on one mandate cannot both use
its last batch or its remaining monthly allowance, and a failed approval (for
example a 402 for insufficient funds) does not use it up.
A batch the mandate does not cover is refused with 403 and
code: "MANDATE_NOT_USABLE", and the message says which limit it hit. Nothing is
reserved or sent. Fall back to an approval with a code, or ask the owner to arm a
new mandate.
The owner gets an in-app notification when a mandate is armed and every time one
approves a payroll.
Managing mandates
Batch statuses
Item statuses
sent is not success. Like a single transfer, the local record is written when
your wallet is debited, before the network confirms anything. Wait for
delivered, or for the payroll.item.settled webhook.Webhooks
Configure your URL withPOST /webhooks/settings (see Webhooks).
Payroll emits four events, all using the standard event / timestamp / data
envelope.
transferCode and batchReference, so you can
reconcile per employee or per run without maintaining your own mapping.
The staff directory
Instead of sending beneficiaries with every batch, keep them in a directory and generate a batch from it. Accounts are verified once and reused, so a monthly run does not re-resolve the same account names every month.
Then create a batch with
{"name": "...", "payPeriod": "2026-08", "fromDirectory": true}
to bill every active employee at their defaultAmount.
Limits
GET /payroll/limits returns the caps in force for your account.
Full endpoint reference
Errors
Scheduled payroll — a recurring run that disburses under a bounded standing
authorization — is available in the Hyparrow dashboard. It is not exposed on the
API, because arming it requires a live second factor from the account owner.

