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

# Billing & tiers

> What a minute costs, how minutes are counted, what each tier can do, and what happens at zero balance.

One number to remember: **₹3 per minute**. That is the `t3` conversational
tier, it is what a new key is issued at, and it is what every example in these
docs uses unless it says otherwise.

| Tier                  | Rate            | Status                   |
| :-------------------- | :-------------- | :----------------------- |
| `t1` — transactional  | ₹1 / minute     | ✅ Live                   |
| `t3` — conversational | **₹3 / minute** | ✅ Live — **the default** |
| `t5` — orchestrated   | ₹5 / minute     | 🔜 Not live              |

`t5` is published so you can plan against it. Requesting it today returns
`501 tier_unavailable` — see [when it arrives](#coming-soon).

**Why `t3` is the default.** It is the always-on path: it speaks through a
premium third-party voice catalogue with no dependency on our own GPU fleet, so
it is the tier that is up whenever the API is up. `t1` runs on the Mira stack at
a third of the price and a smaller voice catalogue — a deliberate trade, and the
right one for high-volume transactional work. Ask for it explicitly:

```json theme={null}
{ "tier": "t1" }
```

## Feature matrix

What the tier buys is not a discount, it is **what the call can do**.

| Capability                                              |  `t1` ₹1 |     `t3` ₹3    |     `t5` ₹5    |
| :------------------------------------------------------ | :------: | :------------: | :------------: |
| Core call (ASR → LLM → TTS, Mira stack)                 |     ✅    |        ✅       |        ✅       |
| Voicemail detection                                     |  ✅ basic |    ✅ proper    |        ✅       |
| Clean call ending                                       |     ✅    |        ✅       |        ✅       |
| Post-call analytics (AI summary + QA score, every call) |     ✅    |        ✅       |        ✅       |
| Human handoff (warm transfer)                           |     ✅    |        ✅       |        ✅       |
| Premium TTS voice option + fallback                     |     ❌    |        ✅       |        ✅       |
| Node-graph runtime                                      |     ❌    |  ✅ (our graph) | ✅ (your graph) |
| IVR detect + navigate                                   |     ❌    |        ✅       |        ✅       |
| Customer-authored node graph                            |     ❌    |        ❌       |        ✅       |
| Priority capacity                                       | standard | reserved floor | reserved floor |

**Every call is opened.** On every tier, each completed call gets an AI summary
and a QA score — 100% of calls, not a sample. Warm transfer to a human is part
of the same lattice: any tier can hand a caller to a person. See the
[roadmap](/general/roadmap) for rollout status of both on `t1`.

**Read the ❌ as a contract.** A ❌ is not "degraded", it is "absent". On `t1`
there is no node-graph runtime and no IVR navigation — the call is one prompt,
start to finish. That simplicity is what makes ₹1 possible.

### Picking a tier

* **`t3` (default)** — start here. Premium voices, no dependency on our GPU
  fleet, and the tier every example in these docs is written against. If you are
  not sure, you want this.
* **`t1`** — one job, under two minutes, no branching, at volume. Order
  confirmations, delivery windows, appointment reminders, OTP-adjacent
  notifications, "are you still interested?". If you can write the whole call as
  one prompt, it ends when the customer says yes or no, and the volume makes ₹2
  a minute worth optimising for, drop to `t1`. Its voice catalogue is two
  voices — `ashu` and `aishe`, see [Voices](/v2/voices).
* **`t5`** — you want to author the flow yourself, node by node, and version it
  like code. Not live.

## What a minute costs

Billing is **per-minute blocks, rounded up, with a one-minute minimum.** The
minute is the billing unit, not just the price: a call is not prorated to the
second, and a part-minute is a whole minute.

| Call duration | Billed minutes | `t3` cost | `t1` cost |
| :------------ | :------------- | :-------- | :-------- |
| 8 seconds     | 1              | ₹3.00     | ₹1.00     |
| 59 seconds    | 1              | ₹3.00     | ₹1.00     |
| 61 seconds    | 2              | ₹6.00     | ₹2.00     |
| 96 seconds    | 2              | ₹6.00     | ₹2.00     |
| 3 min 01 s    | 4              | ₹12.00    | ₹4.00     |

### Metering

`duration_secs` on the [call object](/v2/calls#the-call-object) is the true
media duration in seconds. The charge is that duration rounded **up** to the
next whole minute, never fewer than one, times the tier rate. A call that
never connected is not billed at all — see the table below.

```python theme={null}
import math

def cost_inr(duration_secs: int, per_min_inr: float) -> float:
    minutes = max(1, math.ceil(duration_secs / 60))
    return minutes * per_min_inr
```

You never have to compute this — `cost_inr` on the call object and the
debit row in the [ledger](/v2/wallet#list-transactions) are authoritative. Use
the formula to forecast, not to reconcile.

### What is and is not billable

| Outcome                                       | `status`    | Billed |
| :-------------------------------------------- | :---------- | :----: |
| Conversation completed                        | `completed` |    ✅   |
| Answering machine, message left or hung up on | `voicemail` |    ✅   |
| Hit the duration cap                          | `timeout`   |    ✅   |
| Rang out                                      | `no_answer` |    ❌   |
| Line busy                                     | `busy`      |    ❌   |
| Could not connect, or our pipeline errored    | `failed`    |    ❌   |
| You cancelled before it connected             | `aborted`   |    ❌   |

The rule underneath: **if media went live, you pay for it.** A voicemail
consumed a real dial, real TTS and real minutes of carrier time, so it is
billed. A call our own pipeline broke is not.

### Forecasting a month

Take your answer rate and your mean answered-call duration:

Round each answered call up to a whole minute first, then multiply. Averaging
the seconds and dividing by 60 will under-forecast, because the rounding
happens per call and never cancels out.

```text theme={null}
monthly ₹ = answered_calls × mean(ceil(secs / 60)) × rate
```

A campaign of 50,000 dials at a 35% answer rate and 80 seconds mean talk time,
on `t3`:

```text theme={null}
50,000 × 0.35 = 17,500 answered
80 seconds -> 2 billed minutes each
17,500 × 2 × ₹3 = ₹105,000        (the same list on t1: ₹35,000)
```

Unanswered dials cost nothing, so the 32,500 that rang out are free.

Because the boundary is the minute, **the lever is which side of a boundary
your calls land on.** Trimming an 80-second call to 55 seconds halves its cost;
trimming it to 70 saves nothing. Look at the distribution of `duration_secs`,
not the mean — a cluster sitting just past 60 or just past 120 is the cheapest
thing you will ever fix, and a prompt that caps reply length is usually what
moves it.

## Wallet

Billing is prepaid against one INR wallet per workspace.

```bash theme={null}
curl https://sandbox.voice.miraiminds.co/v2/wallet \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY"
```

```json theme={null}
{ "balance_inr": 500, "currency": "INR", "updated_at": "2026-07-26T09:12:44Z" }
```

* **Debits happen at call end**, one ledger row per billable call, carrying the
  `call_id`.
* **Top-ups are not self-serve yet** — see the
  [roadmap](/general/roadmap). Your Mirai contact credits the workspace; it
  lands within minutes and applies immediately.
* **The ledger is the source of truth** for reconciliation:
  [`GET /v2/wallet/transactions`](/v2/wallet#list-transactions).

See the [Wallet reference](/v2/wallet) for the full API.

## At zero balance

**Before dialling**, we check the wallet can cover at least one minute at the
call's tier. If it cannot:

```json title="402 Payment Required" theme={null}
{
  "error": {
    "code": "insufficient_balance",
    "message": "wallet balance 0.40 INR is below the minimum for one minute at t3"
  }
}
```

* No phone rings. No charge. No call object is created.

* The `Idempotency-Key` is **not** consumed — retry with the same key after
  topping up.

* **Calls already in flight are not killed.** A call that started with credit
  runs to its natural end and then debits. Your balance can therefore dip below
  what the pre-dial check implied during a busy minute.

* **Inside a [campaign](/v2/campaigns) this is not an error.** The campaign
  pauses itself with `pause_reason: "insufficient_balance"`, keeps every
  contact's place, and continues from there once you top up and start it again.

Alert on balance yourself, hourly, at a threshold covering a day of traffic. A
`402` mid-campaign is an expensive way to find out.

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    wallet = httpx.get(f"{API}/v2/wallet", headers=auth).raise_for_status().json()
    if wallet["balance_inr"] < DAILY_BURN_INR:
        alert_ops(f"mirai wallet at ₹{wallet['balance_inr']}")
    ```
  </Tab>

  <Tab title="Node.js">
    ```javascript theme={null}
    const wallet = await fetch(`${API}/v2/wallet`, { headers: auth }).then((r) => r.json());
    if (wallet.balance_inr < DAILY_BURN_INR) {
      await alertOps(`mirai wallet at ₹${wallet.balance_inr}`);
    }
    ```
  </Tab>
</Tabs>

## Setting the tier

Your key carries a default tier — `t3` unless you asked for something else.
Every call and every campaign inherits it unless you override:

```json theme={null}
{
  "agent_id": "agt_01K7Q9F3K7M2N5P9R4T6V8W0XZ",
  "to": "+919876543210",
  "tier": "t1"
}
```

Override downward per call when a particular job is simple enough for `t1`.
There is no way to set a tier per *agent*: the same agent can be run at either
rate.

The call object reports the `tier` it ran at alongside `cost_inr`, so you can
always see which rate card a given call was billed under. A
[campaign](/v2/campaigns) sets its tier once, at create time, and every call it
places inherits it.

## Coming soon

`t3` [went live in August 2026](/general/roadmap) and is now the default.
`t5` is in the contract but not in production. Today:

```json title="501 Not Implemented" theme={null}
{
  "error": {
    "code": "tier_unavailable",
    "message": "Tier t5 is not available on this deployment yet."
  }
}
```

Design against it if you like — the field name and the values will not change —
but do not ship a code path that depends on it until we tell you it is live.
Current target: **`t5` with node graphs in Q4 2026**. See the
[roadmap](/general/roadmap), and ask your account contact to confirm before you
plan a launch around it.
