# API Keys and Authentication

## Supafone authentication and S2S model credentials

Your Supafone API key authenticates your app to Agent Factory. It is different
from the server-side OpenAI, Google, xAI, or Smallest AI key used by the selected speaking
model. Supafone uses its configured platform key unless the account has an
encrypted BYOK override for that provider. Customers need no separate vendor
key when managed credentials are available.

Use `GET /api/v1/labs/runtime?provider=openai` (or `google`, `xai`, `smallest`) to inspect
credential source and readiness without exposing the secret. Model access and
carrier routing still need live verification. See [Native S2S credentials](realtime-agent-factory.md#managed-credentials-and-optional-byok).

**One key does everything.** A single `sl_live_...` Labs key authenticates Labs
Cloud, the whole Supafone product API, the MCP server, and both SDKs — as long
as an app.supafone.ai account exists with the **same email** that owns the key.
Set `export SUPAFONE_TOKEN=sl_live_...` and you are done; there is no second key
to provision. Legacy scoped `sf_live_...` keys still work for hosted-agent-only
use, but they are the exception, not the default.

One key covers both surfaces:

| Key | Base URL | Used for |
| --- | --- | --- |
| `sl_live_...` | `https://api.labs.supafone.ai` **and** `https://api.supafone.ai` | Everything: Labs Cloud oracle, TTS, STT, logs, usage, builder, QA, optimizer — plus the whole product API (campaigns, calls, agents) via one-key auth |
| `sf_live_...` (legacy) | `https://api.supafone.ai/api/v1/labs` | Optional scoped key for hosted-agent-only use — the `sl_` key already covers this surface |

## One Key, Both APIs

An `sl_` key is no longer labs-only. The Supafone product API
(`https://api.supafone.ai`) accepts it as a bearer credential anywhere an
account JWT works: on first use it introspects the key against
`GET https://api.labs.supafone.ai/v1/keys/introspect`, maps the key's owner
email to your app.supafone.ai account, and caches the validated key
in-process for ~5 minutes. Anything doubtful — unknown key, deactivated key,
labs outage — fails closed as a 401, never a fallback.

```bash
export SUPAFONE_TOKEN=sl_live_...   # ONE env var: MCP + both SDKs, end to end

curl https://api.supafone.ai/api/v1/campaigns \
  -H "Authorization: Bearer $SUPAFONE_TOKEN"
```

Requirements:

- An app.supafone.ai account must exist with the **same email** that owns the
  key — otherwise the API answers 401 with "create an app.supafone.ai account
  with the same email".
- The key must be active in the labs console.

Account login (email/password or JWT) keeps working exactly as before — the
`sl_` path is additive.

## Labs Cloud Auth

Create a trial key:

```bash
curl -X POST https://api.labs.supafone.ai/v1/signup \
  -H "Content-Type: application/json" \
  -d '{"email":"you@example.com"}'
```

Use it as a bearer token:

```bash
curl https://api.labs.supafone.ai/v1/usage \
  -H "Authorization: Bearer $SUPAFONE_LABS_API_KEY"
```

The TypeScript SDK uses this key as `apiKey` for Labs Cloud methods:

```ts
const supafone = new Supafone({
  apiKey: process.env.SUPAFONE_LABS_API_KEY!,
});
```

## Legacy Scoped Hosted-Agent Keys

Your one `sl_` key already authenticates the hosted-agent API via one-key auth,
so most integrations never need a second key:

```bash
curl https://api.supafone.ai/api/v1/labs/capabilities \
  -H "Authorization: Bearer $SUPAFONE_LABS_API_KEY"
```

For hosted-agent-only deployments you can still mint a scoped `sf_live_...` key
from the Supafone account-admin flow. It is the exception, not the default.

The hosted-agent API also accepts `x-supafone-key` and `x-supafone-api-key`, but
bearer auth is the recommended default.

The recommended TypeScript setup for every public surface is one token:

```ts
const supafone = new Supafone({
  apiKey: process.env.SUPAFONE_TOKEN!,
});
```

Separate per-surface credentials remain an advanced compatibility option for
teams that deliberately want scoped keys:

```ts
const supafone = new Supafone({
  apiKey: process.env.SUPAFONE_LABS_API_KEY!,
  supafoneApiKey: process.env.SUPAFONE_API_KEY!,
});
```

## Creating Hosted-Agent Keys

Hosted-agent key management is an account-admin operation on the Supafone app
API. It uses the normal app user session or JWT, not the hosted-agent key being
created.

```http
POST   /api/v1/labs/api-keys
GET    /api/v1/labs/api-keys?agency_id=...
DELETE /api/v1/labs/api-keys/{key_id}?agency_id=...
```

Create body:

```json
{
  "agency_id": "00000000-0000-0000-0000-000000000000",
  "name": "Production key",
  "scopes": [
    "agents:write",
    "agents:read",
    "voices:read",
    "calls:write",
    "numbers:read",
    "numbers:write",
    "telephony:read",
    "telephony:write"
  ]
}
```

The raw `sf_live_...` value is returned once. List and revoke responses should
only expose prefixes or metadata.

## Console Sessions

Labs Cloud also supports account sessions for console-scoped features:

```http
POST /v1/auth/register
POST /v1/auth/login
POST /v1/auth/key-login
GET  /v1/account
POST /v1/account/keys
PATCH /v1/account/keys/{key}
```

Builder and QA methods require a session token. Most read and usage endpoints
accept either a session token or an `sl_live_...` key.

## Key Hygiene

- Never commit `sl_live_...`, `sf_live_...`, provider keys, Twilio credentials,
  Stripe secrets, or admin secrets.
- Use environment variables in examples, tests, and deploys.
- Show only masked keys in dashboards and logs.
- Rotate keys when they leave the intended environment.
