Skip to documentationDocumentation
On this page

Quickstart

Create your first invoice, open hosted checkout, and verify payment before fulfillment.

This walkthrough creates an invoice on your server and sends the customer to hosted checkout. Keep the API key on your server throughout the flow.

1. Get your API key#

Create a key with invoices:write and invoices:read. Use sk_test_ for testnet payments or sk_live_ for real funds. Store it as HALFIN_API_KEY in your server's secret manager.

Both environments use https://api.thehalfin.com. Test mode uses testnet transactions; it is not a payment simulator. See environments.

2. Check currencies and networks#

curl
curl 'https://api.thehalfin.com/v1/currencies' \
  --header "X-API-Key: $HALFIN_API_KEY"

Use a returned currency and network pair. online means a current USD price exists; your merchant must also be enabled for that pair and operation.

3. Create your first invoice#

Save a unique idempotency key alongside your order before the first request. Reuse it and the identical request body after a timeout. The example key identifies one order; use a new key for every new invoice.

curl
curl --request POST 'https://api.thehalfin.com/v1/invoices' \
  --header "X-API-Key: $HALFIN_API_KEY" \
  --header 'Idempotency-Key: order-1001-invoice' \
  --header 'Content-Type: application/json' \
  --data '{
    "amount": "25.00",
    "currency": "USD",
    "external_id": "order-1001",
    "description": "Order 1001",
    "metadata": { "order_id": "1001" }
  }'

This example prices the invoice in USD. A fiat invoice has no network: the customer chooses a payment pair on checkout. See the supported fiat invoice prices. To request a fixed crypto amount, send a supported pair, for example "currency": "ETH", "network": "ethereum"; crypto invoices always require network. Use an amount denominated in that crypto asset. Test supports configured native assets, not USDT or USDC.

A successful response is 201. Read data.id and data.checkout_url, and store the invoice ID with your order. Creation records the invoice intent: the payment address, crypto amount, and payment deadline are still null until checkout activation. See the full create response.

4. Redirect to checkout#

Redirect the customer to the returned checkout_url. Opening and activating checkout assigns the payment address, fixes the selected payment amount and rate, and starts the payment window. Use the returned URL as-is.

The customer's browser returning to your site is not proof of payment.

5. Confirm payment on your server#

Register a webhook endpoint for invoice.paid, invoice.overpaid, and the other invoice lifecycle events. Verify its signature and save each event durably before returning 2xx.

Then retrieve the current invoice:

curl
curl 'https://api.thehalfin.com/v1/invoices/00000000-0000-0000-0000-000000000003' \
  --header "X-API-Key: $HALFIN_API_KEY"

Replace the example UUID with data.id. Fulfill once per invoice when the current status is paid or overpaid. invoice.detected is an observation, and confirming means accepted funds are still below the payment threshold. Handle later reversals separately.

A late payment can produce two different events for the same accepted payment. Do not sum event net_amount values; read the current invoice and balances. See business processes.

Next steps#

Read idempotency, errors, and signature verification before processing live orders. The operation reference includes curl examples.