Skip to content

Multi-Tenancy

The Voki platform uses a multi-tenant architecture with complete data isolation per tenant. This guide explains how the tenant system works and how to interact with the API correctly.

Concept

Each company (Voki customer) is an independent tenant. Isolation is guaranteed by:

  • Separate PostgreSQL schema per tenant
  • JWT with tenant claim for authentication
  • X-Tenant header on all authenticated requests

Tenant Identification

Each tenant has a unique slug that identifies it. The slug is defined when the tenant is created and cannot be changed.

Examples of slugs: avanter, clinica-abc, empresa-xyz

How It Works

1. Login

During login, the tenant is specified in the request body:

bash
curl -X POST https://voki.avanter.com.br/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@company.com",
    "password": "password123",
    "tenant": "avanter"
  }'

The returned JWT token contains the tenant in its claims:

json
{
  "sub": "user_uuid",
  "tenant": "avanter",
  "role": "manager",
  "exp": 1708387200
}

2. Authenticated Requests

After login, all requests must include:

  • Authorization: Bearer {token} - JWT token
  • X-Tenant: {slug} - Tenant slug
bash
curl -X GET https://voki.avanter.com.br/api/v1/users \
  -H "Authorization: Bearer eyJhbGci..." \
  -H "X-Tenant: avanter"

Important

The X-Tenant header must match the tenant in the JWT token. If there is a mismatch, the request will be rejected with 401 Unauthorized.

3. Data Isolation

Each request operates exclusively on the authenticated tenant's data:

  • A user from the avanter tenant never accesses data from the clinica-abc tenant
  • All SQL queries are executed within the tenant's schema
  • IDs are unique within each tenant but may repeat across tenants

Technical Architecture

┌─────────────────────────────────────────────────┐
│                  PostgreSQL 16                    │
│                                                   │
│  ┌─────────────┐  ┌─────────────┐  ┌──────────┐ │
│  │   public     │  │   avanter   │  │ clinica  │ │
│  │  (shared)    │  │  (tenant)   │  │ (tenant) │ │
│  │             │  │             │  │          │ │
│  │ - companies │  │ - users     │  │ - users  │ │
│  │ - plans     │  │ - calls     │  │ - calls  │ │
│  │             │  │ - customers │  │ - ...    │ │
│  └─────────────┘  └─────────────┘  └──────────┘ │
└─────────────────────────────────────────────────┘
  • public schema: Shared data (companies, plans, global settings)
  • Per-tenant schema: Isolated data (users, calls, customers, recordings, etc.)

Creating a New Tenant

New tenants are created via the signup flow:

bash
# 1. Validate document
curl -X POST https://voki.avanter.com.br/api/signup/validate-document \
  -H "Content-Type: application/json" \
  -d '{"document": "12.345.678/0001-90", "document_type": "cnpj"}'

# 2. Register
curl -X POST https://voki.avanter.com.br/api/signup/register \
  -H "Content-Type: application/json" \
  -d '{
    "company_name": "New Company",
    "document": "12.345.678/0001-90",
    "document_type": "cnpj",
    "admin_name": "Administrator",
    "admin_email": "admin@newcompany.com",
    "admin_password": "securePassword123",
    "plan": "professional"
  }'

# 3. Checkout (Asaas)
curl -X POST https://voki.avanter.com.br/api/signup/checkout \
  -H "Content-Type: application/json" \
  -d '{
    "tenant": "new-company",
    "plan": "professional",
    "success_url": "https://...",
    "cancel_url": "https://..."
  }'

Best Practices

  1. Store the tenant slug along with the token in your client
  2. Always include the X-Tenant header - even though the token already contains the tenant
  3. Don't hardcode slugs - obtain them from login or configuration
  4. Handle 401 errors - they may indicate an expired token OR an invalid tenant
  5. Renew tokens before expiration using the refresh token

Plan Limits

Each tenant has limits based on their subscribed plan:

ResourceStarterProfessionalEnterprise
Concurrent calls210Unlimited
Users550Unlimited
Departments320Unlimited
RecordingYesYesYes
AI TranscriptionNoYesYes
Advanced AnalyticsNoYesYes

Check the current plan via GET /api/v1/billing/plan.

Documentação da API Voki v4.0