v0.4.0
mahimailabs/voicegatewayv0.4.0May 12, 2026by mahimairaja
AI Summary
Adds multi-tenant cost attribution, allowing a single deployment to serve multiple customers via tenant IDs, virtual API keys, and scoped dashboard views.
Key Highlights
- Multi-tenant support with `tenant_id` tagging for sessions.
- Virtual API key management (generation, verification, soft-revoke).
- Dashboard filtering and new `/api/tenants` endpoints.
New Features
- Multi-tenant cost attribution
- Virtual API key management system
Full Release Notes
**v0.4.0 — Multi-tenant cost attribution**
VoiceGateway now tags every voice session with an optional `tenant_id` so a single deployment can serve many customers and account for each one separately. Three independent surfaces set the tenant: an `attach_session(tenant_id=...)` kwarg, an `inference.set_tenant("…")` ContextVar API, and scoped virtual API keys that auto-attribute at the auth layer. Every cost row, metric row, and replay event for an attributed session lands tagged; pre-v0.4.0 rows stay in the "unattributed" bucket (NULL `tenant_id`).
**Highlights**
- **REQ-VG-TENANT-001** (tag sessions with a tenant dimension): `tenant_id_ctx` ContextVar + `attach_session` kwarg + `log_request` UPSERT with `COALESCE` so the first tenant-bearing request stamps the session for its lifetime. Every cost / metric / replay row tagged via T08's repo-level propagation.
- **REQ-VG-TENANT-002** (slice the dashboard by tenant): new `/api/tenants` + `/api/tenants/{id}` endpoints; existing `/api/costs`, `/api/sessions`, `/api/metrics`, `/api/logs`, `/api/latency` accept a `tenant` query param. New `FilterBar` + `TenantFilter` (200ms-debounced typeahead) + `TenantPill` components with URL persistence. Costs / Sessions / Metrics pages and the SessionDetail modal all rescope when a tenant is selected.
- **REQ-VG-TENANT-003** (issue virtual API keys): new `virtual_keys` table (bcrypt-hashed at cost 12, 8-char visible prefix indexed) + `virtual_keys_repo` (issue / verify / soft-revoke / list / mark-used / list-stale) + `VirtualKeys.tsx` dashboard page with the show-key-once modal. `voicegw tenant list / show <id>` CLI is read-only by design.
- **REQ-VG-TENANT-004** (auto-attribute calls with virtual key): auth middleware in `voicegateway/server/main.py::build_app` detects `vk_`-prefixed bearer tokens, resolves them, sets `tenant_id_ctx` if scoped, returns 403 on body-tenant + key-scope conflict.
**Migration notes**
None breaking. Migration 0005 is idempotent and adds `tenant_id` nullable across `sessions`, `requests`, and (conditionally on prior migrations having run) `turns`, `dead_air_events`, and the four `replay_*` tables. Pre-v0.4.0 rows stay `tenant_id = NULL` and the FE renders them as a muted "unattributed" pill — no backfill happens. The new `bcrypt>=4.0` dependency lands automatically with `pip install -e ".[dev]"` or any cloud-extra reinstall.
Five Foundry Open Questions locked in this release: vk_+32 base32 key shape (OQ1), 128-char UTF-8 tenant cap (OQ2), no backfill (OQ3), `sqlite_master` ALTER guard (OQ4), soft revoke (OQ5).
Out of scope this release: no automatic backfill of pre-v0.4.0 sessions, no CLI key issuance, no `voicegw costs --tenant` flag, no re-tag affordance for already-attributed sessions, no RBAC scopes on virtual keys. The multi-tenant quickstart guide enumerates these explicitly.
**Refinery and Foundry**
- Refinery: https://linear.app/mahimailabs/document/voicegateway-v0-4-0-multi-tenant-cost-attribution
- Foundry: https://linear.app/mahimailabs/issue/MAH-VG-040