Skip to content

Invoices

Invoices are the core of BTC Checkout. Each invoice represents a payment request with a unique Bitcoin address, a USD amount converted to BTC at the current rate, and a time-to-live countdown.

Create an invoice

POST /api/checkout/invoices

Request body:

FieldTypeRequiredDescription
amountUsdnumberYesAmount in USD (minimum 0.01)
ttlMinutesintegerNoOverride default TTL. 1–1440 minutes.
productNamestringNoProduct/service description (max 200 chars)
redirectUrlstringNoOverride the config-level redirect URL for this invoice
metadataobjectNoArbitrary key-value data attached to the invoice

Example:

bash
curl -X POST \
  -H "X-Api-Key: fc_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "amountUsd": 49.99,
    "productName": "Pro Plan - Monthly",
    "metadata": {"orderId": "order_123"}
  }' \
  https://fincobra.com/api/checkout/invoices

Response (HTTP 201):

json
{
  "id": "a1b2c3d4-...",
  "amountUsd": 49.99,
  "amountBtc": 0.0005,
  "btcRate": 99980,
  "btcAddress": "bc1q...",
  "qrCode": "data:image/png;base64,...",
  "status": "pending",
  "productName": "Pro Plan - Monthly",
  "redirectUrl": "https://yoursite.com/thank-you",
  "expiresAt": "2025-01-15T10:50:00.000Z",
  "ttlMinutes": 20,
  "createdAt": "2025-01-15T10:30:00.000Z"
}

The qrCode field contains a base64-encoded PNG of a BIP-21 payment URI (bitcoin:<address>?amount=<btc>), ready to display in an <img> tag.

List invoices

GET /api/checkout/invoices

Query parameters:

ParamTypeDefaultDescription
statusstringFilter by status: pending, paid, confirmed, expired, cancelled, underpaid
limitinteger50Max results (1–200)
offsetinteger0Pagination offset

Response:

json
{
  "invoices": [
    {
      "id": "a1b2c3d4-...",
      "amountUsd": 49.99,
      "amountBtc": 0.0005,
      "btcAddress": "bc1q...",
      "status": "confirmed",
      "paymentState": "exact",
      "receivedBtc": 0.0005,
      "remainingBtc": 0,
      "overpaidBtc": 0,
      "..."
    }
  ],
  "total": 42
}

Get invoice detail

GET /api/checkout/invoices/:id

Returns full invoice data including QR code and time remaining.

Get invoice status

GET /api/checkout/invoices/:id/status

Lightweight endpoint for polling. Returns only status-related fields:

json
{
  "status": "paid",
  "confirmations": 0,
  "txHash": "abc123...",
  "txHashes": ["abc123..."],
  "paidAt": "2025-01-15T10:35:00.000Z",
  "confirmedAt": null,
  "paymentState": "exact",
  "receivedBtc": 0.0005,
  "remainingBtc": 0,
  "overpaidBtc": 0,
  "timeRemainingSeconds": 0
}

Get invoice stats

GET /api/checkout/invoices/stats

Returns aggregate counts across all your invoices:

json
{
  "total": 100,
  "pending": 5,
  "paid": 10,
  "confirmed": 75,
  "expired": 8,
  "underpaid": 2
}

Invoice status lifecycle

pending ──→ paid ──→ confirmed

   ├──→ expired      (no payment received before TTL + grace)

   └──→ underpaid    (partial payment received, then TTL + grace elapsed)
StatusDescription
pendingInvoice created, waiting for payment. Countdown is active.
paidFull BTC amount detected on-chain (0 confirmations). Waiting for block confirmation.
confirmedPayment has at least 1 block confirmation. This is the terminal success state.
expiredTTL elapsed with no payment detected.
underpaidSome BTC was received but less than required, and the grace period has elapsed.

Payment states

Each invoice also has a paymentState indicating how much BTC has been received relative to the required amount:

StateDescription
unpaidNo BTC received yet
partialSome BTC received, but less than amountBtc
exactReceived amount matches amountBtc (within 1 satoshi tolerance)
overpaidReceived more than amountBtc

The payment summary fields are:

  • receivedBtc — total BTC received at the invoice address
  • remainingBtc — BTC still needed (0 if exact or overpaid)
  • overpaidBtc — excess BTC received (0 if exact or underpaid)

Grace period

When an invoice expires but has received a partial payment, the system waits for an additional grace period (unconfirmedWaitMinutes, default 8 hours) before marking it as underpaid. This gives time for in-flight transactions to confirm. Invoices with no payment at all are expired immediately.