Overview
Invoices are one-time payment requests that return a checkout URL and track payment status through confirmation.
An invoice is a one-time payment request. It defines what the customer should pay and returns a checkout_url for the hosted payment page. The invoice tracks payment through blockchain confirmation and fires webhooks at each status transition.
Invoice object
Key fields returned in every invoice response:
| Field | Type | Description |
|---|---|---|
id | uuid | Unique invoice identifier |
status | string | Current invoice status (see table below) |
currency | string | Crypto currency code (e.g. "BTC", "ETH") |
network | string | Blockchain network for multi-network currencies |
amount_requested | string | Requested crypto amount as a decimal string |
amount_fiat | string | Nominated fiat amount (replaces deprecated amount_usd) |
fiat_currency | string | Fiat currency code — currently always "USD" |
amount_paid | string | Total crypto received so far |
deposit_address | string | Blockchain address the customer must pay to. Absent on draft invoices before activation. |
deposit_address_tag | string | null | Memo or destination tag required by some chains (e.g. XRP, XLM). null for chains that do not use tags. |
is_deferred | boolean | true for deferred invoices that start in draft status without a deposit address. |
paid_at | datetime | null | Timestamp when the invoice reached paid status. null while unpaid. |
checkout_url | string | Hosted payment page URL for the customer |
external_id | string | Your own reference ID |
metadata | object | Arbitrary key-value store for your use |
expires_at | datetime | When the invoice expires (controlled by ttl_minutes) |
created_at | datetime | Creation timestamp |
Statuses
| Status | Meaning |
|---|---|
draft | Created in deferred mode — no payment address yet |
pending | Awaiting payment — deposit address issued |
confirming | Payment detected on-chain, awaiting required confirmations |
paid | Payment confirmed — safe to fulfill |
overpaid | Customer sent more than the requested amount |
underpaid | Invoice expired with partial payment below the threshold |
expired | Invoice TTL elapsed without sufficient payment |
cancelled | Cancelled before payment |
invalid | Created in an invalid state (e.g. unsupported currency config) |
Creating an invoice
Instant invoice (most common)
curl -X POST https://api-sandbox.thehalfin.com/v1/invoices \
-H "Content-Type: application/json" \
-H "X-API-Key: $HALFIN_API_KEY" \
-d '{
"currency": "BTC",
"amount": "0.01000000",
"idempotency_key": "order-0001"
}'USD-nominated invoice
Nominate the invoice in USD and let halfin calculate the crypto amount at creation time:
curl -X POST https://api-sandbox.thehalfin.com/v1/invoices \
-H "Content-Type: application/json" \
-H "X-API-Key: $HALFIN_API_KEY" \
-d '{
"amount_fiat": "50.00",
"fiat_currency": "USD",
"currency": "ETH"
}'Deferred invoice
Set deferred: true to create a draft invoice without a deposit address. Activate it later to issue the deposit address and start the TTL clock.
{ "currency": "BTC", "amount": "0.001", "deferred": true }TTL and expiry
Invoices expire after ttl_minutes (default: 60 minutes). After expiry no new payments are accepted. An invoice.expired or invoice.underpaid webhook fires at expiry.
Underpayment threshold
underpayment_threshold (a fraction between 0 and 1) defines how much below the requested amount is still treated as paid. For example, 0.01 means payments within 1% of the requested amount are fully credited. Payments below the threshold result in underpaid.
Never fulfill an order from a browser redirect or client-side signal alone. Confirm from a verified invoice.paid webhook or a server-side status check.
Related webhooks
| Event | When it fires |
|---|---|
invoice.confirming | Payment detected on-chain |
invoice.paid | Payment confirmed |
invoice.overpaid | More than requested received |
invoice.underpaid | Invoice expired with partial payment |
invoice.expired | Invoice TTL elapsed with no payment |
invoice.late_payment | Payment arrived after expiry |
invoice.payment_reversed | Confirmed payment reversed (chain reorg) |