Use case

USDT checkout for online stores

A lot of online customers hold one crypto asset and it is USDT. They keep it on an exchange or in a wallet, it tracks the dollar, and they would rather spend it than convert to a card. The job for the store is narrow: take that USDT, book the dollar amount you actually priced, and don't make the customer think about networks or confirmations. halfin does that with a fiat-anchored invoice — you state the price in USD, the customer pays the equivalent in USDT on whichever network they hold it, and the figure that lands in your ledger is the figure you billed.

01

Why USDT is the asset your customers already hold

USDT is the most widely held stablecoin in circulation, and for a store that matters more than any technical property. The customer who wants to pay in crypto usually has a USDT balance sitting on an exchange or in a wallet, denominated in dollars, ready to send. Asking them to pay in BTC or ETH means asking them to convert first; offering USDT means they pay with what they have.

It is dollar-pegged, so the amount the customer sees and the amount you book are the same currency of thought. A $120 order is roughly 120 USDT — there is no mental conversion, no "what is this worth today", and no surprise when the payment confirms. For both sides the number stays still, which is exactly what a checkout needs.

That is why USDT acceptance is the first crypto rail most stores turn on. It is the lowest-friction option for the customer and the cleanest one for your finance team, because a stablecoin payment maps back to your fiat price without an FX step in the middle.

02

Price in USD, settle in USDT — the rate lock does the work

Even though USDT tracks the dollar, you do not want your checkout quoting raw token amounts and hoping they match. You price in your catalogue currency — USD, EUR, whatever your storefront already uses — and create a fiat-anchored invoice. halfin computes the payable USDT amount from the live rate and pins it the moment the invoice activates.

From activation the customer owes a fixed USDT amount inside a defined expiry window. They are shown a concrete figure to send, not a moving quote, and if the window passes the invoice expires rather than silently re-pricing — you decide whether to re-issue. Because the booked figure is the fiat one, reconciliation is mechanical: every paid invoice maps back to the dollar amount you charged, matched by the asset and the network it arrived on.

The request is the same shape as any halfin invoice. You send the fiat amount as a string with its currency; you do not request a network or a success URL — the customer picks the USDT network on the hosted checkout page, and your success page is handled by the redirect.

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": "120.00",
    "fiat_currency": "USD",
    "idempotency_key": "order-58213"
  }'

# The USD amount anchors the order. halfin pins the payable USDT
# figure at activation and returns a hosted checkout URL where the
# customer chooses their USDT network (TRC-20, ERC-20, or Solana).
# Verify the signed invoice webhook before releasing the order.
# Full request and response schema: docs.thehalfin.com.
03

TRC-20, ERC-20, or Solana — which USDT network to enable

USDT is not one thing on one chain — the same token lives on several networks, and the network the customer pays on changes their cost and speed. halfin runs real gates for USDT on Tron (TRC-20), Ethereum (ERC-20), and Solana (SPL). You enable the networks you want to accept, and the customer pays on whichever one they hold funds on.

TRC-20 is the one most stores lead with, because Tron transfer fees are low and customers who keep USDT on exchanges very often hold the TRC-20 version. ERC-20 is the canonical Ethereum form your EVM-native customers will reach for, at the cost of Ethereum network fees. Solana USDT settles fast and cheap and suits customers already in that ecosystem. None of these is a placeholder — each is a gate that actually watches the chain and credits in a reorg-aware way once the network's confirmation threshold is met.

USDT networkWhy a customer picks itFee character
Tron (TRC-20)Most commonly held USDT; the default for exchange withdrawals.Low transfer fees — usually the cheapest rail to pay on.
Ethereum (ERC-20)Canonical USDT for EVM-native wallets and DeFi users.Ethereum network fees apply; higher than the other two.
Solana (SPL)Customers already operating in the Solana ecosystem.Fast finality, low fees.
04

What happens after the customer pays

Treat the redirect to your success page as cosmetic and the webhook as authoritative. A customer can pay and then close the tab before the redirect fires; the signed webhook still arrives, and that is what should flip the order to paid and release fulfilment.

halfin watches the chain, applies that network's confirmation threshold, and credits the payment reorg-aware — a payment shown as paid has settled under the chain's rules, not merely been seen in the mempool. When the invoice resolves your server receives an HMAC-signed webhook. Verify the signature first, then act. The canonical invoice events are invoice.confirming, invoice.paid, invoice.underpaid, invoice.overpaid, and invoice.expired, so an underpayment or a late payment is a defined outcome you can branch on rather than a silent failure.

USDT being dollar-pegged does not exempt it from the usual stablecoin edge cases. A customer can send slightly too little — paying a stale quote, or having an exchange skim a withdrawal fee — and that surfaces as invoice.underpaid with the recorded shortfall, so you can request a top-up or settle partially under your own policy. An overpayment is recorded the same way rather than vanishing. If you ever need to return funds, refunds run against the original invoice instead of an ad-hoc manual send.

  • invoice.paid is the signal to release the order — after you verify the HMAC signature.
  • invoice.underpaid records the shortfall; decide top-up or partial settlement per your policy.
  • invoice.overpaid records the excess so it stays visible and accountable.
  • invoice.expired fires when the window lapses; re-issue at the current rate if the customer returns.
  • Reorg-aware crediting waits for the network's confirmation threshold before marking paid.
05

Wiring it into a store without a plugin

There is no official CMS plugin to install. USDT checkout is the same REST API and hosted checkout regardless of platform, so a custom store and a popular storefront integrate it the same way: create an invoice from the order total, redirect the customer to the returned hosted checkout URL, and wait for the signed webhook before marking the order paid.

The store side stays small and stateless about crypto. You never hold a USDT balance in your application, never track confirmations yourself, and never branch on which network the customer chose — halfin owns all of that. Your code creates one invoice and reacts to one webhook. Pass an idempotency key on the create call so a retried request, after a timeout or a double-submit, returns the same invoice instead of billing the order twice.

Pair this with static deposit addresses only when you genuinely want a persistent receive address per customer rather than a per-order invoice — for most storefront checkouts the per-order invoice is the right primitive, because it carries the fiat anchor, the rate lock, and the expiry that make the order reconcile cleanly.