Per-surface pricing
INR paise per second
| Field | Type | Notes |
|---|---|---|
textvoice | 4 paise / sec | Derived from the same env-tunable per-minute sell rate the PAYG voice path uses; ceiling-rounded to the second. |
voicebot | 4 paise / sec | Identical engine to text-voice; metered separately for embed-snippet attribution. |
meeting-agent | 8 paise / sec | LiveKit room + Vikash AI participant + GPU LLM. |
meeting | 1 paise / sec | Bare LiveKit room. No AI, no transcription. |
Prices above are the launch defaults. Voice-surface rates track the same env-driven cost model as the rest of the platform — if we tune the input costs, your per-second price tracks; we'll announce changes 30 days in advance.
Reservation + reconciliation
When a session opens we reserve a 100 paise floor against your wallet and write a row to api_usage. When the session closes we reconcile the row to the actual duration × per-second rate. Voice surfaces round up to whole billable minutes (matching the PAYG ledger semantics); meeting surfaces settle at single-paise resolution.
# Pull a 30-day rollup for a single key (dashboard scope).
curl https://www.vaanilabs.in/api/api-keys/<KEY_ID>/usage?range=30d \
-H "Cookie: <your dashboard session>"// Voice surfaces (textvoice + voicebot) round to billable
// MINUTES under the hood — same wallet ledger as PAYG calls.
//
// bill_paise = ceil(seconds / 60) * sell_rate_per_minute
//
// Meeting surfaces are charged per SECOND with a 1-paise floor.
//
// bill_paise = max(1, seconds * price_per_second)# At session-open time we reserve 100 paise as a floor against
# your wallet. The session close-out path reconciles the actual
# duration once the WebSocket / room ends.
RESERVATION_FLOOR_PAISE = 100Out of money
We refuse to start a session if your wallet is at zero AND you do not have an active autopay mandate. The refusal is a clean 402 insufficient_balance with a setup_url hint. In-flight sessions are NOT killed mid-stream — only new sessions are blocked.
Usage rollup endpoint
GET/api/api-keys/[id]/usage
Owner-scoped, dashboard-session authenticated (NOT a public-API route). Accepts a range query param like 30d (1–365 days, default 30). Returns totals + a per-surface breakdown + the most recent 1000 raw rows.
Response shape
| Field | Type | Notes |
|---|---|---|
key | { id, name, key_prefix } | Identifying metadata for the key being queried. |
range_days | integer | The window applied (clamped to 1–365). |
totals | { sessions, units, cost_paise } | Aggregate over the window. |
by_surface | { [surface]: { sessions, units, cost_paise } } | Per-surface split for the same window. |
recent | ApiUsageRow[] | Up to 1000 most recent raw rows, newest first. |