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

# AI Prepaid Wallet

> Charge an AI agent's customers by usage — meter tokens as events, price them with a real-time plan, and debit a prepaid wallet continuously as the agent runs.

This guide shows how to bill an AI product the way customers expect: they **fund a prepaid wallet**, your agent **meters usage** (tokens, calls, seconds…) as events, and Monigo **debits the wallet in real time** as the usage accrues. When the balance runs out, metering pauses; when they top up, it resumes automatically.

It ties together three Monigo primitives:

| Primitive                  | Role in this flow                                                                                                                             |
| -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| **Events + Metrics**       | Your agent emits usage events; a metric turns them into a billable quantity (e.g. summed tokens). See [Metering](/guides/metering).           |
| **Real-time billing plan** | Prices the metered usage and debits the wallet continuously (\~5s) instead of at period end.                                                  |
| **Prepaid wallet**         | The customer's balance. Funded inline in your app via the [wallet widget](/guides/wallet-management); debited automatically as usage accrues. |

<Info>
  **The shape of the model:** customer funds wallet → agent runs → usage metered → wallet debited in near-real-time → balance hits zero → metering pauses → customer tops up → metering resumes. No invoices to chase, no surprise bills — the customer only spends what they've funded.
</Info>

## How it works

```mermaid theme={null}
flowchart TD
    A["Your agent<br>emits usage events"] -->|ingest| B["Monigo<br>events → metric · cumulative usage"]
    B --> C["Every ~5s: marginal = price of usage − charged so far"]
    C --> D[Debit the prepaid wallet for the marginal]
    D --> E{Balance empty?}

    E -->|No| B
    E -->|Yes| F[/Pause + prepaid_balance_insufficient webhook/]
    F --> G["WalletWidget in customer's app<br>live balance · Top up button"]
    G --> H[Customer funds the wallet]
    H -->|auto-resume on wallet credit| B

    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:#F3F4F6,color:#1F2937,stroke:#6B7280
    style F fill:#FEE2E2,color:#991B1B,stroke:#EF4444
    style G fill:#EFF6FF,color:#1E40AF,stroke:#3B82F6
    style H fill:#EFF6FF,color:#1E40AF,stroke:#3B82F6
```

Charging is **asynchronous and batched** (\~5s latency), so it never sits on your ingest hot path. The wallet's double-entry ledger is the system of record; at the end of each billing period Monigo emits one **paid summary invoice** for the customer's books (no extra debit — the money was already taken).

## Prerequisites

* A Monigo account and a **secret API key** (`mk_live_…`). All steps below run **server-side** — never expose the key in client code.
* The [`@monigo/sdk`](https://www.npmjs.com/package/@monigo/sdk) package (examples use TypeScript; the REST endpoints are shown alongside).

<Warning>
  **Two different customer identifiers — read this once.** When you create a customer you give it your own `external_id` and Monigo returns its `id` (a UUID).

  * **Events** reference the customer by **your `external_id`** (so you never have to look up a Monigo ID on your hot path).
  * **Management APIs** (wallet, subscription) reference the customer by **the Monigo `id` (UUID)**.

  The examples below are explicit about which one to use at each step.
</Warning>

## Step 1 — Create the customer

<CodeGroup>
  ```ts TypeScript theme={null}
  const customer = await client.customers.create({
    external_id: 'org_12345',          // YOUR id for this customer
    name: 'Acme Robotics',
    email: 'billing@acme.example',
  })
  // customer.id is the Monigo UUID; customer.external_id is "org_12345"
  ```

  ```bash cURL theme={null}
  curl -X POST https://api.monigo.co/v1/customers \
    -H "Authorization: Bearer mk_live_..." \
    -H "Content-Type: application/json" \
    -d '{ "external_id": "org_12345", "name": "Acme Robotics", "email": "billing@acme.example" }'
  ```
</CodeGroup>

## Step 2 — Define your usage metric

A **metric** turns raw events into a billable quantity. For token billing, sum a `tokens` property from your `agent_token_usage` events.

<CodeGroup>
  ```ts TypeScript theme={null}
  const metric = await client.metrics.create({
    name: 'AI Agent Tokens',
    event_name: 'agent_token_usage',   // events with this name feed this metric
    aggregation: 'sum',                // count | sum | max | minimum | average | unique
    aggregation_property: 'tokens',    // the event property to sum
    description: 'Total tokens consumed by the agent',
  })
  ```

  ```bash cURL theme={null}
  curl -X POST https://api.monigo.co/v1/metrics \
    -H "Authorization: Bearer mk_live_..." \
    -H "Content-Type: application/json" \
    -d '{
      "name": "AI Agent Tokens",
      "event_name": "agent_token_usage",
      "aggregation": "sum",
      "aggregation_property": "tokens"
    }'
  ```
</CodeGroup>

<Tip>
  Use `aggregation: "count"` (no `aggregation_property`) if you bill per-request instead of per-token. See [Pricing models](/guides/pricing-models) for tiered, package, and overage shapes — they all work with real-time billing.
</Tip>

## Step 3 — Create a real-time prepaid plan

Set `billing_mode: "realtime"` and attach a price for your metric. Here, ₦0.10 per token via a `per_unit` price.

<CodeGroup>
  ```ts TypeScript theme={null}
  const plan = await client.plans.create({
    name: 'AI Prepaid — ₦0.10 / token',
    currency: 'NGN',
    plan_type: 'collection',           // required for realtime
    billing_period: 'monthly',         // required for realtime
    billing_mode: 'realtime',
    prices: [
      { metric_id: metric.id, model: 'per_unit', unit_price: '0.100000' },
    ],
  })
  ```

  ```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": "AI Prepaid — token billing",
      "currency": "NGN",
      "plan_type": "collection",
      "billing_period": "monthly",
      "billing_mode": "realtime",
      "prices": [
        { "metric_id": "<metric_id>", "model": "per_unit", "unit_price": "0.100000" }
      ]
    }'
  ```
</CodeGroup>

<Warning>
  `billing_mode: "realtime"` requires **`plan_type: "collection"`** and **`billing_period: "monthly"`** (usage is aggregated per calendar month). Other combinations are rejected at plan creation. All pricing models (`per_unit`, `tiered`, `package`, `overage`, `cap`) are supported.
</Warning>

## Step 4 — Create the wallet and subscribe

The wallet holds the prepaid balance; the subscription connects the customer to the plan. Both use the Monigo **customer `id`** (not the external\_id).

<CodeGroup>
  ```ts TypeScript theme={null}
  const wallet = await client.wallets.getOrCreate({
    customer_id: customer.id,          // Monigo UUID
    currency: 'NGN',
  })

  const subscription = await client.subscriptions.create({
    customer_id: customer.id,          // Monigo UUID
    plan_id: plan.id,
  })
  ```

  ```bash cURL theme={null}
  curl -X POST https://api.monigo.co/v1/wallets \
    -H "Authorization: Bearer mk_live_..." \
    -d '{ "customer_id": "<customer_uuid>", "currency": "NGN" }'

  curl -X POST https://api.monigo.co/v1/subscriptions \
    -H "Authorization: Bearer mk_live_..." \
    -d '{ "customer_id": "<customer_uuid>", "plan_id": "<plan_id>" }'
  ```
</CodeGroup>

## Step 5 — Let the customer fund the wallet

Drop the prepaid wallet UI into your app. Mint a customer-scoped **portal token** on your server, then render `<WalletWidget>` — it shows the live balance, opens the provider's inline checkout on **Top up**, and refreshes automatically. Full details in [Wallet management](/guides/wallet-management) and [Embedding the portal](/guides/embedding-the-portal).

<CodeGroup>
  ```ts Server (mint token) theme={null}
  // Mint with the customer's external_id; pass only the raw token string to the client.
  const pt = await client.portalTokens.create({
    customer_external_id: 'org_12345',
    label: 'Agent wallet',
  })
  return { portalToken: pt.token, walletId: wallet.id }
  ```

  ```tsx Client (React) theme={null}
  import { MonigoProvider, WalletWidget } from '@monigo/react'
  import '@monigo/tokens/monigo.css'

  <MonigoProvider portalToken={portalToken}>
    <WalletWidget walletId={walletId} currency="NGN" presets={[1000, 5000, 10000]} />
  </MonigoProvider>
  ```

  ```svelte Client (Svelte) theme={null}
  <script>
    import { MonigoProvider, WalletWidget } from '@monigo/svelte'
    import '@monigo/tokens/monigo.css'
    let { portalToken, walletId } = $props()
  </script>

  <MonigoProvider {portalToken}>
    <WalletWidget {walletId} currency="NGN" presets={[1000, 5000, 10000]} />
  </MonigoProvider>
  ```
</CodeGroup>

`<WalletWidget>` is available for **React, Svelte, and Vue** (`@monigo/{react,svelte,vue}`). The provider webhook is the source of truth for crediting — **never credit the wallet from the browser**; Monigo credits it automatically when the payment provider confirms.

## Step 6 — Meter usage

As your agent runs, send a `agent_token_usage` event for each unit of work. Reference the customer by **your `external_id`**, put the token count in `properties`, and always include an **`idempotency_key`** so retries never double-charge.

<CodeGroup>
  ```ts TypeScript theme={null}
  const res = await client.events.ingest({
    events: [
      {
        event_name: 'agent_token_usage',
        customer_id: 'org_12345',                 // YOUR external_id (not the UUID)
        idempotency_key: 'run_2026_06_17_abc',    // stable per unit of work
        timestamp: new Date(),
        properties: { tokens: 15000, model: 'gpt-4' },
      },
    ],
  })
  // res.ingested: accepted keys; res.duplicates: keys already seen
  ```

  ```bash cURL theme={null}
  curl -X POST https://api.monigo.co/v1/ingest \
    -H "Authorization: Bearer mk_live_..." \
    -H "Content-Type: application/json" \
    -d '{
      "events": [{
        "event_name": "agent_token_usage",
        "customer_id": "org_12345",
        "idempotency_key": "run_2026_06_17_abc",
        "properties": { "tokens": 15000, "model": "gpt-4" }
      }]
    }'
  ```
</CodeGroup>

<Tip>
  Batch up to **1,000 events** per `ingest` call. The `idempotency_key` should be a stable id from your own system (a run id, request id, etc.) so re-sending the same event is a no-op — critical when money moves automatically. See [Idempotency](/guides/idempotency).
</Tip>

That's the whole integration. Everything below happens **automatically**.

## What happens automatically

Within a few seconds of each event, Monigo:

1. **Reconciles and debits.** It recomputes the period's cumulative cost from the metric and debits the wallet for the *marginal* increase since the last charge — so the running cost is always exactly `price(total usage so far)`. Typical latency is **\~5 seconds**.
2. **Updates the live balance.** The `<WalletWidget>` poll picks up the new (lower) balance, so the customer watches their balance draw down as the agent works.
3. **Pauses on empty.** When the wallet can't cover the next charge, the subscription is **paused**, further events for that customer are dropped, and a `subscription.prepaid_balance_insufficient` webhook fires.
4. **Resumes on top-up.** When the customer funds the wallet, the subscription **reactivates**, the accrued (unpaid) usage is charged from the new balance, and metering continues.
5. **Closes the period.** At month end, Monigo emits **one paid summary invoice** (per-metric line items, total = what was actually debited) for the customer's records — with **no additional debit**.

## Step 7 — Handle the webhooks

Register an endpoint (Dashboard → Webhooks) and react to these events. See [Webhooks](/integrations/webhooks) for signature verification.

| Event                                       | When                                                          | What to do                                                                     |
| ------------------------------------------- | ------------------------------------------------------------- | ------------------------------------------------------------------------------ |
| `subscription.prepaid_balance_insufficient` | Wallet can't cover the next charge; subscription paused       | Notify the customer to top up; surface the wallet widget / a "fund wallet" CTA |
| `customer.wallet.topped_up`                 | Wallet credited (the customer funded it)                      | Optionally confirm in-app; the subscription auto-resumes — no action required  |
| `invoice.paid`                              | Monthly summary invoice issued (already paid from the wallet) | Store/forward for the customer's billing records                               |

```json subscription.prepaid_balance_insufficient theme={null}
{
  "subscription_id": "sub_...",
  "customer_id": "cus_...",
  "amount_due": "120.000000",
  "currency": "NGN",
  "reason": "insufficient_balance"
}
```

## How real-time charging works

For the curious — and for reasoning about edge cases:

* **Marginal reconcile, not per-event pricing.** Each cycle charges `price(cumulative usage) − already_charged`. This keeps tiered/package/overage pricing exact across a period and makes `cap` charge its flat fee exactly once.
* **Crash-safe and idempotent.** Each debit carries a deterministic idempotency key, so a retry after a failure can never double-charge.
* **Bounded free usage.** Because charging trails ingestion by a few seconds, a tiny amount of usage can be metered in the window between the balance hitting zero and the pause taking effect. This is bounded to roughly the charge interval.
* **Wallet is the source of truth.** Real-time debits are ordinary `usage` ledger entries; the monthly invoice merely records the total. There is never a second debit at period end.

## A working example

A minimal SvelteKit app — mint a portal token, render `<WalletWidget>`, and simulate agent spend — lives at [`platform/samples/ai-agent-wallet`](https://github.com/monigo-africa/platform/tree/main/samples/ai-agent-wallet).

## Next steps

<CardGroup cols={2}>
  <Card title="Wallet management" href="/guides/wallet-management">
    Wallet operations, virtual accounts, and the `<WalletWidget>` in depth.
  </Card>

  <Card title="Metering" href="/guides/metering">
    Event ingestion patterns, batching, and idempotency.
  </Card>

  <Card title="Pricing models" href="/guides/pricing-models">
    Tiered, package, overage, and cap pricing — all work with real-time billing.
  </Card>

  <Card title="Embedding the portal" href="/guides/embedding-the-portal">
    Drop-in components for React, Svelte, and Vue.
  </Card>
</CardGroup>
