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/invoicesCreates 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.
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
| Field | Type | Required | Description |
|---|---|---|---|
amountUsd | number | Yes | Amount in USD. Minimum 0.01. |
paymentTiming | object | No | Override the dashboard default timing for this invoice. |
productName | string | No | Product or service description. Max 200 chars. |
issuedBy | string | No | Organization issuing the invoice. Defaults to the dashboard issuer name. Max 120 chars. |
billTo | string | No | Customer or company name shown on the invoice. Max 120 chars. |
merchantReference | string | No | Your order or internal reference. Max 200 chars. |
customerId | string | No | Your internal customer identifier. Max 200 chars. |
customerEmail | string | No | Customer email for reconciliation. Max 320 chars. |
redirectUrl | string | No | Override the dashboard redirect URL for this invoice. |
metadata | object | No | Arbitrary 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:
{
"paymentTiming": {
"mode": "immediate",
"expiresAfterMinutes": 20
}
}Due-date invoices remain payable through the due date plus grace period:
{
"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:
{
"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/:idReturns a known invoice by id. Use this when you need the current invoice state outside a webhook handler.
curl https://fincobra.com/api/checkout/invoices/a1b2c3d4-1111-4222-8333-abcdefabcdef \
-H "X-Api-Key: fc_live_..."Short example:
{
"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/statusUse this endpoint when you need a smaller payload for status polling.
curl https://fincobra.com/api/checkout/invoices/a1b2c3d4-1111-4222-8333-abcdefabcdef/status \
-H "X-Api-Key: fc_live_..."{
"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
| Status | Meaning | Recommended merchant action |
|---|---|---|
awaiting_payment | No sufficient payment has been detected yet. | Keep the order pending. |
partially_paid | Some funds were detected, but the invoice is not fully paid. | Keep the order pending and review paymentSummary. |
payment_detected | Sufficient funds were detected but have not reached the confirmation threshold. | Keep the order pending unless your business accepts detected-but-unconfirmed payment. |
confirmed | Sufficient funds reached the confirmation threshold. | Mark the order paid. |
paid_out_of_band | The merchant recorded an external payment for the invoice. | Mark the order paid and keep the recorded note for reconciliation. |
expired | The final payable deadline passed before sufficient payment was detected. | Stop accepting payment for this invoice and prompt the customer to create a new checkout. |
voided | The 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:
| Action | When available | Final invoice state |
|---|---|---|
accept_late_payment | late_payment exception on an expired or voided invoice after full payment confirmation. | confirmed; the exception is closed. |
mark_paid_out_of_band | Open 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_unpaid | Open 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/voidVoids an awaiting_payment invoice. Voided invoices are terminal and are no longer payable.
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-paymentRecords an external payment for an awaiting_payment, partially_paid, or expired invoice.
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.