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

# API keys

> How API keys, scopes, and the Authorization header work in Slideless

## Two key types

| Type                 | Prefix | Scope                     | Created via                               |
| -------------------- | ------ | ------------------------- | ----------------------------------------- |
| **Organization key** | `cko_` | Acts on behalf of one org | Dashboard → Organization → API Keys       |
| **Admin key**        | `cka_` | Cross-org platform admin  | Internal tooling only, not user-creatable |

Almost everything you do uses an organization key. Admin keys exist for platform-level automation and are not exposed in the dashboard.

## How you use it

The recommended path is the [`slideless` CLI](/cli/overview). Either approach stores the key in `~/.config/slideless/config.json` (mode `0600`) and configures every subsequent CLI command to send the right `Authorization` header.

**From scratch, no dashboard needed ([full guide](/cli/auth)):**

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
slideless auth signup-request --email you@example.com
slideless auth signup-complete --email you@example.com --code 123456 --first-name "Alex"
```

`signup-complete` creates your account + organization + a `cko_` key and saves it as the active profile, all in one call. For an existing account on a new machine, use `login-request` + `login-complete` instead.

**Paste a key from the dashboard:**

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
slideless login
# paste the cko_ key when prompted
```

Switch between profiles with `slideless use <name>`.

If you call the HTTP API directly, send the key as a bearer token:

```
Authorization: Bearer cko_your_organization_api_key
```

## Scopes

When you create an organization key, you pick scopes:

| Scope                 | What it allows                                                                                         |
| --------------------- | ------------------------------------------------------------------------------------------------------ |
| `presentations:write` | Push new content, share/unshare, invite collaborators, delete presentations                            |
| `presentations:read`  | List your presentations, get presentation metadata                                                     |
| `marketplace:publish` | Publish, unpublish, and update [marketplace](/concepts/marketplace) listings, and star/unstar listings |

A key without the relevant scope returns `permission-denied` (HTTP `403`) from the affected endpoint. Pick the narrowest scope set that fits the use case. A script that only lists decks should use `presentations:read` only.

## Lifecycle

```
created (status=active)
  ↓
viewed once at creation (raw value shown)
  ↓
used N times (lastUsedAt updated on every successful call)
  ↓
revoked (status=revoked) OR expired (past expiresAt)
```

| Transition     | How                                                                                                                                               |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| Create         | Either `slideless auth signup-complete` / `login-complete` ([CLI OTP flow](/cli/auth)), or Dashboard → Organization → API Keys → "Create API key" |
| View raw value | **Once**, at creation. Slideless stores only a SHA-256 hash.                                                                                      |
| Use            | After signup/login the key is saved locally; every CLI command then authenticates automatically                                                   |
| Revoke         | Dashboard → API Keys → click "Revoke"                                                                                                             |
| Rotate         | Run `slideless auth login-complete` again (mints a fresh key), or paste a new one via `slideless login`. Revoke the old key from the dashboard.   |

## What's stored, what isn't

Slideless stores:

* A **SHA-256 hash** of the key (not the raw value)
* The **prefix** (first 8 chars) for display in the UI
* Metadata: name, description, scopes, organizationId, userId, createdAt, lastUsedAt, expiresAt

Slideless does **not** store the raw key. If you lose it, you must create a new one.

## Limits

| Limit                     | Value                                    |
| ------------------------- | ---------------------------------------- |
| API keys per organization | 20                                       |
| Keys per user             | No additional cap                        |
| Key length                | Fixed (auto-generated; you can't choose) |
| Per-key rate limit        | None enforced in v1                      |

## Verifying a key

The simple way is the CLI:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
slideless verify
```

Prints `✓ API key valid` and exits 0 on success, nonzero on failure. Convenient for CI and troubleshooting.

If you need to call the HTTP endpoint directly, see [`POST /verifyApiKey`](/api-reference/verify-api-key).

## Errors you might see

| `code`              | Meaning                                  | Fix                                                       |
| ------------------- | ---------------------------------------- | --------------------------------------------------------- |
| `unauthenticated`   | Missing or invalid key                   | Re-run `slideless login`, or check `Authorization` header |
| `permission-denied` | Key valid but missing the required scope | Recreate the key with the correct scope                   |
| `permission-denied` | Key has been revoked                     | Create a new key                                          |

## Operational guidance

* **Treat keys as secrets.** Don't commit them to git, don't paste them in chat, don't put them in client-side code.
* **Use one key per integration.** Easier to rotate, easier to attribute usage.
* **Set `lastUsedAt` reminders.** If a key hasn't been used in a long time, it's a candidate for revocation.
* **Prefer scoped keys over admin-style "do anything" keys.** Even if the dashboard only offers `presentations:read` and `presentations:write` today, picking the minimum reduces blast radius later.
