Invoices
An invoice is the financial artifact your customer pays. Every charge - recurring plan fee, mid-cycle proration, metered usage, one-off add-on - lands as a typed line on an invoice. Tax and FX state are pinned at finalize, so an invoice generated months ago replays bit-exact even if rates, rules, or prices changed underneath.
Lifecycle
Code
| Status | Meaning |
|---|---|
draft | Mutable working state - lines can be added, totals recompute on each change |
pending_approval | Held for an approval gate before it can finalize |
finalized | Immutable - totals locked, tax + FX rates pinned, invoice_number assigned, customer can be billed |
overdue | Past due_date without full payment; the dunning policy is now retrying |
paid | Fully paid (terminal - no transitions out) |
void | Cancelled / written off (terminal) |
error | Payment-retry exhausted; sits here until an operator manually retries (→ paid) or voids it |
Transitions are state-machine enforced - invalid transitions return 409 INVALID_TRANSITION.
Generating an invoice
Two paths into draft:
Code
Kontorion generates invoices automatically based on subscription billing periods:
- Billing period ends (or starts, depending on advance/arrears configuration)
- For each active subscription, a draft invoice is created with:
- Recurring charges for each product in the plan
- Usage charges (aggregated from usage events via configured aggregators)
- Prorated charges for mid-cycle changes
- Applied discounts and promotions
- Tax calculations based on applicable tax rules
- The invoice is finalized automatically (or held for approval, if a workflow is configured)
Generating an invoice
Trigger invoice generation for a subscription. The endpoint is POST /v1/invoices/generate (not a plain POST /v1/invoices):
Code
| Field | Required | Notes |
|---|---|---|
subscription_id | yes | UUID. The subscription to generate the invoice for. |
billing_period_start / billing_period_end | no | RFC 3339 timestamps. When omitted, the current open period is used. |
locale | no | One of en, de, fr, es, it, pt, nl, ja. Drives PDF/XRechnung wording. |
Returns 201 Created with the freshly generated invoice (in draft status). To finalize, call POST /v1/invoices/{id}/finalize.
Invoice line items
For closed-period generation by the scheduler (the typical path), this happens automatically at current_period_end - you usually don't call generate yourself.
Finalizing
FX policy & exchange-rate pinning
When the invoice currency differs from the catalog currency, every finalized invoice records three candidate exchange-rate IDs: issue_exchange_rate_id and period_start_exchange_rate_id on the invoice header, and segment_exchange_rate_id on each line. The active org fx_policy (set on the org's tax profile) decides which candidate's rate is the one that shaped the totals; the other two are kept for audit and "what-if" rendering. fx_policy_applied on each line tells you which one won.
Audit atoms
For invoices that span a price-version split or cover multiple price_keys under a keyed product, each line decomposes into atoms - one per (price_key × time-segment) computation unit. Atoms always sum to their parent line's totals and carry the per-tier walk for STAIRCASE / VOLUME / PACKAGE pricing, so customer-facing breakdowns can be rendered without re-running the price evaluator. Fetch with GET /invoices/{id}?depth=full to populate the atoms array.
Adding lines to an invoice
For pass-through costs or one-off charges, add a line to a draft invoice via POST /v1/invoices/{id}/lines. Lines on a draft invoice can be patched with PATCH /v1/invoices/{id}/lines/{line_id} and removed with DELETE /v1/invoices/{id}/lines/{line_id}. The shape of the line input matches the invoice line model (see invoice_lines.go).
Refunds
Credit notes are special invoices that reverse or adjust charges from a previous invoice. They reduce the amount owed and can trigger a refund.
Use cases:
- Partial refund for a service outage
- Full refund for a mistaken charge
- Adjustment for incorrect pricing
Credit notes reference the original invoice via credit_note_of and follow the same lifecycle as regular invoices.
PDF export
Generate a formatted PDF for any finalized invoice:
Code
Response is application/pdf (binary).
The PDF includes:
- Your organization's branding and legal details
- Customer billing information
- Itemized charges with quantities, rates, and tax breakdown
- Payment instructions and due date
- Invoice and buyer reference numbers
Voiding & regenerating
| Endpoint | Use for |
|---|---|
POST /v1/invoices/{id}/void | Cancel a finalized invoice (terminal). For accounting purity, prefer issuing a credit note - voiding loses the financial record |
POST /v1/invoices/{id}/regenerate | Re-finalize using current state. Useful after fixing data the original finalize captured incorrectly. The new invoice replaces the old one and inherits the same invoice_number |
Code
Related
When an invoice is finalized, Kontorion can automatically attempt payment collection through the configured payment gateway:
- Check for available wallet balance - deduct from wallet first
- If remaining balance, charge the customer's default payment method
- If payment fails, enter the dunning flow (retry schedule + escalation)
Manual payment recording
For payments collected outside Kontorion (bank transfer, check, etc.):
Code
Approval workflows
Approval workflows for invoices are on the roadmap - the storage layer is in place but the public REST surface is not yet wired. When it ships, an approval-required invoice will stay in draft until the request resolves; rejection returns the invoice to operator review.
Next steps
- Subscriptions - how subscriptions generate invoices
- Pricing Models - how charges are calculated
- Error Handling - understanding error responses
- API Reference - Invoices - full endpoint documentation