Skip to content

Invoices

Invoices are the core checkout object. Each invoice represents one USD payment request.

Use the dashboard to configure payment methods and create an API key. Use the API key from your server to create invoices and read invoice state.

Create an Invoice

POST /api/checkout/invoices

Creates an invoice using the payment methods configured in the dashboard. The response includes an invoice id and paymentUrl.

Store both values with your order. Send the customer to paymentUrl to complete payment on the hosted payment page.

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

Request Body

FieldTypeRequiredDescription
amountUsdnumberYesAmount in USD. Minimum 0.01.
paymentTimingobjectNoOverride the dashboard default timing for this invoice.
productNamestringNoProduct or service description. Max 200 chars.
issuedBystringNoOrganization issuing the invoice. Defaults to the dashboard issuer name. Max 120 chars.
billTostringNoCustomer or company name shown on the invoice. Max 120 chars.
merchantReferencestringNoYour order or internal reference. Max 200 chars.
customerIdstringNoYour internal customer identifier. Max 200 chars.
customerEmailstringNoCustomer email for reconciliation. Max 320 chars.
redirectUrlstringNoOverride the dashboard redirect URL for this invoice.
metadataobjectNoArbitrary JSON object attached to the invoice. metadata.notes, when present, must be a string up to 140 chars.

Invoice Timing

Immediate invoices expire after a configured number of minutes:

json
{
  "paymentTiming": {
    "mode": "immediate",
    "expiresAfterMinutes": 20
  }
}

Due-date invoices remain payable through the due date plus grace period:

json
{
  "paymentTiming": {
    "mode": "due_date",
    "dueAfterDays": 7,
    "gracePeriodDays": 14
  }
}

Due-date invoices require an enabled USDT or USDC payment method on Ethereum. Bitcoin payment methods are only used for immediate invoices.

Response

FinCobra returns HTTP 201 with the invoice object. Most integrations only need these fields:

json
{
  "id": "a1b2c3d4-1111-4222-8333-abcdefabcdef",
  "paymentUrl": "https://fincobra.com/pay/a1b2c3d4-1111-4222-8333-abcdefabcdef",
  "amountUsd": 49.99,
  "status": "awaiting_payment",
  "paymentCoverage": "no_payment",
  "receivedAmountUsd": 0,
  "confirmedAmountUsd": 0,
  "productName": "Pro Plan - Monthly",
  "merchantReference": "order_123",
  "customerEmail": "buyer@example.com",
  "metadata": {
    "orderId": "order_123"
  },
  "paymentTiming": {
    "mode": "immediate",
    "expiresAfterMinutes": 20,
    "payableUntilAt": "2026-04-29T10:20:00.000Z"
  },
  "paymentSummary": {
    "paymentCoverage": "no_payment",
    "receivedAmountUsd": 0,
    "confirmedAmountUsd": 0,
    "remainingAmountUsd": 49.99,
    "overpaymentAmountUsd": 0
  }
}

The full response also includes payment options and timestamps. See API Reference for the complete contract.

Get Invoice Detail

GET /api/checkout/invoices/:id

Returns a known invoice by id. Use this when you need the current invoice state outside a webhook handler.

bash
curl https://fincobra.com/api/checkout/invoices/a1b2c3d4-1111-4222-8333-abcdefabcdef \
  -H "X-Api-Key: fc_live_..."

Short example:

json
{
  "id": "a1b2c3d4-1111-4222-8333-abcdefabcdef",
  "paymentUrl": "https://fincobra.com/pay/a1b2c3d4-1111-4222-8333-abcdefabcdef",
  "status": "payment_detected",
  "paymentCoverage": "exact_payment",
  "receivedAmountUsd": 49.99,
  "confirmedAmountUsd": 0,
  "confirmations": 1,
  "paymentDetectedAt": "2026-04-29T10:05:00.000Z",
  "confirmedAt": null,
  "merchantReference": "order_123",
  "paymentSummary": {
    "paymentCoverage": "exact_payment",
    "receivedAmountUsd": 49.99,
    "confirmedAmountUsd": 0,
    "remainingAmountUsd": 0,
    "overpaymentAmountUsd": 0
  },
  "payments": []
}

Get Invoice Status

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

Use this endpoint when you need a smaller payload for status polling.

bash
curl https://fincobra.com/api/checkout/invoices/a1b2c3d4-1111-4222-8333-abcdefabcdef/status \
  -H "X-Api-Key: fc_live_..."
json
{
  "status": "payment_detected",
  "paymentCoverage": "exact_payment",
  "receivedAmountUsd": 49.99,
  "confirmedAmountUsd": 0,
  "confirmations": 1,
  "paymentDetectedAt": "2026-04-29T10:05:00.000Z",
  "confirmedAt": null,
  "paidOutOfBandAt": null,
  "paidOutOfBandNote": null,
  "paymentSummary": {
    "paymentCoverage": "exact_payment",
    "receivedAmountUsd": 49.99,
    "confirmedAmountUsd": 0,
    "remainingAmountUsd": 0,
    "overpaymentAmountUsd": 0
  },
  "lastPaymentObservedAt": "2026-04-29T10:05:00.000Z"
}

Webhooks are preferred over polling for production order updates. Polling is useful for admin screens, fallback checks, and local testing.

Status Handling

StatusMeaningRecommended merchant action
awaiting_paymentNo sufficient payment has been detected yet.Keep the order pending.
partially_paidSome funds were detected, but the invoice is not fully paid.Keep the order pending and review paymentSummary.
payment_detectedSufficient funds were detected but have not reached the confirmation threshold.Keep the order pending unless your business accepts detected-but-unconfirmed payment.
confirmedSufficient funds reached the confirmation threshold.Mark the order paid.
paid_out_of_bandThe merchant recorded an external payment for the invoice.Mark the order paid and keep the recorded note for reconciliation.
expiredThe final payable deadline passed before sufficient payment was detected.Stop accepting payment for this invoice and prompt the customer to create a new checkout.
voidedThe invoice was voided before payment was detected.Stop accepting payment for this invoice.

Payment Timing Model

The invoice payable window decides whether payment is on time. A payment first observed at or before paymentTiming.payableUntilAt is on time; a payment first observed after that timestamp is late. Payment events can still be observed and confirmed after the payable window, but a late payment does not automatically make an expired or voided invoice paid.

On-time full payment moves the invoice to payment_detected and then confirmed after the configured confirmation threshold. For Bitcoin, the post-expiry confirmation grace applies only when the full quoted Bitcoin amount was observed at or before payableUntilAt; it gives that on-time Bitcoin payment more time to confirm. It does not make late first payments or late top-ups valid.

If the payable deadline passes while only a partial payment has been observed, the invoice becomes expired with paymentCoverage: "partial_payment" and opens a partial_payment exception. If a full or extra payment arrives after the payable window, the invoice stays expired or voided, paymentCoverage reflects the observed amount, and a late_payment exception opens for merchant review.

Exception actions have fixed invoice outcomes:

ActionWhen availableFinal invoice state
accept_late_paymentlate_payment exception on an expired or voided invoice after full payment confirmation.confirmed; the exception is closed.
mark_paid_out_of_bandOpen late_payment or partial_payment exception when the merchant received payment outside FinCobra.paid_out_of_band; the exception is closed and the note is stored on the invoice.
close_unpaidOpen exception on an expired or voided invoice that should remain unpaid.The invoice stays expired or voided; the exception is closed.

Overpayment during the payable window does not open an exception. The invoice follows the normal payment lifecycle and shows paymentCoverage: "overpayment" plus the excess amount in paymentSummary.overpaymentAmountUsd.

Void an Invoice

POST /api/checkout/invoices/:id/void

Voids an awaiting_payment invoice. Voided invoices are terminal and are no longer payable.

bash
curl -X POST https://fincobra.com/api/checkout/invoices/a1b2c3d4-1111-4222-8333-abcdefabcdef/void \
  -H "X-Api-Key: fc_live_..." \
  -H "Content-Type: application/json" \
  -d '{}'

Record Payment

POST /api/checkout/invoices/:id/record-payment

Records an external payment for an awaiting_payment, partially_paid, or expired invoice.

bash
curl -X POST https://fincobra.com/api/checkout/invoices/a1b2c3d4-1111-4222-8333-abcdefabcdef/record-payment \
  -H "X-Api-Key: fc_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "note": "Paid by wire transfer"
  }'

The note field is required and can be up to 2000 characters. The updated invoice has status: "paid_out_of_band", paidOutOfBandAt, and paidOutOfBandNote.

status is the fulfillment state for the invoice. paymentCoverage explains whether the invoice has no payment, a partial payment, an exact payment, or an overpayment. Overpayment does not open an exception; the invoice remains in its payment lifecycle state and the excess amount is shown in paymentSummary.overpaymentAmountUsd. receivedAmountUsd, confirmedAmountUsd, and paymentSummary are USD-denominated.

Use payments[] when you need payment-level details such as transaction hash, observed amount, confirmations, and confirmedAt.

Payment Options

Invoices include paymentOptions[] for hosted and custom payment pages. A standard hosted-page integration can ignore this field and redirect customers to paymentUrl.

Use paymentOptions[] only when you are building custom payment UI. See API Reference for the field contract.