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

# SDK Authentication

> Publishable keys for the browser, secret keys for your server

The Voice SDK starts a call by creating a session with the [Voice Sessions API](https://docs.telzino.com/api-reference/voice-sessions.md). There are two ways to authenticate that request.

[Chat](https://docs.telzino.com/sdk/chat.md) uses the publishable key only. [Texts and outbound calls](https://docs.telzino.com/sdk/server.md) use a secret key from your server.

| | Publishable key | Secret key |
| - | - | - |
| Where it runs | The visitor's browser | Your server |
| Credential | `pk_live_...` | An access token from [OAuth client credentials](https://docs.telzino.com/api-reference/authentication.md) |
| Safe to expose | Yes, only works from allowed origins | No, keep it on your server |
| `end_user` | Ignored | Passed to the agent |
| Max `ttl_seconds` | 900 | 3600 |
| Limits | Burst limits and a daily cap | None |

## Publishable keys

Use a publishable key when the page itself starts the call.

```ts theme={null}
import { TelzinoVoice } from '@telzino/voice';

const voice = new TelzinoVoice({ publishableKey: 'pk_live_...' });
```

### Creating a key

In the dashboard, open the **API Keys** page and use **Publishable keys**. Each key has:

* **Key name**: a label for you, for example `Marketing site`.
* **Allowed origins**: the exact origins that may use the key, one per line.
* **Allowed agent ids** (optional): comma-separated agent UUIDs. Leave it empty to allow every agent the key can reach.
* **Access**: which organization or reseller the key can reach.

The full key is shown once, when you create it. Copy it then. Telzino stores only a hash, and the list afterward shows just the key prefix.

> [!NOTE]
>
> Creating a publishable key requires a partner account user with the `create:api_keys` permission (a Telzino Admin). Reseller admins can view and revoke the keys issued for their reseller, but cannot create them.

### Allowed origins

Origins are compared exactly: scheme, host and port. `https://example.com` does not allow `https://www.example.com` or `http://example.com`. A wildcard `*` is refused, and every key needs at least one origin. Add `http://localhost:5173` (or your dev port) while developing.

If a page runs on an origin that is not listed, the browser blocks the request. In the SDK, `start()` rejects with `origin_not_allowed`, or with `network` if the browser blocked the response entirely.

### Revoking a key

Revoke a key from the same list. Revocation takes effect immediately: the next session request with that key fails with `invalid_key`.

### Limits

Publishable keys are rate limited, because the key is public:

* 60 session requests per minute per key.
* 10 session requests per minute per key and client IP.
* A daily session cap per key, 2,000 sessions by default, counted from 00:00 UTC.

Over a limit, the API answers `429 rate_limited` and the SDK rejects with `rate_limited`, which is recoverable. If Telzino cannot verify the daily count, it fails closed and also answers `rate_limited`.

## Secret keys

When you want to identify the caller, or never expose any key to the browser, mint the session on your server. Authenticate with an access token from the [OAuth client credentials flow](https://docs.telzino.com/api-reference/authentication.md) and call the same endpoint:

```bash theme={null}
curl -X POST https://api.telzino.com/v1/voice/sessions \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "3f1c2a4e-8b7d-4c3a-9e2f-1a2b3c4d5e6f",
    "end_user": { "id": "user_8231", "name": "Ada", "email": "ada@example.com" },
    "metadata": { "plan": "pro" }
  }'
```

The response is the same JSON the browser needs. Return it unchanged from your own endpoint and give the browser a `session` provider instead of a key:

```ts theme={null}
import { TelzinoVoice } from '@telzino/voice';
import type { SessionRequest, SessionResponse } from '@telzino/voice';

const voice = new TelzinoVoice({
  session: async (req: SessionRequest): Promise<SessionResponse> => {
    const res = await fetch('/api/telzino-session', {
      method: 'POST',
      headers: { 'content-type': 'application/json' },
      body: JSON.stringify(req),
    });
    return res.json();
  },
});
```

> [!WARNING]
>
> Your endpoint decides what the browser may ask for. Check that the user is signed in and that the `agentId` is one you intend them to call before you mint a session. Do not forward the request body to Telzino blindly.

Metadata is background data about the caller. See [Security](https://docs.telzino.com/sdk/security.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.