Invoices overview
Itemized statements of what a customer owes.
An invoice is an itemized statement VINR generates from a subscription cycle or that you create directly, then collects payment against. It is the bridge between Billing (deciding what a customer owes) and Payments (actually collecting it).
The invoice lifecycleAsk
Every invoice — whether subscription-generated or hand-built — moves through the same states. Knowing the current status tells you exactly what you can and cannot change.
| Status | Meaning | Mutable? |
|---|---|---|
draft | Being assembled. Line items can be added or removed. | Yes |
open | Finalized and awaiting payment. Amounts are locked. | No (totals) |
paid | Collected in full. | No |
uncollectible | Written off after dunning gave up. | No |
void | Cancelled before payment; reverses any accounting. | No |
Finalizing is the one-way door. A draft becomes open once you finalize it (or VINR auto-finalizes a subscription invoice an hour after it is created). After that, the only ways out are payment, void, or uncollectible.
How collection worksAsk
When an invoice finalizes, VINR computes the amount due, then attempts a payment against the customer's default method based on the invoice's collection_method:
charge_automatically— VINR charges the saved method immediately and runs dunning on failure. This is the default for subscriptions.send_invoice— VINR issues a hosted invoice page and payment link; the customer pays on their own time, bounded bydays_until_due.
Discounts from coupons and tax are applied during finalization, so the total you see on an open invoice already reflects them.
Create an invoice directlyAsk
For one-off charges that do not belong to a subscription — a setup fee, professional services, a manual top-up — build the invoice yourself. Add invoice items first, then finalize.
import { Vinr } from '@vinr/sdk';
const vinr = new Vinr({ secretKey: process.env.VINR_SECRET_KEY });
// 1. Attach line items to the customer's pending (draft) invoice.
await vinr.invoiceItems.create({
customer: 'cust_8aJ2k',
amount: 15000, // €150.00, integer minor units
currency: 'EUR',
description: 'Onboarding setup fee',
});
// 2. Create the invoice that sweeps up pending items.
const invoice = await vinr.invoices.create({
customer: 'cust_8aJ2k',
collectionMethod: 'send_invoice',
daysUntilDue: 14,
}); // status: "draft", id: "inv_..."
// 3. Finalize to lock totals and open it for payment.
const open = await vinr.invoices.finalize(invoice.id);
console.log(open.status, open.total, open.hostedInvoiceUrl);
// "open" 15000 "https://pay.vinr.com/inv_..."The same flow over raw REST hits POST https://api.vinr.com/v1/invoices with an X-Api-Key: <key> header; use the sandbox.api.vinr.com base and a test card such as 4242 4242 4242 4242 to walk it end to end.
Reading and reconcilingAsk
Each finalized invoice carries the numbers finance teams reconcile against. The key fields:
Prop
Type
Every invoice exposes a stable hostedInvoiceUrl (a branded payment page) and an invoicePdf link, so you rarely need to render statements yourself.
Resulting eventsAsk
Drive your accounting and fulfilment off webhooks rather than polling. The lifecycle emits:
invoice.finalized— totals are locked; safe to record as a receivable.invoice.paid— collected in full; grant access or ship the goods here.invoice.payment_failed— collection failed; dunning takes over.invoice.voided— reversed before payment; back out any receivable.
const event = vinr.webhooks.verify(payload, req.headers['x-vinr-signature']);
if (event.type === 'invoice.paid') {
const invoice = event.data.object; // "inv_..."
await fulfilAccess(invoice.customer, invoice.lines);
}Edge casesAsk
Next stepsAsk
How billing works
Where invoices sit in the recurring-revenue flow.
Dunning & recovery
What happens when collection fails.
Invoice items API
Reference for line items and one-off charges.
Last updated on