A payout run is a list you re-submit safely, not a fire-and-forget script
Paying one vendor is a transaction. Paying your creators is a list, and lists fail differently. A batch job times out partway through, your scheduler retries it, and a naive integration re-sends every line — some creators now paid twice, some still not paid, and a reconciliation job that takes the rest of the day. The cost is not just the duplicate money; it is the trust you spend explaining it.
halfin removes the ambiguity at the unit of work. Each creator's payout carries its own idempotency key derived from your run identifier — for example the run date plus the creator's id. If a line is retried by your code, a proxy, or a flaky connection, halfin recognises the key and does not pay that creator a second time. Re-running the whole list after a crash converges on exactly one payout per creator.
That property is what lets you treat a payout run as re-submittable rather than fragile. You do not have to diff your own logs against the chain to work out where a run stopped; you submit the list, halfin deduplicates by key, and you read each payout's state back to confirm. The run becomes the thing you retry, audit, and reconcile against — not a one-shot you are afraid to touch.
Mass payouts is a fan-out over the single-payout API
There is no separate batch endpoint to learn. A mass payout is a fan-out: you loop your payee list and call the same single-payout API once per creator, each call carrying its own idempotency key. That is a deliberate design choice — the unit that succeeds, fails, or retries is one payout to one destination, so a bad wallet on line 400 is a single visible failure you re-issue, not a whole batch you have to unwind.
Your platform owns the list. Creator identity, earned balance, payout eligibility, and wallet validation all live in your own stack, because that is your system of record for who gets paid. halfin's job starts when you hand it an approved instruction: currency, amount, destination, and the idempotency key. It processes the on-chain rail and returns signed status; it does not decide who is eligible.
The key is the contract between your run and halfin's deduplication. Derive it deterministically from data you already have — a run id and a creator id — so the same logical payout always produces the same key. Re-running the loop then collides on every key that already succeeded and pays only the lines that did not.
- One call per creator over the single-payout API — no batch endpoint to model.
- Each line carries currency, amount, destination, and a per-line idempotency_key.
- The idempotency key is derived from your run id + creator id, so it is stable across retries.
- A failed line is re-issued on its own without disturbing lines that already paid.
- Your stack owns identity and eligibility; halfin owns the on-chain rail.
# A creator payout run fans out over the single-payout API:
# one call per creator, each with an idempotency key tied to the run.
# Re-running the whole loop after a crash is safe — colliding keys
# mean nobody is paid twice.
RUN_ID="2026-06-week2" # your own run identifier
while IFS=, read -r creator currency amount destination; do
curl -sS -X POST https://api.thehalfin.com/api/v1/payouts \
-H "X-API-Key: $HALFIN_API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"currency\": \"$currency\",
\"amount\": \"$amount\",
\"destination\": \"$destination\",
\"idempotency_key\": \"creator-$RUN_ID-$creator\"
}"
done < roster.csv
# Amounts are strings, currency is the crypto code, destination is the
# creator's wallet. Read each payout back to reconcile per-line state,
# and confirm settlement from the payout.completed webhook.
# See docs.thehalfin.com for the full request and response schema.Operator approval sits between 'build the run' and 'money moves'
Paying a roster is a privileged action, and it should not be a single automated step that any compromised key or buggy cron can fire at full scale. halfin separates building a payout from authorising it: an operator approves before funds move, and that approval is a recorded event rather than an implicit side effect of calling an endpoint.
API keys are scoped, so the credential that creates draft payouts does not have to be the credential that releases them. A platform can let a service assemble the run from earned balances while a human — or a separate, tightly-scoped key — performs the approval, keeping a clear two-step boundary around the moment money actually leaves your balance.
The practical effect is that a mistake is catchable before it is expensive. A run built against the wrong period, a payee list with a bad column, a duplicate scheduled trigger — all of these are reviewable while the payouts are still pending, instead of discovered after the chain has settled them.
Every payout is auditable, and the webhook is the source of truth
Each payout is an object with its own state, not a line buried in a batch you can only read as a whole. You query a single payout to see whether it is pending, completed, or failed, and you reconcile a whole run by reading its payouts rather than by parsing your application logs. For a platform whose relationship with creators is built on paying them correctly, that per-line auditability is the point.
Settlement is reported by a signed webhook, and that — not your own optimistic write — is what should mark a creator paid. When a payout settles on-chain, halfin emits a payout.completed event; your server verifies the HMAC signature first, then updates the creator's balance and your ledger. Treat the webhook as the source of truth: a settlement is final when the signed event says so and the chain's confirmations back it, not when your loop finished iterating.
Crediting on the incoming side is reorg-aware with per-chain confirmation thresholds, and the same discipline carries through to payouts — the status you reconcile against reflects what actually held on-chain. Your finance and trust-and-safety teams get a record they can produce later: which run, which creator, which destination, which signed completion event.
| Payout shape | halfin primitive | When a platform reaches for it |
|---|---|---|
| Whole-roster weekly/monthly run | Mass payouts (idempotent fan-out) | Scheduled creator earnings across the full list. |
| One-off bonus, correction, or off-cycle pay | Single payouts | A single creator or a manual fix outside the run. |
| Creator-initiated withdrawal | Single payouts | A creator drawing down their available balance on demand. |
| Revenue split (platform / creator / collaborator) | Mass payouts | Fan-out of one income event into its shares. |
| Pay in a different asset than earned | Balance conversion + payouts | Creator wants USDC; the platform holds another asset. |
What you keep, and what halfin processes
The division of labour is worth stating plainly because it shapes how you build. Your platform is the system of record for who your creators are, what they have earned, and whether they are eligible and screened to be paid. halfin is the payment infrastructure that moves the money once you have decided to move it. It does not become your compliance program and it does not certify your platform.
halfin onboards merchants through KYB and is built with AML awareness; the travel rule is a concept your team should understand as volumes grow. None of that is a license halfin holds or a status it confers on you. Keep creator identity, payout eligibility, and wallet validation inside your own stack; hand halfin the approved payment instruction; reconcile against the signed status it returns. For higher-risk niches, take legal and licensing questions to your own counsel — this page does not give regulatory advice.
Where a creator wants paying in an asset different from the one your platform collects in, balance conversion sits between the held balance and the payout — automatic or manual — and also lets you rebalance your own treasury between assets without manual desk work. Creators are frequently paid in stablecoins on low-fee rails such as Tron (TRC-20) or Solana (SPL), but the supported surface is only the rails with a real on-chain gate.
- Your stack: creator identity, earned balance, eligibility, wallet validation, screening.
- halfin: the on-chain payout rail, operator approval, signed and auditable status.
- Supported rails only — Bitcoin, Ethereum and ERC-20, Base, Arbitrum, Polygon, BNB Smart Chain, Tron and TRC-20, XRP Ledger, Solana and SPL.
- Cross-asset payouts go through balance conversion, not a separate product.