---
slug: platform/api-keys
title: API keys
kind: reference
surface: platform
summary: Reference for Aetherfy API keys — the afy_live_ and afy_test_ formats, one-time plaintext reveal, per-tier key limits, the create-update-revoke rotation procedure, agent-injected keys, and the auth header and error codes.
sources:
  - dashboard/pages/api/dashboard/api-keys/index.js
  - dashboard/pages/api/dashboard/api-keys/[keyId].js
  - dashboard/pages/api/dashboard/onboarding/default-key.js
  - dashboard/src/lib/services/defaultKeyProvisioner.js
  - dashboard/migrations/054_extend_plans_for_collections_and_api_keys.sql
  - aetherfy-control-plane:api/middleware/auth.py
  - aetherfy-control-plane:shared/error_codes.py
  - aetherfy-vectors-python-sdk:aetherfy_vectors/auth.py
  - aetherfy-vectors-js-sdk:src/auth.ts
  - aetherfy-cli:cmd/login.go
---

# Aetherfy API keys

## The format of an Aetherfy API key

An Aetherfy API key is a prefix followed by exactly 32 hexadecimal characters.

| Prefix | Meaning |
|---|---|
| `afy_live_` | Production key |
| `afy_test_` | Test key |

Aetherfy stores only a SHA-256 hash of the key. It also keeps a display-only
prefix — the first 12 characters — so you can identify a key in a list without
the plaintext existing anywhere in the system.

That 32-hexadecimal shape is what Aetherfy **generates**. The client-side
validators are deliberately more permissive than the generator, so they keep
working if the issued format ever widens — neither is a statement about what
Aetherfy issues today:

- **The Aetherfy generator** issues `afy_live_` or `afy_test_` followed by
  exactly 32 hexadecimal characters. This is the canonical, issued format.
- **Both Aetherfy SDKs** validate against `^afy_(live|test)_[a-zA-Z0-9]{16,}$`
  — 16 or more alphanumeric characters, not necessarily hexadecimal.
- **The Aetherfy CLI** requires the prefix plus at least 32 alphanumeric
  characters.

A key that passes an SDK or CLI check is therefore not necessarily a key
Aetherfy issued; only the server decides that. The looser client-side rules
exist so an older SDK or CLI does not reject a future key format.

## The one-time reveal of an Aetherfy key

The plaintext of an Aetherfy API key is shown exactly once, at creation, and
never again. There is no endpoint that returns it afterwards, and Aetherfy
support cannot recover it, because only the hash was kept.

On first login the Aetherfy welcome modal reveals your default key's plaintext
once. A second attempt at that reveal returns HTTP 410 with the code
`ALREADY_REVEALED`. If you lose the plaintext, the answer is always to create a
new key.

## Where to manage Aetherfy API keys

Create, rename and revoke keys at
`https://app.aetherfy.com/dashboard/settings/api-keys`.

Revoking a key in Aetherfy takes effect immediately — there is no propagation
delay and no grace window for in-flight clients.

## What an Aetherfy API key is scoped to

Aetherfy API keys are per **account**. They are not per workspace and not per
project. Holding one key rather than another does not narrow what you can reach.

Tenant isolation in Aetherfy is enforced per request on the server, derived from
the account the key belongs to — not by the key carrying a scope of its own.

## Agent-scoped keys issued by Aetherfy

An Aetherfy agent receives an automatically-generated key, injected into its
environment as `AETHERFY_API_KEY`. These keys behave differently from the ones
you create:

| Property | Agent-injected key |
|---|---|
| Visible in the dashboard | No |
| Counts against your key quota | No |
| Lifecycle | Removed automatically when the agent is deleted |

You do not create, rotate or revoke these yourself.

## How many API keys each Aetherfy tier allows

| Tier | Maximum API keys |
|---|---|
| Free | 2 |
| Starter | 5 |
| Performance | 10 |
| Enterprise | 50 |

Exceeding the limit returns HTTP 400 from Aetherfy, with a message naming your
plan and its allowance. Agent-injected keys are excluded from this count.

## Rotating an Aetherfy API key

There is **no rotate endpoint** in Aetherfy. Rotation is a three-step procedure
you perform yourself:

1. Create a new key at `https://app.aetherfy.com/dashboard/settings/api-keys` and
   capture the plaintext at creation time.
2. Update every client, environment variable and secret store that carries the
   old key.
3. Revoke the old key.

Do the steps in that order. Revocation is immediate, so revoking before step 2 is
complete will break live traffic.

## How Aetherfy clients read the key

| Client | Where the key comes from |
|---|---|
| Python SDK | `AETHERFY_API_KEY`, then `AETHERFY_VECTORS_API_KEY` |
| JavaScript SDK | `AETHERFY_API_KEY`, then `AETHERFY_VECTORS_API_KEY` |
| CLI | `credentials.yaml`, written with permissions `0600`; also honours `AETHERFY_API_KEY` |

Both Aetherfy SDKs check the environment in that order, so setting
`AETHERFY_API_KEY` covers every client at once. The CLI is documented at `/cli`.

## Authenticating directly against the Aetherfy HTTP API

Send the key as a bearer token:

```http
Authorization: Bearer afy_live_0123456789abcdef0123456789abcdef
```

Aetherfy answers a bad or absent credential with:

| Condition | Status | Code |
|---|---|---|
| Header missing or malformed | 401 | `MISSING_API_KEY` |
| Key not recognised | 401 | `INVALID_API_KEY` |

Both are terminal for the request — retrying the same key will not change the
answer.
