Use case

Scholarship and stipend disbursement across borders

A foundation awards forty scholarships across fourteen countries. The award decisions are done; the hard part is getting the money to the recipients. International wires cost a fixed fee per student, take days, arrive net of correspondent-bank deductions, and bounce when a name doesn't match a bank record — and a program officer ends up chasing failed transfers one at a time. halfin turns a disbursement list into a payout run: each recipient is one payout line, the run is paid exactly once even if retried, and finance reconciles a clean per-recipient result instead of a stack of wire confirmations.

01

Disbursement is a payout problem, not a collection problem

Most of the payment friction in education sits on the inbound side — collecting tuition that students struggle to pay across borders. Scholarship and stipend disbursement is the mirror image. The money is the program's to send, the recipient list is already approved, and the job is to move funds outward to people scattered across the same map the students come from. That is a payout flow, and it has a different failure mode than collection: not a declined card, but a wire that costs more than it should, lands late, and fails silently when a routing detail is off.

International wires are the default tool and the worst fit. Each transfer carries a fixed fee that is painful on a small stipend, clears in days through correspondent banks that each take a cut, and arrives in an amount the recipient did not expect. When one bounces — a mismatched beneficiary name, a closed account, an unsupported corridor — nobody finds out until the recipient says the money never came. For a cohort of forty, a program officer is reconciling forty individual confirmations by hand, and the ones that quietly failed are the ones that surface as complaints weeks later.

The structural problem is that there is no single run with a single verdict. Forty wires are forty separate actions, each with its own status, fee, and timing. A disbursement needs to be one reviewable batch that either pays a recipient or reports clearly that it didn't — so the program can see, at a glance, who has been paid and who still needs attention. That is exactly the shape halfin payouts give it.

02

One recipient list, one payout run, paid once

halfin models a disbursement as a set of payouts you submit together and reason about as a unit. Each recipient is one line carrying a currency, an amount as a string, a destination address, and its own idempotency key. For a single award — a one-off grant, an emergency stipend — that is a single payout with operator review before the funds move. For a whole cohort, it is a mass payout: the same per-recipient guarantee applied to the entire list at once.

The load-bearing property is idempotency. Each line's key is derived from your own records — typically the recipient's award id joined with the disbursement period — so it is deterministic. If the run is interrupted and re-submitted because a worker restarted, a request timed out ambiguously, or a program officer re-ran the file, halfin returns the payout it already created instead of sending a second one. Disbursing a stipend twice is not a small error when it comes out of a fixed grant budget; the keyed run is safe to retry from the top, every time.

Payouts do not leave the balance the instant the API is called. Each one enters a pending-approval state and is released from the dashboard, so the run you submit is a proposal a treasurer or program lead signs off before any money moves. That separates the programmatic staging path — assemble the whole cohort from your award records unattended — from the human control point that authorizes the spend. Partial failure is the normal case, not an exception: a malformed address or an amount below a chain's dust threshold rejects only that line and is reported on its own, so the other thirty-nine recipients still get paid while you fix the one that didn't.

  • One award → a single payout with operator review before funds move.
  • A whole cohort → a mass payout: the same list submitted as one idempotent run.
  • Each line is keyed deterministically, so a retried run pays each recipient exactly once.
  • Payouts stage programmatically, then a human approves the run from the dashboard.
  • A bad line is rejected and reported on its own — the rest of the cohort still pays.
03

What a disbursement line carries

Every recipient in a run is described by the same small set of fields, whether you send one stipend or four hundred. Amounts are always strings — never floating-point numbers — so a grant figure is transported exactly, with no binary-rounding drift between your books and the chain. Currency and network are chosen per line, so a recipient in one region can receive USDT on Tron while another receives USDC on Solana, all in the same run.

FieldTypeNotes
currencystringAsset + network, e.g. USDT (TRC-20 / ERC-20 / Solana), USDC (ERC-20 / Solana / Base), BTC.
amountstringThe disbursement figure as a string. Never a JS number — grant budgets stay exact.
destinationstringRecipient's address; validated for the chosen network before the payout is accepted.
idempotency_keystringDeterministic per recipient + period (e.g. award id + cycle). Re-submitting returns the original payout.
04

Submitting a disbursement run from code

There is no separate disbursement or batch endpoint to learn: a cohort run is a fan-out over the single-payout API, where the idempotency key on each line makes the loop safe to interrupt and re-run. Derive each key from your award records so the same recipient in the same cycle always maps to the same key. If the process dies partway through, you re-run the entire loop — already-created payouts come back unchanged, and only the recipients who haven't been paid yet are created.

The example below walks a list of approved awards and submits one payout per recipient. Because each call is idempotent, wrapping the whole run in a retry is correct rather than dangerous — the second pass converges on exactly one payout per recipient. The full request and response schema, the supported assets and networks, and the webhook envelope are defined at docs.thehalfin.com.

# Fan out a scholarship disbursement; each line is idempotent, so re-running is safe.
while IFS=, read -r award currency amount destination; do
  curl -sS -X POST https://api.thehalfin.com/api/v1/payouts \
    -H "Content-Type: application/json" \
    -H "X-API-Key: $HALFIN_API_KEY" \
    -d "{
      \"currency\": \"$currency\",
      \"amount\": \"$amount\",
      \"destination\": \"$destination\",
      \"idempotency_key\": \"scholarship-2026-spring-$award\"
    }"
done < awards.csv
# Re-run the same file after a crash: keys collide, nobody is paid twice.
# Each payout waits for dashboard approval before funds leave the balance.
05

Let each recipient receive on the chain they actually use

Scholarship recipients are not a homogeneous group, and forcing everyone onto one network means failed payments and addresses that cannot receive the asset you sent. A student in a region where USDT on Tron is the everyday dollar asset should receive it there; a recipient who lives on Solana should get USDC on Solana for the speed and low fee; someone holding BTC can be paid in Bitcoin. halfin lets each line pick its own currency and network, so one run can span all of them without splitting the cohort into separate files.

Stablecoins do most of the work for disbursement, because a stipend or grant is almost always quantified in dollars and a recipient wants a stable amount, not exposure to a volatile asset between award and spend. The matrix below is the real surface halfin runs gates on — a payout draws from this, not from a longer aspirational list. Settlement is reorg-aware and uses per-chain confirmation thresholds, so a payout reported as complete has actually settled to the depth that chain requires, which matters at the tail of a large cohort where you want a per-recipient status to mean "done", not "broadcast and hopefully fine".

  • Per-line network choice — mix Tron, Solana, Base, and Bitcoin payouts in one run.
  • Stablecoins keep a dollar-quoted stipend stable between disbursement and spend.
  • Reorg-aware crediting and per-chain thresholds before a payout reports complete.
AssetNetworks halfin supportsWhy a recipient reaches for it
USDTTron (TRC-20), Ethereum (ERC-20), SolanaMost widely held dollar asset in emerging markets
USDCEthereum (ERC-20), Base, SolanaDollar-stable stipends; low fees on Base / Solana
BTCBitcoinRecipients who hold and spend from a BTC wallet
SOLSolana (SOL + SPL)Fast, low-fee settlement when paid natively
XRPXRP LedgerFast finality for recipients holding XRP
06

An audit trail the program can stand behind

Grant money is accountable money. A foundation, university office, or scholarship program has to be able to show who was awarded what, that the funds actually reached them, and that nobody was paid twice or paid by mistake. With international wires that record is a folder of bank confirmations in different formats; with halfin it is a structured, per-recipient trail in one place. Every payout carries enough context — your own award id, the recipient, the cycle — to tie a wallet payment back to the disbursement decision it came from.

The same dashboard and API hold the whole run, so reconciliation is one pass, not forty. The program sees which payouts were proposed, which were approved, which settled, and which lines were rejected and need a corrected address. A signed webhook on payout.completed tells the program's own system when a disbursement has actually landed on-chain — verify the HMAC signature before recording it as paid — so the record in the program's system and the record in halfin stay aligned through events rather than manual data entry.

Because idempotency keys are deterministic, the audit also answers the question that worries finance most: can this run have double-paid anyone? Re-running the file reproduces the same keys, halfin matches each to the payout it already created, and the answer is provably no — something a program officer can re-run without fear and an auditor can trace end to end.

  • Each payout ties back to your own award id, recipient, and disbursement cycle.
  • Proposed, approved, settled, and rejected states are visible per recipient in one place.
  • payout.completed webhooks confirm settlement — verify the HMAC signature before recording it.
  • Deterministic keys make "could this have double-paid?" a provable no.
07

Where the program's responsibility starts and stops

Disbursing scholarships across borders does not move the program's own obligations onto halfin — it clarifies the boundary. halfin's role is the payout rail: it executes the disbursement, screens the payment counterparty, applies confirmations, and keeps the payout and webhook records. The program keeps its own award decisions, recipient eligibility, and whatever institutional requirements apply to how it grants and reports funds.

Onboarding to halfin runs through KYB — verification of the program or institution as a merchant. That is not a status the program can claim toward its own governance, and it is not recipient identity verification. AML awareness and the travel rule are operating concepts that shape how outbound payments are screened and recorded; they are processes, not certifications halfin holds on the program's behalf. The maintainable pattern is to keep award decisions and recipient eligibility inside the program's own systems and let halfin own whether the disbursement was sent, where it went, and that it settled — two systems of record that reconcile through signed events.

  • halfin verifies the program as a merchant through KYB — not recipient identity, not governance.
  • Keep award decisions and recipient eligibility inside your own systems.
  • AML and travel-rule awareness shape outbound screening and records as a process, never a license.
  • halfin owns whether the disbursement settled and where it went; your program owns who was awarded.