Two ways to take a deposit, picked by how the player funds
Casino deposits split cleanly into two patterns, and the right primitive depends on whether the player is funding a specific amount once or topping up a balance again and again. halfin covers both with different objects, so you do not bend one tool to do the other's job.
Hosted checkout is the fast path for a one-off, amount-anchored deposit. A player at the cashier picks a figure, you create a fiat-anchored invoice for that amount, and you redirect the player to checkout.thehalfin.com. They pay from their own wallet on a network you accept. The rate is locked at activation, so the credited play balance matches the figure the player saw at the cashier even if they take a minute to fund. For a deposit screen that lives entirely inside your own product, self-hosted checkout renders against the same API on your domain — same invoice, your UI.
Static deposit addresses are the right shape for a regular. A player who funds every week does not want a fresh invoice and a fresh address each time. Issue a persistent deposit address against that player's account once, store it on your user record, and credit every payment that lands on it — no per-deposit checkout step, no amount to fix in advance, nothing to expire. The address itself is the identifier: a deposit is attributed to the player by the address it arrived on, so the cost of supporting recurring funding does not grow with the number of top-ups.
- One-off, amount-known deposit → fiat-anchored invoice + hosted checkout, rate locked at activation.
- Deposit screen inside your own product → self-hosted checkout against the same invoice API.
- Recurring top-ups from a known player → one static deposit address per account, reused indefinitely.
- Attribution → invoice id for checkout deposits; receiving address for static-address deposits.
Confirmation is on-chain truth, not a hopeful UI
The dangerous version of a deposit flow credits a player the instant a transaction shows up in a mempool or hits one confirmation. That is how a casino pays out winnings on a deposit that later disappears in a reorg. halfin does not do that. Each deposit is credited reorg-aware, after the chain's own confirmation threshold — so a deposit your system treats as funded has actually settled to the depth that chain requires.
Thresholds differ by chain because the chains differ. A Bitcoin deposit waits for more confirmations than a fast-finality chain because a Bitcoin reorg is a real, if rare, event; a chain with near-instant finality clears sooner. You do not configure or reason about any of this per deposit — halfin applies the correct per-chain rule and only then credits the merchant balance. The practical contract for your cashier is simple: a confirmed deposit is final, and a deposit that is still confirming is not yet spendable.
Underpaid and overpaid only exist on the invoice path, because only there is there a quoted amount to compare against. A player who sends slightly too little against a fiat-anchored invoice produces an explicit underpaid state you can surface at the cashier, not a silent mismatch your support desk discovers at reconciliation. A static deposit address has no pre-declared amount, so it has no underpaid or overpaid state — halfin simply credits whatever the player actually sent.
Which deposit rails a casino accepts
Players arrive holding different assets on different chains, and the rail that fails is the one you did not turn on. halfin runs real on-chain gates for every network below — there is no placeholder rail that quietly does nothing. Stablecoins do most of the work for casino deposits, because the value a player funds does not drift between the cashier and the confirmation; native coins cover players who hold them. Accept the assets your player base actually sends and let the rest be a non-issue.
| Network | Native asset | Stablecoins on this network |
|---|---|---|
| Bitcoin | BTC | — |
| Ethereum | ETH | USDT (ERC-20), USDC (ERC-20) |
| Base | ETH | USDC |
| Arbitrum | ETH | — |
| Polygon | native gas token | — |
| BNB Smart Chain | BNB | — |
| Tron | TRX | USDT (TRC-20) |
| XRP Ledger | XRP | — |
| Solana | SOL | USDT (SPL), USDC (SPL) |
The signed webhook is what credits the player
The redirect a player sees after paying is cosmetic. They can pay and close the tab before any success page loads; a flaky connection can drop the redirect entirely. None of that should affect whether the player gets credited. The thing your cashier trusts is the webhook — an HMAC-signed event halfin sends your server when the deposit's state changes.
The discipline is one line long and it is not optional: verify the signature first, then act. An unsigned or wrongly-signed payload is not a deposit, it is a request to credit a player from someone who is not halfin. Only after the signature checks out do you move the play balance. For an invoice-backed deposit, invoice.paid is the credit signal; invoice.underpaid and invoice.overpaid tell you the player's transfer did not match the quote so you can hold or reconcile instead of crediting blindly; invoice.expired closes a deposit the player never funded.
Static-address deposits ride the same signed-event discipline: halfin notifies your backend when a deposit on a player's address is detected and again when it is credited under the chain's threshold. Whichever path produced it, the webhook is your ledger's source of truth — the player-balance write happens on the verified event, never on the redirect.
- invoice.confirming — the deposit invoice is live and the rate is locked.
- invoice.paid — the deposit confirmed at the chain threshold; credit the player.
- invoice.underpaid / invoice.overpaid — the transfer did not match the quote; hold and reconcile.
- invoice.expired — the player never funded; close the cashier attempt.
- Verify the HMAC signature before every one of these moves money.
Create a player deposit invoice
The deposit integration is small enough to show in full. Create a fiat-anchored invoice for the figure the player chose at the cashier — the amount is anchored to a fiat currency so the credited play balance equals what the player expects, and the rate is locked when the invoice activates. The response carries a hosted checkout URL on checkout.thehalfin.com; redirect the player there and then wait for the signed webhook before you touch the balance. The full request and response schema lives at docs.thehalfin.com.
Amounts are sent as strings, never as floating-point numbers, so a value transports exactly with no rounding drift between your books and the chain. The example below is the request shape; treat the eventual invoice.paid webhook — after you verify its signature — as the single moment the player is funded.
curl -X POST https://api.thehalfin.com/api/v1/invoices \
-H "X-API-Key: $HALFIN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"amount_fiat": "50.00",
"fiat_currency": "USD",
"deferred": true,
"idempotency_key": "deposit-player-8821-00041"
}'
# The response includes a hosted checkout URL on checkout.thehalfin.com;
# see docs.thehalfin.com for its full schema. Redirect the player there,
# then verify the signed invoice.paid webhook on your server before
# crediting the player's play balance.Where the casino's responsibility ends and halfin's begins
A clean deposit flow depends on a clean division of labour. Your platform decides who the player is, whether they are allowed to deposit, and how much credited balance becomes play balance — KYC status, jurisdiction, age, responsible-gaming limits. halfin receives the deposit, watches the chain, applies the confirmation rule, credits the merchant balance, and returns a signed event. It is a payment rail, not a gambling licence: whether your casino may operate in a given market is your question to answer with your own counsel and regulator, and halfin neither grants nor implies that approval.
On the rail itself, halfin runs KYB onboarding for the operator so it knows the business it processes for, and processing is AML-aware as a matter of process — none of which is a status halfin holds on your behalf. Player identity stays your system of record. The payment records halfin keeps — the invoice, the deposit, the webhook — attach back to your player IDs so your own controls and your finance team have an unambiguous trail to reconcile against.