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

# Authentication

> API key management, Bearer tokens, and scopes

## Bearer tokens

All API requests must include a Bearer token in the `Authorization` header:

```bash theme={null}
curl https://api.useqrkit.com/v1/qr-codes \
  -H "Authorization: Bearer qr_live_your_key_here"
```

Requests without a valid token return a `401 Unauthorized` error.

To check a key without touching any resources, call `GET /v1/me` — it requires
no scope and returns the workspace name, plan, scopes and environment behind
the key:

```bash theme={null}
curl https://api.useqrkit.com/v1/me \
  -H "Authorization: Bearer qr_live_your_key_here"
```

## API key format

QRKit API keys use a prefix to indicate the environment:

| Prefix     | Environment | Description                                                       |
| ---------- | ----------- | ----------------------------------------------------------------- |
| `qr_live_` | Production  | For your production integration                                   |
| `qr_test_` | Test        | For development and CI — created codes are marked as test-created |

<Info>
  Test keys work identically to live keys and create real QR codes in your
  workspace (marked internally as created by a test key), so you can verify
  the full flow end to end. Delete test codes when you're done — they appear
  in your dashboard like any other code.
</Info>

## Scopes

Each API key has one or more scopes that control what it can access:

| Scope            | Description                                     |
| ---------------- | ----------------------------------------------- |
| `qr:read`        | Read QR codes and folders                       |
| `qr:write`       | Create, update, and delete QR codes and folders |
| `analytics:read` | Access scan analytics                           |
| `tokens:manage`  | Create, list, and revoke API keys               |

<Warning>
  Follow the principle of least privilege. Only grant scopes that your integration needs.
</Warning>

## Creating API keys

API keys are created from the [QRKit dashboard](https://useqrkit.com/dashboard/api-keys) (recommended) or via the [Tokens API](/api-reference/tokens/create). API access requires a paid plan.

When you create a key, the full key value is returned **once**. Store it securely — you won't be able to see it again. The dashboard and API only show the key prefix (e.g., `qr_live_a1b2`) for identification.

## Key rotation

Rotate API keys using the [Rotate endpoint](/api-reference/tokens/rotate) or the dashboard. This creates a new key with the same name, scopes and expiry, and revokes the old one.

<Note>
  Token management endpoints (`/tokens/*`) are authenticated with your QRKit
  dashboard session (a Clerk session JWT), not with an API key — a leaked API
  key can never mint new keys.
</Note>

```bash theme={null}
curl -X POST https://api.useqrkit.com/v1/tokens/rotate \
  -H "Authorization: Bearer <clerk_session_jwt>" \
  -H "Content-Type: application/json" \
  -d '{"key_id": "key_abc123"}'
```

## Key expiration

API keys can optionally have an expiration date. Set `expires_in_days` when creating a key:

```json theme={null}
{
  "name": "CI Pipeline Key",
  "scopes": ["qr:read", "qr:write"],
  "expires_in_days": 90
}
```

Expired keys return a `401 Unauthorized` error. Create a new key or use rotation before the current key expires.

## Security best practices

<Steps>
  <Step title="Use environment variables">
    Never hardcode API keys in source code. Use environment variables or a secrets manager.
  </Step>

  <Step title="Use test keys for development">
    Use `qr_test_` keys during development and CI/CD. Switch to `qr_live_` only in production.
  </Step>

  <Step title="Rotate regularly">
    Set up a rotation schedule for your production keys (e.g., every 90 days).
  </Step>

  <Step title="Minimize scopes">
    Grant only the scopes your integration needs. A read-only dashboard only needs `qr:read`.
  </Step>
</Steps>
