<!-- AvatarFactory Docs · https://avatarfactory.in/docs/platform/api-keys · Full map: https://avatarfactory.in/llms.txt -->

# API keys

One permanent test key, as many live keys as you have apps, and public deployment IDs for embeds. Which credential goes where, and why.

AvatarFactory issues three kinds of credential. They are not interchangeable,
and the differences are enforced on our servers rather than left to convention.

| Credential | How many | Safe in a browser? | Use it for |
| --- | --- | --- | --- |
| af_test_… | Exactly one, forever | Yes | in development | Local development. Pass it straight to the SDK as apiKey. |
| af_live_… | As many as you want | Never | Your server, minting session tokens. |
| dep_… | As many as you want | Yes | Public embeds and Framer sites, locked to domains you authorize. |

All three live under **[Profile → Developer](/profile?tab=developer)**, except
deployment IDs, which are created per-avatar in the Platform's **Deploy** tab.

## The test key

One key, created once, and **it cannot be reissued** — so it is the one key we
keep showing you in the dashboard rather than hiding after creation.

It draws on a **separate free allowance** that never touches your plan's
minutes, which is exactly why there is only one: a second test key would just be
a second way to spend the same capped allowance.

```tsx
// Development only. Test keys are the only keys the SDK's apiKey path accepts.
const config = {
  apiKey: process.env.NEXT_PUBLIC_AF_TEST_KEY, // af_test_…
  avatar: { avatarId: "default" },
};
```

> A test key in a client bundle is an accepted trade for local work — its
>   allowance is capped and separate. A **live** key in a client bundle is not,
>   which is why the server rejects `af_live_*` on the SDK's `apiKey` path
>   entirely. There is no flag to override that.

## Live keys

There is no longer "the" live key on an account. Create **one per app or
environment** — production web, staging, the iOS backend, a client project —
and the day you need to revoke one, you revoke that one and nothing else stops
working.

### Step 1 — Create it

**Profile → Developer → Live keys → New live key.** Give it a name, up to 40
characters. Name it after the app or environment that will hold it — one day you
will be revoking it by this name, and "Live key 3" will not help you.

### Step 2 — Copy it now

The full key is shown **once**, at creation, and never again. We store what is
needed to authenticate it, not something we can read back to you.

Put it straight into your server's secret store. If you lose it, create a
replacement and revoke the old one — there is no recovery path, by design.

### Step 3 — Use it on your server only

A live key's job is to be exchanged for a short-lived session token on your
backend. See [Authentication](/docs/authentication) for the endpoint and
copy-paste implementations.

After creation the list shows each key by name with a **truncated prefix**
(`af_live_abcdefgh…`) — enough to tell two keys apart when you are deciding
which to revoke, not enough to use.

### Disable, revoke, and the audit trail

| Action | Effect |
| --- | --- |
| Disable | The key stops working immediately, but stays on the account. Reversible — re-enable it and it works again. Use this to test whether a key is still in use before you revoke it. |
| Revoke | Permanent. The key can never authenticate again. |

Revoked keys **stay listed**. That is deliberate: the audit log and the session
records that reference them have to keep making sense after the key is gone.

> **Rotate immediately if a live key is exposed** — in a commit, a log, a
>   screenshot, a support ticket. Create the replacement first, deploy it, then
>   revoke the old one, so there is no gap.

### Keeping a live key server-side

```bash
# .env — server-only. No NEXT_PUBLIC_ prefix, no VITE_ prefix, no equivalent.
AVATAR_FACTORY_KEY=af_live_xxxxxxxxxxxxxxxx
```

Anything prefixed for client exposure is compiled into your bundle and is
readable by anyone who opens devtools. There is no such thing as a "hidden"
client-side environment variable.

## Deployment IDs

A deployment (`dep_…`) is a **public** credential for a single avatar. It is
designed to be visible: it ships in Framer sites and in front-end code with no
backend.

What keeps it safe is not secrecy but its limits:

| Constraint | What it means |
| --- | --- |
| Domain allowlist | The deployment only answers requests from domains you authorize. Copying the ID to another site does not make it work there. |
| Monthly minute budget | A ceiling you set, enforced on our servers and reset each calendar month. Usage is shown live on the deployment card. |
| Single avatar and mode | It serves one avatar in one mode. It cannot be repointed from the client. |
| Pause and revoke | Pause stops the embed without deleting it; revoke is permanent. Both take effect server-side. |

Deployments require a paid plan and are created per-avatar: **Platform → open an
avatar → Deploy → Framer → New deployment**. See the
[Framer guide](/docs/sdk/framer/overview) for the full flow.

## Choosing a credential

| You are building | Use |
| --- | --- |
| Anything in production, with a backend | A live key on the server | exchanged for tokens via getSessionToken. |
| A prototype on your machine | Your test key | passed as apiKey. |
| A Framer site or a public landing page with no backend | A deployment ID | passed as deployId. |
| A mobile app | A live key on your backend. React Native supports getSessionToken only. |

> These are the keys that authenticate **you to us**. The keys you bring for
>   your own OpenAI, Anthropic, Google, ElevenLabs, or Inworld account are a
>   separate system with separate rules — see
>   [Bring your own keys](/docs/guides/byok).
