Transfers
Resolve a beneficiary, quote the fee, and send money.
A transfer has three steps: resolve the account, check the fee, then send. This module is called transfers.
Resolve the beneficiary
Find the bank code with GET /transfers/banks, then confirm the account name. Show the name to your user, or check it against your records, before you continue.
curl https://api.payinto.co/api/v1/business/transfers/resolve-account \
--header "Authorization: Bearer $PAYINTO_SECRET_KEY" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data '{
"bank_code": "058",
"account_number": "0123456789"
}'Keep data.reference for the next steps:
{
"status": "success",
"message": "Account resolved successfully.",
"timestamp": 1793404800000,
"data": {
"reference": "0196431c-6e02-7a44-8d1f-52b1c9e07a33",
"bank_code": "058",
"bank_name": "Guaranty Trust Bank",
"account_name": "Ada Example",
"alias": null,
"account_number": "0123456789",
"is_saved": false,
"updated_at": "2026-10-31T09:00:00.000000Z",
"bank_logo_url": null
}
}Quote the fee (optional)
POST /transfers/fee returns the total that will leave your account.
curl https://api.payinto.co/api/v1/business/transfers/fee \
--header "Authorization: Bearer $PAYINTO_SECRET_KEY" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data '{
"amount": 250000,
"beneficiary_bank_code": "058"
}'Send the transfer
Send a merchant_reference so you can retry safely.
curl https://api.payinto.co/api/v1/business/transfers \
--header "Authorization: Bearer $PAYINTO_SECRET_KEY" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data '{
"resolved_account_reference": "0196431c-6e02-7a44-8d1f-52b1c9e07a33",
"beneficiary_bank_code": "058",
"beneficiary_account_number": "0123456789",
"amount": 250000,
"narration": "Vendor settlement",
"merchant_reference": "payout-10002"
}'Confirm the outcome
A 200 means Payinto accepted the request, and the response has no final status. Call GET /transactions/tsq/{reference} to confirm it.
curl https://api.payinto.co/api/v1/business/transactions/tsq/payout-10002 \
--header "Authorization: Bearer $PAYINTO_SECRET_KEY"The transaction.debit.succeeded webhook confirms that your account was debited. It doesn't confirm that the money reached the beneficiary.
Choose the debit account
Transfers debit your main account by default. To use another account, send the same debit_account_id when you resolve, quote, and send.
Transfer to a Payinto Tag
To pay a Payinto user, resolve their tag first. POST /transfers accepts bank details only, so pass the resolved values to it.
curl https://api.payinto.co/api/v1/business/transfers/resolve-recipient \
--header "Authorization: Bearer $PAYINTO_SECRET_KEY" \
--header "Content-Type: application/json" \
--data '{ "recipient": "@tag_recipient" }'Tags are case-insensitive, and the @ is optional. The response adds resolved_account_reference, display_tag, and business_name to the usual beneficiary fields.
| Status | Meaning |
|---|---|
404 | The tag doesn't exist in this environment. |
422 | The tag is malformed, or the recipient has no receiving account. |
400 | The debit account wasn't found, or bank resolution failed. |
Common errors
| Status | Message | Fix |
|---|---|---|
400 | Could not find the account. | Check debit_account_id, and confirm the account belongs to this environment. |
400 | Could not validate the account details. | Check the bank code and account number. |
409 | Duplicate merchant reference with a different payload. | Use a new reference, or resend the original payload. |
422 | Field errors | Fix the fields listed in errors. |