Use case

Forex broker payments: trader deposits and withdrawals

A forex broker has two payment flows that touch real money every day: a trader funding an account, and a trader cashing out. halfin covers both ends with the same primitives — fiat-anchored invoices and hosted checkout for the deposit, approved payouts for the withdrawal — and leaves the approval decision, the risk screening, and the system of record where they belong: inside your back office. You get a payment layer your finance team can reconcile, not a black box that decides who gets paid.

01

Two flows, one payment layer

Trader deposits and trader withdrawals look like opposites, but operationally they are the same problem viewed from two sides: money has to move, the broker has to stay in control of who moves it, and finance has to be able to close the books afterward. halfin gives you a primitive for each direction and a signed event stream that ties them back to a trader.

On the inbound side, a trader funds an account by paying an invoice. You create the invoice anchored to the fiat amount you book the deposit in — USD or EUR — and the trader settles in a supported crypto asset. The rate locks when the invoice activates, so the figure you credit to the trading account is the figure you quoted, not whatever the market did while the deposit was in flight.

On the outbound side, a withdrawal is a payout. Your back office approves the request against the trader's balance and your own policy, then hands halfin a single payout instruction: an asset, an amount, a destination wallet, and an idempotency key. halfin executes the transfer and reports the result back as a signed event. The approval is yours; the execution and the record are the rail's.

02

Trader deposits: fiat-anchored invoices

A funding request has a deadline the trader cares about — they want to be in the market now, not after a card processor or a bank window clears. A crypto invoice removes the intermediary that adds the delay, but only if the amount stays honest. That is what the fiat anchor is for.

You bill the deposit in the currency your ledger runs on. The trader pays the equivalent in whichever supported asset they hold; the invoice records both the fiat figure you anchored and the asset amount that actually arrived on-chain. Because crediting is reorg-aware and waits for the per-chain confirmation threshold, the deposit you mark as cleared is one that actually held. Underpayments and overpayments are recorded against the invoice rather than stranded, so a trader who sends the wrong amount becomes a support case you can see and resolve, not money that vanished into an unmatched-deposit pile.

  • Anchor the deposit in USD or EUR; let the trader settle in a supported asset.
  • Rate locks at activation — the credited fiat figure does not drift mid-payment.
  • Reorg-aware crediting at the per-chain confirmation threshold before you mark a deposit cleared.
  • Underpaid and overpaid deposits are surfaced against the invoice, not lost.
  • Each invoice carries your own reference so it maps back to a trader and a trading account.
03

Trader withdrawals: approved payouts

A withdrawal is where a payment rail is most tempting to over-automate and most dangerous to. halfin deliberately does not decide whether a trader may withdraw. Your back office checks the balance, applies your withdrawal policy, screens the destination wallet, and approves — then creates the payout. halfin is the executor, not the approver.

A single payout is one approved transfer to one destination. The instruction carries the asset, the amount, the destination wallet, and an idempotency key that makes a retried request safe: if your service resubmits the same payout after a timeout, the key guarantees the trader is paid once, not twice. When the transfer settles, halfin emits a signed payout.completed event so your ledger can move the withdrawal from pending to done against a record you can trust.

When you run a withdrawal batch — end-of-day funded-trader payouts, for example — the same single-payout call is the unit you fan out over, one approved line at a time, each with its own idempotency key. There is no separate batch endpoint to learn; the batch is many idempotent single payouts, which is also what keeps a partial failure recoverable line by line instead of as one opaque blob.

04

Where the broker boundary sits

An FX or CFD broker carries obligations halfin does not touch: trader onboarding, identity and suitability checks, the regulatory status required in each market it operates in, and the trading platform itself. halfin's surface is narrow on purpose — it collects the deposit, executes the approved withdrawal, keeps the payment records, and reports state through dashboard data and signed webhooks. It is payment infrastructure, not a broker back office and not a license.

The clean division is to keep every trading and identity decision in your stack and let halfin own only the money movement and its audit trail. The table below draws that line for the two flows on this page.

ConcernBroker back office ownshalfin owns
Trader identity / KYCOnboarding, identity checks, suitability, the system of record for who the trader is.Nothing — halfin receives an instruction tied to your reference.
Deposit approvalWhether to accept funds and how to credit the trading account.Issuing the invoice and crediting the confirmed on-chain amount.
Withdrawal approvalBalance check, withdrawal policy, destination-wallet screening, the approve decision.Executing the approved payout and reporting its final state.
Audit trailLinking payment records to traders and accounts in your ledger.Invoice, payout, and signed-webhook records for every movement.
05

Reconciliation runs on signed events

The reason both flows reconcile cleanly is that nothing happens silently. Every state change a broker cares about arrives as an HMAC-signed webhook, and the rule is the same for all of them: verify the signature before you act. A forged invoice.paid that credits a trading account, or a forged payout.completed that closes a withdrawal in your ledger, is exactly the kind of event you must not trust on its face.

The events below are the ones a broker integration leans on. Deposit-side events move a funding request through to a credited account; the payout event closes a withdrawal. Each one is something your CRM, risk desk, or finance system can subscribe to and reconcile against the dashboard and the REST API.

EventFlowWhat your system does
invoice.confirmingDepositShow the trader the address, asset, amount, and countdown; mark the funding request live.
invoice.paidDepositCredit the trading account against the anchored fiat figure once the signature verifies.
invoice.underpaidDepositOpen a support case for a top-up or partial credit under your policy.
invoice.overpaidDepositRecord the excess against the trader and handle it per your overpayment policy.
invoice.expiredDepositClose the funding request; re-issue at the current rate if the trader still wants in.
payout.completedWithdrawalMove the withdrawal from pending to settled in your ledger and notify the trader.
06

What an integration looks like

Both flows are spec-first REST against scoped API keys. A deposit starts with one create-invoice call, anchored to your booking currency; a withdrawal is one create-payout call your back office makes after it approves. The payout body below is the shape that matters: an asset, an amount as a string, a destination wallet, and an idempotency key. The exact response schemas live in the docs and the @halfin/sdk-merchant types — the point here is that one authenticated call per direction covers the broker's payment surface.

# Trader funds an account — anchor the deposit in the booking currency.
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": "500.00",
    "fiat_currency": "USD",
    "description": "Account funding — trader 4821",
    "idempotency_key": "00000000-0000-4000-8000-000000000001"
  }'

# Trader withdraws — your back office approves first, then creates the payout.
curl -X POST https://api.thehalfin.com/api/v1/payouts \
  -H "X-API-Key: $HALFIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "currency": "USDT",
    "amount": "240.00",
    "destination": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
    "idempotency_key": "withdrawal-4821-2026-06-10"
  }'

# Reconcile both flows on signed events: invoice.paid credits the account,
# payout.completed closes the withdrawal. Verify the HMAC signature first.
# See docs.thehalfin.com for the full request and response schemas.