Invoices
Every billing period the subscription engine generates an invoice — the record of what is owed and what happened while collecting it. This page covers reading invoices, the two mutations (void, retry-charge), and the dunning machinery that retries failed charges before giving up.
All endpoints use your secret key as a Bearer token under https://api-gateway.lunixi.com/api/v1/subscriptions. List endpoints use cursor pagination (pageSize, pageToken).
All invoice amounts are minor-unit (kuruş) integers — "amount": 149900 is ₺1.499,00.
Invoice lifecycle
invoice.paid arrives late — your webhook consumer must treat it as a delayed success.POST :id/void can take an open invoice out of the flow at any point (invoice.voided).
Status values
The status field on an invoice takes exactly these values:
status | Meaning |
|---|---|
DRAFT | Not finalized yet — no charge is triggered |
OPEN | Finalized — collection is attempted |
PAID | Fully collected — terminal |
UNCOLLECTIBLE | Max dunning attempts exhausted — terminal |
VOID | Manually voided — terminal |
The transitions are DRAFT → OPEN → PAID | UNCOLLECTIBLE | VOID; the three terminal statuses never change again.
List & retrieve
| Method | Path | What it does |
|---|---|---|
GET | /subscriptions/invoices | List invoices (cursor pagination) |
GET | /subscriptions/invoices/:id | One invoice with its line items and collection history |
curl "https://api-gateway.lunixi.com/api/v1/subscriptions/invoices?pageSize=20" \
-H "Authorization: Bearer at_live_5f3e2b1a..."{
"id": "inv_01JX9A2C6R",
"subscriptionId": "sub_01JX5B8R3M",
"status": "OPEN",
"amount": 149900,
"currency": "TRY",
"periodStart": "2026-07-01T00:00:00Z",
"periodEnd": "2026-08-01T00:00:00Z"
}Void an invoice
POST /subscriptions/invoices/:id/void cancels an open invoice — no further collection attempts will be made for it. Use it for goodwill credits, billing mistakes, or when you settle a dispute out-of-band. Emits invoice.voided.
curl -X POST https://api-gateway.lunixi.com/api/v1/subscriptions/invoices/inv_01JX9A2C6R/void \
-H "Authorization: Bearer at_live_5f3e2b1a..."Retry a charge
POST /subscriptions/invoices/:id/retry-charge triggers an immediate collection attempt, outside the automatic dunning schedule. Typical use: the customer just updated their card (you received subscription.payment_card_swapped or card.added) and you want to collect right away instead of waiting for the next scheduled retry.
curl -X POST https://api-gateway.lunixi.com/api/v1/subscriptions/invoices/inv_01JX9A2C6R/retry-charge \
-H "Authorization: Bearer at_live_5f3e2b1a..."Dunning
When an AUTO_CHARGE collection fails, the invoice enters dunning: a schedule of automatic retries whose shape you define on the plan — see Plans:
| Plan field | Role in dunning |
|---|---|
maxDunningAttempts | How many automatic retries before giving up |
dunningScheduleDays | When each retry runs, as day offsets from the first failure (e.g. [1, 3, 7]) |
gracePeriodDays | How long the subscription keeps its entitlements while the invoice is unpaid |
The flow, event by event:
invoice.payment_failed
The first charge (or a retry) failed. React here: e-mail the customer, show an in-app banner, point them at the customer portal to update their card.
Scheduled retries
The platform retries per dunningScheduleDays. Each failed retry emits another invoice.payment_failed; a successful one emits invoice.paid and dunning ends. A manual retry-charge also counts as an attempt to collect the same invoice.
invoice.uncollectible
All maxDunningAttempts are exhausted. The invoice is marked uncollectible — decide your policy: suspend access, keep the subscription in a degraded state, or write the amount off.
During gracePeriodDays the customer keeps access even though the invoice is unpaid — dunning is a recovery window, not an instant cut-off. Choose plan values that match how tolerant your product wants to be.
Payment method lost
If the stored card behind an AUTO_CHARGE subscription becomes unusable — deleted, or expired with no replacement — the platform emits subscription.payment_method_lost and switches the subscription's collection to MANUAL: invoices keep being issued, but nothing is auto-charged.
Recovery: the customer adds a new card (portal cards/update, or merchant API POST /subscriptions/cards + set-default), then you collect open invoices with retry-charge and, if desired, switch the subscription back to AUTO_CHARGE.
Errors
| Status | Meaning | What to do |
|---|---|---|
401 | Missing/invalid Bearer key | Check the Authorization header |
404 | Invoice not found | Verify the id belongs to your account |
409 | Invalid state (voiding a paid invoice, retry-charging a voided/paid one) | Read GET /invoices/:id and act on the current state |
422 | Retry not possible — e.g. no usable card on the subscription | Have the customer add a card first, then retry |
Webhooks
| Event | When |
|---|---|
invoice.created | A period invoice was generated |
invoice.paid | Collection succeeded (auto, retry-charge or manual settlement) |
invoice.payment_failed | A charge attempt failed — dunning is running |
invoice.uncollectible | Dunning exhausted; the invoice will not be collected automatically |
invoice.voided | The invoice was voided |
subscription.payment_method_lost | Stored card unusable — collection fell back to MANUAL |
See Webhooks for delivery and signature verification.
Next steps
- Plans — configure
maxDunningAttempts,dunningScheduleDays,gracePeriodDays - Subscriptions — collection methods and lifecycle
- Customer Portal — where customers fix their own failed payments