Invoices

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:

FieldTypeDescription
iduuidUnique invoice identifier
statusstringCurrent invoice status (see table below)
currencystringCrypto currency code (e.g. "BTC", "ETH")
networkstringBlockchain network for multi-network currencies
amount_requestedstringRequested crypto amount as a decimal string
amount_fiatstringNominated fiat amount (replaces deprecated amount_usd)
fiat_currencystringFiat currency code — currently always "USD"
amount_paidstringTotal crypto received so far
deposit_addressstringBlockchain address the customer must pay to. Absent on draft invoices before activation.
deposit_address_tagstring | nullMemo or destination tag required by some chains (e.g. XRP, XLM). null for chains that do not use tags.
is_deferredbooleantrue for deferred invoices that start in draft status without a deposit address.
paid_atdatetime | nullTimestamp when the invoice reached paid status. null while unpaid.
checkout_urlstringHosted payment page URL for the customer
external_idstringYour own reference ID
metadataobjectArbitrary key-value store for your use
expires_atdatetimeWhen the invoice expires (controlled by ttl_minutes)
created_atdatetimeCreation timestamp

Statuses

StatusMeaning
draftCreated in deferred mode — no payment address yet
pendingAwaiting payment — deposit address issued
confirmingPayment detected on-chain, awaiting required confirmations
paidPayment confirmed — safe to fulfill
overpaidCustomer sent more than the requested amount
underpaidInvoice expired with partial payment below the threshold
expiredInvoice TTL elapsed without sufficient payment
cancelledCancelled before payment
invalidCreated 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.

EventWhen it fires
invoice.confirmingPayment detected on-chain
invoice.paidPayment confirmed
invoice.overpaidMore than requested received
invoice.underpaidInvoice expired with partial payment
invoice.expiredInvoice TTL elapsed with no payment
invoice.late_paymentPayment arrived after expiry
invoice.payment_reversedConfirmed payment reversed (chain reorg)

Methods

  • CreatePOST /v1/invoices
  • ListGET /v1/invoices
  • GetGET /v1/invoices/{invoiceID}