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 (the automatic retries after a failed payment), 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.

Invoices for connected merchants

A platform creates and manages invoices for a connected merchant with its platform secret key. Send the merchant ID in the Ionic-Account header, or pass the account request option to the server SDK (@ionicfi/sdk 0.4.4 or later). The invoice belongs to that merchant.
  • The platform key and the merchant’s connection must both grant invoices:write. Reading invoices and downloading PDFs need invoices:read.
  • The customer, payment method, and any price must belong to the selected merchant in the same mode. An object from another merchant returns 404.
  • Every write returns 403 MERCHANT_INACTIVE while the merchant is not active.
  • Collecting payment with POST /v1/invoices/{id}/pay and changing the card it charges with POST /v1/invoices/{id}/payment_method also need the merchant to be ready to take payments in that mode. Until then they return 403 PAYMENTS_NOT_ENABLED (403 LIVE_PAYMENTS_NOT_ENABLED in live mode), or 422 account_not_yet_active or 422 account_activation_failed while the merchant’s payment account is being set up. Other invoice and invoice item writes, including void, don’t need payments to be ready.

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.
  • An invoice item or line that names a price must use a price owned by the same account in the same mode. Any other price returns 404 PRICE_NOT_FOUND.
  • A 409 from any mutating endpoint means the invoice was modified concurrently. The request can be retried as-is.

What’s next

Adjust a paid invoice

Preview and issue a credit note against a paid invoice.

Bill on a schedule

Let Ionic issue a renewal invoice each period.

Handle invoice events

React to payment, failure, and write-off events.