Save a recipient
Name-checked, screened, and reusable — the way to pay a bank account twice.
A beneficiary is somewhere you pay, saved. It carries the name on the account,
the account itself, the country and the currency, plus two things a raw
destination on a payout can never have: what the rail said the account is
called, and whether the recipient has cleared screening.
Beneficiaries are a dashboard session only, in both directions — an API key can neither read nor manage them. See Authentication.
Save one
curl -X POST https://sandbox.inversepay.app/api/b/v1/beneficiaries \
-H "Authorization: Bearer $INVERSEPAY_SESSION_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"label": "Rwanda Metal Works — settlement",
"full_name": "Rwanda Metal Works Ltd",
"type": "bank",
"account_identifier": "00040100123456789",
"bank_name": "Banque de Kigali",
"currency": "RWF",
"country_code": "RW"
}'| Field | ||
|---|---|---|
label | required | What you call them. Shown in lists; ours to display, never to match on. |
full_name | required | The name on the account. This is what gets checked. |
type | required | mobile_money, bank or card. |
account_identifier | required | The wallet number, account number or card token. |
currency | required | Three letters. |
country_code | required | Two letters. |
bank_name | optional | |
destination | optional | Anything else the rail needs, in the same open shape a payout takes. |
A wallet is the same call with "type": "mobile_money" and the number as the
account_identifier:
curl -X POST https://sandbox.inversepay.app/api/b/v1/beneficiaries \
-H "Authorization: Bearer $INVERSEPAY_SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"label": "Aline — payroll",
"full_name": "Aline Uwase",
"type": "mobile_money",
"account_identifier": "+250788123456",
"currency": "RWF",
"country_code": "RW",
"destination": { "network": "MTN" }
}'Saving the same account twice is a 409. Pay the one you have rather than
creating a second, which would carry its own separate screening state.
The response is the interesting part
{
"id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"label": "Rwanda Metal Works — settlement",
"full_name": "Rwanda Metal Works Ltd",
"type": "bank",
"currency": "RWF",
"country_code": "RW",
"account_identifier": "00040100123456789",
"bank_name": "Banque de Kigali",
"validation_status": "unavailable",
"account_name_returned": null,
"screening_status": "pending",
"payable": false,
"archived_at": null,
"created_at": "2026-08-14T09:02:11Z"
}Two fields decide whether money can move, and payable is the one to read.
It is the single gate: the payout path and the dashboard both compute it the
same way, so they cannot disagree about it.
validation_status — is this account called what you think?
We ask the rail who owns the account and compare it to full_name.
| Value | Meaning |
|---|---|
matched | The rail's name and yours agree. |
partial | Close, not exact. Worth a human glance. |
mismatch | They differ. Somebody else owns this account. |
unavailable | We could not check — the rail has no lookup, or it did not answer. |
unchecked | Not checked yet. |
unavailable is not a mismatch and is never reported as one. "We could not
check" and "the names differ" are different facts, and a business shown the
second when the first is true stops trusting the check.
Whatever the rail said is in account_name_returned, verbatim. If you are
disputing a mismatch you need the other name, not our verdict on it.
This does not block a payout. A mismatch is a warning; acting on it is yours.
screening_status — may money move at all?
| Value | payable |
|---|---|
unscreened | no |
pending | no |
hit | no — on a sanctions list |
clear | yes |
cleared_after_review | yes — a person judged a hit a false positive |
blocked | no, permanently — a person confirmed the hit |
Screening fails closed. Anything other than clear or cleared_after_review
does not pay, and that includes unscreened and pending: not having looked is
not a clean result, and the first payout to a new recipient is exactly when that
matters.
Clearing a recipient for payment
A beneficiary sitting at pending or hit is waiting on a person. They are in
the review queue:
curl https://sandbox.inversepay.app/api/b/v1/beneficiaries/review-queue \
-H "Authorization: Bearer $INVERSEPAY_SESSION_TOKEN"Clearing one is the Owner's alone — it is the one action that turns "this may not be paid" into "this may":
curl -X POST https://sandbox.inversepay.app/api/b/v1/beneficiaries/$BENEFICIARY_ID/clear \
-H "Authorization: Bearer $INVERSEPAY_SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "note": "Known supplier since 2023. Name matches the contract." }'The note is kept. An auditor reading this later needs to know what the reviewer believed, not just that somebody clicked.
Clearing only works from pending or hit. Clearing something never flagged
would be a way to mark a beneficiary reviewed without anybody reviewing them.
The opposite decision is /block, which is permanent, and /archive, which
retires a recipient without deleting them — deleting would take the screening
history with it and leave every payout already made to them pointing at nothing.
Paying one
curl -X POST https://sandbox.inversepay.app/api/b/v1/payouts \
-H "Authorization: Bearer $INVERSEPAY_SESSION_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"idempotency_key": "invoice-8821-settlement",
"amount_minor": 240000000,
"currency": "RWF",
"method": "bank",
"transaction_type": "b2b",
"beneficiary_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7"
}'The name, country and destination come from the beneficiary. Send any of them yourself and yours wins.
A payout to a beneficiary that is not payable is a 409, and the response
says which screening status refused it. The check runs again at payout time, not
only when the recipient was saved: lists change, and somebody cleared in March
can be listed in June.