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

# Authentication

> What one project API key can do, how key scope works today, and how the admin key differs.

Every public API request authenticates with a **project API key** sent as a bearer token:

```http theme={null}
Authorization: Bearer ck_live_xxxxxxxxxxxxxxxxxxxxxxxx
```

Keys are stored as SHA-256 hashes, scoped to one project, and minted in the dashboard
(**Project → API keys**). They are **environment-specific**: a key created on localhost only
authenticates against `http://localhost:3000`; a production key only authenticates against
`https://api.craftkit.dev`.

## One key, full project access

A project key is **full-access within its project**. There is no per-key scope, role, or
permission column today — every valid `ck_live_` key for a project can do all of the following
for that project, with **no per-org provisioning**:

<CardGroup cols={2}>
  <Card title="Render" icon="play">
    `POST /v1/templates/:slug/render`
  </Card>

  <Card title="Read templates" icon="list">
    `GET /v1/templates` and `GET /v1/templates/:slug`
  </Card>

  <Card title="Poll renders" icon="timer">
    `GET /v1/renders/:id`
  </Card>

  <Card title="Create shares" icon="link">
    `POST /v1/renders/:id/shares`
  </Card>
</CardGroup>

The same key is also accepted as the embed **partner secret**, so it can reach partner-key embed
endpoints such as `GET /v1/embed/builder/templates` (list) and
[`GET /v1/embed/renders/:id/download`](/api-reference/download-render) (private stream).

<Note>
  For a headless render integration you need **exactly one** `ck_live_` key, and the template
  must live in the project that key belongs to. No admin key, no embed session, no provisioning.
</Note>

## 401 vs 404

These two are easy to confuse when a render "fails":

* **401 `unauthorized`** — the key is missing, malformed, revoked, or from the wrong environment.
* **404 `template_not_found`** — the key authenticated fine, but no template with that slug exists
  **in that key's project**. Usually means the key resolves to a different project than you expect,
  or the template was never created/published there.

## The admin key is separate

`CRAFTKIT_ADMIN_KEY` is a single global environment secret that gates only the multi-tenant
provisioning endpoints (`POST/PATCH /v1/admin/provision`). It is compared directly against the
env value and **never consults the API-key table** — so a `ck_live_` key sent to `/v1/admin/provision`
returns `401`. You do **not** need the admin key for headless rendering.

## Key scope

Today a project key is all-or-nothing within its project, which means the key you embed in a
backend service can also create and publish templates. There is no **render-only** or
**read-only** scoped key yet (roadmap). Until then:

* Mint a **dedicated key per integration** (rendering, embed, inbound webhooks each separate) so
  you can revoke one without disrupting the others.
* Store keys in environment variables, never in client code or logs.

## Key management

Keys are minted and revoked only from the dashboard — there is no programmatic key-issuance or
rotation endpoint. **Revocation is immediate with no grace period**, so rotate by minting the new
key, deploying, verifying traffic, then revoking the old one.
