> ## Documentation Index
> Fetch the complete documentation index at: https://docs.monigo.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Invoice Lifecycle

> How invoices move from draft to finalized to paid — and when to void them.

Every billing period produces one invoice per subscription. An invoice starts as a draft, gets finalized when amounts are locked, transitions to paid when the charge succeeds, and can be voided if something goes wrong. This guide covers each state and the transitions between them.

## Status overview

```mermaid theme={null}
stateDiagram-v2
    [*] --> draft : generate

    draft --> finalized : finalize
    finalized --> paid
    finalized --> void

    paid --> [*]
    void --> [*]
```

| Status      | Description                                                    |
| ----------- | -------------------------------------------------------------- |
| `draft`     | Invoice exists but amounts are not locked. Can be regenerated. |
| `finalized` | Amounts are locked. Payment collection is in progress.         |
| `paid`      | Payment was collected successfully.                            |
| `void`      | The invoice was voided. No charge was collected.               |

***

## Draft

A draft invoice is created automatically at the end of each billing period, or manually via the API. In draft state:

* Line items reflect the latest aggregated usage
* The invoice can be regenerated (if usage was updated)
* No charge has been attempted

**Generate a draft invoice manually:**

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.monigo.co/v1/invoices/generate \
    -H "Authorization: Bearer mk_live_..." \
    -H "Content-Type: application/json" \
    -d '{ "subscription_id": "<subscription_id>" }'
  ```

  ```go Go theme={null}
  invoice, err := client.Invoices.Generate(ctx, subscriptionID)
  ```

  ```ts TypeScript theme={null}
  const invoice = await client.invoices.generate(subscriptionId)
  ```
</CodeGroup>

**Inspect a draft invoice:**

<CodeGroup>
  ```bash cURL theme={null}
  curl https://api.monigo.co/v1/invoices/<invoice_id> \
    -H "Authorization: Bearer mk_live_..."
  ```

  ```go Go theme={null}
  invoice, err := client.Invoices.Get(ctx, invoiceID)
  ```

  ```ts TypeScript theme={null}
  const invoice = await client.invoices.get(invoiceId)
  ```
</CodeGroup>

The response includes `line_items` — one entry per metric/price pair — so you can verify each charge before finalizing.

***

## Finalized

Finalizing locks the invoice amounts. Once finalized:

* Line item amounts cannot be changed
* Payment collection is triggered automatically
* The `invoice.finalized` webhook fires

**Finalize an invoice:**

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.monigo.co/v1/invoices/<invoice_id>/finalize \
    -H "Authorization: Bearer mk_live_..."
  ```

  ```go Go theme={null}
  finalized, err := client.Invoices.Finalize(ctx, invoiceID)
  ```

  ```ts TypeScript theme={null}
  const finalized = await client.invoices.finalize(invoiceId)
  ```
</CodeGroup>

<Info>
  In the automatic billing cycle, Monigo finalizes invoices for you. You only need to call finalize manually if you generated a draft invoice yourself and want to trigger collection.
</Info>

***

## Paid

When Monigo successfully collects payment from your configured provider, the invoice moves to `paid`. The `invoice.paid` webhook fires and `paid_at` is set.

If collection fails (insufficient funds, expired card, etc.), the invoice remains `finalized` and the `invoice.payment_failed` webhook fires. Monigo does not automatically retry — you should listen for this webhook and take action (notify the customer, pause the subscription, retry after they update their payment method).

**List paid invoices for a customer:**

<CodeGroup>
  ```bash cURL theme={null}
  curl "https://api.monigo.co/v1/invoices?customer_id=<customer_id>&status=paid" \
    -H "Authorization: Bearer mk_live_..."
  ```

  ```go Go theme={null}
  list, err := client.Invoices.List(ctx, monigo.ListInvoicesParams{
      CustomerID: customerID,
      Status:     monigo.InvoiceStatusPaid,
  })
  ```

  ```ts TypeScript theme={null}
  const list = await client.invoices.list({
    customer_id: customerId,
    status: InvoiceStatus.Paid,
  })
  ```
</CodeGroup>

***

## Void

Voiding cancels an invoice without collecting payment. Void a `draft` or `finalized` invoice when:

* The invoice was generated in error
* The customer should not be charged for that period
* You need to issue a corrected invoice (void → regenerate)

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.monigo.co/v1/invoices/<invoice_id>/void \
    -H "Authorization: Bearer mk_live_..."
  ```

  ```go Go theme={null}
  voided, err := client.Invoices.Void(ctx, invoiceID)
  ```

  ```ts TypeScript theme={null}
  const voided = await client.invoices.void(invoiceId)
  ```
</CodeGroup>

<Warning>
  A `paid` invoice cannot be voided. If you need to reverse a collected payment, issue a refund directly through your payment provider (Paystack, Flutterwave, or Monnify).
</Warning>

**Void and regenerate (correcting an invoice):**

```bash theme={null}
# 1. Void the incorrect invoice
curl -X POST https://api.monigo.co/v1/invoices/<invoice_id>/void \
  -H "Authorization: Bearer mk_live_..."

# 2. Replay affected events if needed (see Idempotency guide)
curl -X POST https://api.monigo.co/v1/events/replay \
  -H "Authorization: Bearer mk_live_..." \
  -d '{ "from": "2026-02-01T00:00:00Z", "to": "2026-02-28T23:59:59Z" }'

# 3. Generate a fresh draft
curl -X POST https://api.monigo.co/v1/invoices/generate \
  -H "Authorization: Bearer mk_live_..." \
  -d '{ "subscription_id": "<subscription_id>" }'
```

***

## Webhook events

| Event                    | Status transition | Fired when                     |
| ------------------------ | ----------------- | ------------------------------ |
| `invoice.created`        | → `draft`         | A draft invoice is generated   |
| `invoice.finalized`      | → `finalized`     | Invoice amounts are locked     |
| `invoice.paid`           | → `paid`          | Payment collected successfully |
| `invoice.payment_failed` | stays `finalized` | Payment collection failed      |
| `invoice.voided`         | → `void`          | Invoice is voided              |

***

## Related

* [Billing Cycle](/concepts/billing-cycle) — when invoices are generated automatically
* [Idempotency & Replayability](/guides/idempotency) — replaying events before regenerating
* [Webhooks](/integrations/webhooks) — receiving and verifying invoice events
