Use case

Crypto payments for digital goods and instant delivery

When you sell a download, a licence key, a game top-up, or API credit, there is nothing to ship and nothing to ship back. The moment the customer pays, they expect the file, the key, or the balance — and once you have delivered it, you cannot un-deliver it. That makes the timing of delivery the whole game: deliver too early and a payment that never settles costs you the goods; deliver off the wrong signal and a customer who closed the tab never gets what they paid for. This page is about one narrow job — releasing a digital good at exactly the moment a crypto payment is final, and not a moment before.

01

The job: deliver on the payment, not on the promise of one

A physical store has slack in its timing. An order can sit in "paid" for hours before anyone packs it, and if a payment turns out to be bad, the goods are still on the shelf. Digital goods have no such slack. The customer wants the licence key on the confirmation screen, the download link in the same session, the top-up reflected in their in-app balance immediately. Delivery and payment collapse into a single moment, and that moment has to be the right one.

The danger is delivering on a signal that is not yet final. A crypto payment passes through several states a naive integration might mistake for "done": a transaction appears in the mempool, then gets one confirmation, then accumulates more. Hand over a download on the first sighting and a transaction that is dropped, replaced, or unwound by a chain reorganization leaves you with the good delivered and no money received. For a digital good there is no recovery — you cannot recall a file the customer already has.

halfin's job here is to give you exactly one trustworthy delivery trigger. You create an invoice for the order, the customer pays on the hosted checkout page, and halfin waits for that chain's confirmation threshold and credits the payment in a reorg-aware way before it tells you anything is final. Your fulfilment code listens for one event — invoice.paid — and only that event releases the good. Everything before it is informational.

02

invoice.paid is the only event that should release the good

An invoice emits several signed webhook events over its life, and for digital goods it matters which one your delivery code reacts to. The instinct to "show progress" by releasing something on an early event is exactly the mistake that costs you product. Use the earlier events to update the customer-facing status if you like, but gate the actual delivery on invoice.paid alone.

The table below is the canonical set of invoice events and what a digital-goods seller should do with each. The rule running through it is simple: nothing irreversible happens until the payment is confirmed and final on-chain, and that single fact is what invoice.paid represents.

Webhook eventWhat it means on-chainWhat a digital-goods seller does
invoice.confirmingThe invoice is live, the rate is locked, the payment window is open.Mark the order as awaiting payment. Deliver nothing.
invoice.paidPayment reached the per-chain confirmation threshold and is final.Verify the signature, then release the download, key, or top-up.
invoice.underpaidA deposit arrived but fell short of the expected amount.Withhold delivery; request the balance or refund per your policy.
invoice.overpaidThe deposit exceeded the expected amount.Deliver the good; reconcile the excess and refund it if your policy says so.
invoice.expiredThe window elapsed before a sufficient payment confirmed.Deliver nothing; re-issue at the current rate if the customer returns.
03

Why reorg-aware confirmation is the part you cannot skip

A blockchain payment is not final the instant it appears. A transaction can sit unconfirmed in the mempool and then be dropped or replaced; even a confirmed transaction can be unwound if the chain reorganizes and a competing block wins. Different chains settle at different depths, which is why a single "one confirmation is enough" rule across every network is wrong — what is safe on one chain is premature on another.

halfin applies a per-chain confirmation threshold and credits in a reorg-aware way: if a transaction that looked confirmed is unwound by a reorganization, that is reflected rather than ignored. The practical consequence for you is that invoice.paid does not fire on a sighting or a single shaky confirmation — it fires once the payment has held under that chain's rules. For a physical good you might absorb the rare bad payment; for a digital good handed over instantly and irrecoverably, waiting for that threshold is the difference between a sale and a giveaway.

This is exactly the work you do not want to build yourself. Tracking per-chain confirmation depths, watching for replacements, and detecting reorgs across Bitcoin, the EVM chains, Tron, the XRP Ledger, and Solana is a moving target. halfin owns it on the processing side so your fulfilment logic can stay a single rule: deliver on invoice.paid, after verifying the signature.

04

Wiring delivery to the verified webhook

Drive delivery from the server-to-server webhook, never from the customer's redirect. A buyer of a digital good is especially likely to close the tab the second they have paid — they came for the file, not for your success page — so a delivery flow that waits for them to land back on your site will strand paid customers. The signed webhook arrives whether or not the browser ever returns, which is precisely why it is the right trigger.

Verify the HMAC signature before you act on a single field. You recompute the signature over the raw request body with your signing secret and compare; only then do you trust an invoice.paid event and release the good. An unverified payload is just an HTTP request anyone could have sent, and acting on a forged invoice.paid would hand out licence keys for free. Tie each invoice to its order with your own order id as the idempotency key, so a retried create call returns the same invoice and a redelivered webhook maps cleanly back to the order it belongs to.

Make delivery itself idempotent on your side too. Webhooks can be redelivered, so a buyer should get one licence key, not three, if invoice.paid arrives more than once — key your fulfilment on the order id and no-op if you have already delivered. The full envelope and signing scheme are documented at docs.thehalfin.com.

  • Create the invoice with your order id as the idempotency key.
  • Redirect the customer to the hosted checkout URL in the response.
  • On invoice.paid, verify the HMAC signature before trusting any field.
  • Release the download, licence, or top-up only after the signature checks out.
  • Make delivery idempotent so a redelivered webhook never double-grants the good.
05

The create call, and the amount you anchor it to

The store side is one authenticated POST. You send the order total as a fiat amount and currency — the currency your catalogue already prices in — and halfin pins the payable crypto amount when the invoice activates, then returns an invoice with a hosted checkout URL. The rate lock matters for digital goods because the gap between a customer opening the page and confirming a payment is exactly when a moving market would otherwise turn a correct payment into an underpayment that blocks delivery.

Amounts are strings end to end — never floats — and the fiat_currency is your anchor, not a crypto code. A customer who wants to settle in a fixed crypto amount instead would receive a fixed-asset invoice, but for a store pricing in dollars the fiat anchor is what keeps reconciliation clean. After the create call, wait for the signed invoice.paid webhook before you deliver.

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": "29.00",
    "fiat_currency": "USD",
    "description": "Pro licence — order #90412",
    "idempotency_key": "order-90412"
  }'

# halfin locks the rate at activation and returns an invoice with a hosted
# checkout URL. Redirect the customer there. Deliver the licence only after
# a signed invoice.paid webhook arrives and its signature verifies.
# See docs.thehalfin.com for the full request, response, and signing schema.
06

Final payments, deliberate refunds

Digital goods are where chargebacks hurt most. A card payment for a download can be reversed weeks later, by which point the file is long delivered and there is nothing to reclaim — you eat the loss, the dispute fee, and a hit to your acquirer scorecard. Sellers of software, keys, top-ups, and credit feel this acutely, because the product is gone the instant it is delivered.

A crypto payment confirmed through halfin does not reverse on its own. Once it is credited under the chain's confirmation threshold it has settled on-chain, and there is no issuer-initiated chargeback. That removes the after-the-fact reversal risk that makes digital goods a hard sell for card acquirers. It also reframes returns: because nothing forces a reversal on you, a refund is a deliberate decision you make through the refund flow against the original invoice — for a genuine return, a duplicate purchase, or goodwill — on your own terms rather than under a dispute you cannot decline.

None of this is a pricing claim; pricing is a separate conversation. It is a different risk profile, and for a business whose entire inventory is irrecoverable the moment it is delivered, the absence of forced reversals is often the reason to take crypto at all.