Skip to main content
Invoices let you record pending charges for a customer, compose them into a document with a gapless number, and collect payment off-session or by directing the buyer to a hosted page. On Node, npm install @ionicfi/sdk gives you typed calls for every request below; the server SDK guide has details. Each example also shows raw curl.

Lifecycle

1

(Optional) Record pending charges

Create invoice items against a customer before invoicing. When you create an invoice for that customer, every pending item in the invoice currency drains onto the new draft automatically.
2

Create a draft invoice

Call POST /v1/invoices with a customer, currency, and collection method. The draft starts with all pending items already applied as lines. Drafts carry no number and do not appear in sequences.
3

Edit the draft

Add or remove individual lines before finalizing. Totals recompute on each change.
4

Finalize

Call POST /v1/invoices/{id}/finalize to assign a sequential number, apply tax, and freeze the lines. A zero-total invoice transitions directly to paid.
5

Collect payment

For charge_automatically invoices, call POST /v1/invoices/{id}/pay. For send_invoice invoices, Ionic provides a hosted invoice page where the buyer pays directly.

Record pending charges

Invoice items record a charge against a customer without immediately billing them. When you create an invoice for that customer, all pending items in the invoice currency are drained onto it as lines and cleared from the pending queue.
An invoice item stays pending until an invoice drains it. A pending item can be updated (POST /v1/invoice_items/{id}) or deleted (DELETE /v1/invoice_items/{id}). Once drained, neither operation is allowed.

Create a draft invoice

The created invoice has status: draft and no number. Any pending invoice items for this customer in the given currency are drained onto the draft atomically.

Edit the draft

Add or remove lines while the invoice is a draft. Each call recomputes subtotal and total. Add a line
Remove a line
Both operations return 422 if the invoice is not a draft.

Finalize

Finalizing transitions the invoice from draft to open. It assigns the next gapless, per-merchant sequential number (INV-000001 in live mode, TEST-INV-000001 in test mode), applies tax, stamps finalized_at, and freezes all lines.
A zero-total invoice (all lines sum to zero plus zero tax) transitions directly to paid at finalization. No collection call is needed.
Abandoned drafts never consume a number. The finalized sequence is always contiguous.

Collect payment

charge_automatically

Call POST /v1/invoices/{id}/pay to charge the customer’s saved card off-session. Always include an Idempotency-Key — retrying without one can create a duplicate charge.
A 504 does not prove the payment failed. Do not retry with a new Idempotency-Key; the payment may already have been authorized. Retrieve the invoice or its payment attempts, and reuse the same key for the same request.
The invoice’s payment_intent field links to the payment intent created for collection (pi_…). During a dunning retry cycle, next_payment_attempt_at shows the Unix timestamp of the next scheduled attempt.

send_invoice

When collection_method is send_invoice, Ionic provides a hosted invoice page where the buyer enters their payment details. No server-side pay call is needed; the invoice transitions to paid when the buyer completes payment on the hosted page.
Subscribe to invoice.paid and invoice.payment_failed to handle collection results regardless of how the invoice was paid. See Webhook events. Event delivery can occur shortly after the API response.

Void and write off

Void cancels an open invoice that has taken no payment.
Mark uncollectible writes off an open invoice as bad debt. The outstanding balance is retained for reporting.
Both operations return 422 if the invoice is not in open status.

Invoice statuses

Payment attempts

Retrieve an invoice’s payment attempts, newest first. Use this history to show each attempt and its result.
Each attempt has a status of pending, succeeded, failed, or blocked, and a failure_code when the card was declined or blocked. pending means the final result is not known yet; retrieve the attempts again before retrying.

Retrieve and list

The list endpoint accepts customer, subscription, status, limit (default 20, max 100), and offset.

Best practices

  • Always send an Idempotency-Key on POST /v1/invoices/{id}/pay. A network timeout leaves the charge state ambiguous — retrying with the same key is safe; retrying without one risks a duplicate.
  • Distinguish 402 from 504 before deciding what to do next. A 402 is a definitive decline and requires a new payment method. A 504 means the outcome is unknown and will resolve on its own.
  • Use GET /v1/invoices/{id}/payment_attempts to show each collection try with its outcome and failure code.
  • Store your order or billing ID in metadata when creating the invoice so you can match it to records in your own system.
  • Record metered or usage-based charges as invoice items throughout the billing period. When the billing cycle closes, create one invoice per customer and currency — the pending items drain automatically.
  • A 409 from any mutating endpoint means the invoice was modified concurrently. The request can be retried as-is.