---
title: "Authentication"
description: "ZeroVoice authentication — API keys, JWT tokens, and webhook verification"
canonical: "https://docs.ainative.studio/docs/zerovoice/authentication"
last-updated: "2026-11-02T18:12:43.468Z"
---

# Authentication

Source: https://docs.ainative.studio/docs/zerovoice/authentication

> ZeroVoice authentication — API keys, JWT tokens, and webhook verification

# Authentication

ZeroVoice supports two authentication methods: **JWT bearer tokens** and **API keys**.

## JWT Bearer Tokens

### Login

```bash
POST /auth/login
Content-Type: application/json

{
  "email": "user@company.com",
  "password": "your-password"
}
```

Response:
```json
{
  "access_token": "eyJ...",
  "refresh_token": "rft_...",
  "token_type": "bearer",
  "expires_in": 900
}
```

### Using the token

```bash
curl -H "Authorization: Bearer eyJ..." \
  https://your-instance/api/v1/calls/live
```

### Token details

| Property | Value |
|---|---|
| Algorithm | HS256 (local) or RS256 (external ZeroApp) |
| TTL | 15 minutes (hard limit) |
| Issuer | `https://auth.zeroapp.dev` |
| Audience | `zerovoice` |

### Refreshing tokens

```bash
POST /auth/refresh
Content-Type: application/json

{
  "refresh_token": "rft_..."
}
```

Refresh tokens use one-time rotation: each use invalidates the previous token and returns a new pair. Replaying a used refresh token revokes the entire token family (theft detection).

## API Keys

For service-to-service or agent integrations, use API keys instead of JWT tokens.

### Creating an API key

```bash
POST /api/v1/api-keys
Authorization: Bearer <admin-token>
Content-Type: application/json

{
  "name": "MCP Bridge",
  "expires_in_days": 90
}
```

### Using API keys

```bash
curl -H "X-API-Key: zvk_..." \
  https://your-instance/api/v1/contacts
```

### Key management

- Keys can be listed, revoked, and auto-expire
- Revoked keys are purged nightly
- Keys inherit the creating user's org scope

## Rate Limits

| Scope | Limit |
|---|---|
| General API | 200 requests/min per tenant |
| Auth endpoints | 10 requests/min per IP |
| Webhook endpoints | 30 requests/min per tenant |

Rate limit headers are returned on every response:
```
X-RateLimit-Limit: 200
X-RateLimit-Remaining: 195
X-RateLimit-Reset: 1719006000
Retry-After: 12
```

## Multi-tenant isolation

Every authenticated request is scoped to the user's `org_id`. Tenant isolation is enforced at the query level — there is no way to access another organization's data through the API.
