> ## 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.

# Prepaid Billing

> Charge customers from a wallet balance at period-end instead of issuing a payment request. Subscriptions pause automatically when balance runs low and resume when funds are added.

With **postpaid billing** (the default), Monigo generates an invoice at period-end and then collects payment via your connected payment provider. With **prepaid billing**, the customer maintains a wallet balance and Monigo debits that wallet atomically when the invoice is generated — no separate payment step required.

Prepaid works best when:

* Customers pre-purchase credits (SaaS with top-up model, APIs with token packs)
* You need deterministic settlement at billing time with no failed-payment recovery loops
* Your customers are API-first businesses that want to fund accounts rather than maintain card-on-file

<Info>
  Prepaid billing is only available on **collection** plans. Payout plans always use postpaid flow.
</Info>

## How it works

```mermaid theme={null}
flowchart TD
    A[Period Ends] --> B[Usage Aggregated<br>+ Pricing Applied]
    B --> C{Wallet Balance ≥ Total?}

    C -->|YES| D[Wallet Debited Atomically]
    D --> E[Invoice Created as 'paid'<br>no draft · no finalize step]
    E --> F[Period Advances]
    F --> G[/invoice.paid webhook fired/]

    C -->|NO| H[Draft Invoice Created\naudit trail]
    H --> I[Subscription Status → 'paused']
    I --> J[/subscription.prepaid_balance_insufficient<br>webhook fired/]
    J --> K[Period Does NOT Advance<br>customer must top up to resume]

    style A fill:#1F2937,color:#fff,stroke:#374151
    style B fill:#F3F4F6,color:#1F2937,stroke:#D1D5DB
    style C fill:#F3F4F6,color:#1F2937,stroke:#6B7280
    style D fill:#DCFCE7,color:#14532D,stroke:#16A34A
    style E fill:#DCFCE7,color:#14532D,stroke:#16A34A
    style F fill:#DCFCE7,color:#14532D,stroke:#16A34A
    style G fill:#16A34A,color:#fff,stroke:#14532D
    style H fill:#FEF3C7,color:#92400E,stroke:#F59E0B
    style I fill:#FEE2E2,color:#991B1B,stroke:#EF4444
    style J fill:#FEE2E2,color:#991B1B,stroke:#EF4444
    style K fill:#FEE2E2,color:#991B1B,stroke:#EF4444
```

When the customer tops up their wallet with enough funds, Monigo automatically retries billing and resumes the subscription — no manual intervention needed.

***

## Setting up a prepaid plan

Add `"billing_mode": "prepaid"` when creating a collection plan:

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.monigo.co/v1/plans \
    -H "Authorization: Bearer mk_live_..." \
    -H "Content-Type: application/json" \
    -d '{
      "name": "API Starter",
      "currency": "NGN",
      "plan_type": "collection",
      "billing_period": "monthly",
      "billing_mode": "prepaid"
    }'
  ```

  ```go Go theme={null}
  plan, err := client.Plans.Create(ctx, monigo.CreatePlanParams{
      Name:          "API Starter",
      Currency:      "NGN",
      PlanType:      "collection",
      BillingPeriod: "monthly",
      BillingMode:   "prepaid",
  })
  ```

  ```ts TypeScript theme={null}
  const plan = await client.plans.create({
    name: "API Starter",
    currency: "NGN",
    plan_type: "collection",
    billing_period: "monthly",
    billing_mode: "prepaid",
  });
  ```
</CodeGroup>

The `billing_mode` field on a plan defaults to `"postpaid"` and is immutable once the plan has active subscribers.

***

## Wallet auto-creation

When a customer subscribes to a prepaid plan, Monigo automatically creates a wallet in the plan's currency if one does not already exist. No explicit wallet-creation step is needed.

You can fetch or top-up a customer's wallet at any time:

<CodeGroup>
  ```bash cURL theme={null}
  # List wallets for a customer
  curl https://api.monigo.co/v1/customers/{customer_id}/wallets \
    -H "Authorization: Bearer mk_live_..."

  # Credit a wallet
  curl -X POST https://api.monigo.co/v1/wallets/{wallet_id}/credit \
    -H "Authorization: Bearer mk_live_..." \
    -H "Content-Type: application/json" \
    -d '{
      "amount": "10000.00",
      "description": "Top-up via payment link",
      "idempotency_key": "topup_<your_reference>"
    }'
  ```

  ```go Go theme={null}
  // Credit a wallet
  entry, err := client.Wallets.Credit(ctx, walletID, monigo.CreditWalletParams{
      Amount:         "10000.00",
      Description:    "Top-up via payment link",
      IdempotencyKey: "topup_<your_reference>",
  })
  ```

  ```ts TypeScript theme={null}
  const entry = await client.wallets.credit(walletId, {
    amount: "10000.00",
    description: "Top-up via payment link",
    idempotency_key: "topup_<your_reference>",
  });
  ```
</CodeGroup>

<Tip>
  Always provide an `idempotency_key` when crediting wallets. This prevents double-credits if the request is retried.
</Tip>

***

## The happy path: billing with sufficient balance

When billing runs and the wallet has enough funds, Monigo:

1. Aggregates usage for the period
2. Calculates the invoice total using the plan's prices
3. Debits the wallet atomically (debit is recorded in the ledger)
4. Creates the invoice directly with `status: "paid"` — no draft or finalize step
5. Advances the subscription to the next period
6. Fires an `invoice.paid` webhook

The resulting invoice will have:

| Field          | Value                  |
| -------------- | ---------------------- |
| `status`       | `"paid"`               |
| `paid_at`      | Timestamp of the debit |
| `wallet_debit` | `true`                 |

No charge is submitted to your payment provider for prepaid invoices — settlement is entirely wallet-based.

***

## Handling insufficient balance

If the wallet balance is lower than the invoice total when billing runs:

1. A draft invoice is created as an audit record (period is **not** advanced)
2. The subscription status moves to `"paused"`
3. A `subscription.prepaid_balance_insufficient` webhook is fired

```json theme={null}
{
  "event": "subscription.prepaid_balance_insufficient",
  "data": {
    "subscription_id": "sub_...",
    "customer_id": "cus_...",
    "plan_id": "pla_...",
    "wallet_balance": "450.00",
    "invoice_total": "1200.00",
    "currency": "NGN"
  }
}
```

Use this webhook to notify the customer (email, WhatsApp, in-app banner) that their balance is low and prompt them to top up.

<Warning>
  The billing job for a paused prepaid subscription is non-retryable. The subscription stays paused until the customer tops up — at which point Monigo auto-resumes (see below). Do not manually re-trigger billing; instead, credit the wallet and let Monigo handle the rest.
</Warning>

***

## Auto-resume on top-up

When you credit a wallet belonging to a customer with a paused prepaid subscription, Monigo:

1. Checks whether the new balance covers the outstanding invoice total
2. If yes: retries billing immediately — debits the wallet, creates the invoice as `"paid"`, and moves the subscription back to `"active"`
3. If still insufficient: leaves the subscription paused

This is fully automatic. The resume flow fires the same `invoice.paid` webhook as a normal billing cycle.

<CodeGroup>
  ```bash cURL theme={null}
  # Top up the wallet — Monigo auto-resumes the subscription if balance is now sufficient
  curl -X POST https://api.monigo.co/v1/wallets/{wallet_id}/credit \
    -H "Authorization: Bearer mk_live_..." \
    -H "Content-Type: application/json" \
    -d '{
      "amount": "5000.00",
      "description": "Manual top-up",
      "idempotency_key": "topup_abc123"
    }'
  ```

  ```go Go theme={null}
  entry, err := client.Wallets.Credit(ctx, walletID, monigo.CreditWalletParams{
      Amount:         "5000.00",
      Description:    "Manual top-up",
      IdempotencyKey: "topup_abc123",
  })
  // If balance is now ≥ invoice total, the subscription is auto-resumed.
  ```

  ```ts TypeScript theme={null}
  const entry = await client.wallets.credit(walletId, {
    amount: "5000.00",
    description: "Manual top-up",
    idempotency_key: "topup_abc123",
  });
  // If balance is now ≥ invoice total, the subscription is auto-resumed.
  ```
</CodeGroup>

***

## Webhook events

| Event                                       | When fired                                      |
| ------------------------------------------- | ----------------------------------------------- |
| `invoice.paid`                              | Wallet debit succeeded; invoice created as paid |
| `subscription.prepaid_balance_insufficient` | Balance too low; subscription paused            |
| `customer.wallet.topped_up`                 | Wallet was successfully credited                |

Register a webhook endpoint in the [Webhooks guide](/integrations/webhooks) to receive these events.

***

## Customer portal

When a customer views their subscriptions in the customer portal, prepaid subscriptions display:

* A **Prepaid** badge next to the subscription status
* Their **current wallet balance** alongside the estimated period total
* A warning and **Top up wallet →** link when the balance is below the estimated total

This gives customers full visibility into their balance before the next billing cycle runs.

***

## Comparing prepaid and postpaid

|                    | Postpaid (default)               | Prepaid                        |
| ------------------ | -------------------------------- | ------------------------------ |
| `billing_mode`     | `"postpaid"`                     | `"prepaid"`                    |
| Invoice created    | As `draft`, then finalized       | Directly as `paid`             |
| Payment collection | Via payment provider (card/bank) | Debited from wallet            |
| Failed payment     | Retry logic + dunning            | Subscription paused            |
| Recovery           | Automatic retries                | Customer tops up → auto-resume |
| Best for           | SaaS with card-on-file           | APIs with credit/token packs   |

***

## Related

* [Billing Cycle](/concepts/billing-cycle) — how periods work and when billing runs
* [Subscription Lifecycle](/guides/subscription-lifecycle) — pause, resume, and cancel behavior
* [Invoice Lifecycle](/guides/invoice-lifecycle) — invoice states and transitions
* [Webhooks](/integrations/webhooks) — receiving billing events
* [Customer Portal](/guides/customer-portal) — wallet balance visibility for customers
