---
title: 'API Keys'
description: 'Mint, list, and revoke API keys for the Yorker REST API and CLI.'
section: 'Reference'
canonical_url: 'https://yorkermonitoring.com/docs/reference/api-keys'
---

# API Keys

API keys authenticate every non-session call to the Yorker control plane: REST API requests and CLI commands. They are minted from the dashboard or via the REST API itself, scoped to a single team, and shown to the holder exactly once at creation. Private-location runners use a separate credential type (runner keys) managed under [Private Locations](/docs/guides/private-locations); this page covers user/CLI keys only.

## Key shape

| Property | Value |
|---|---|
| Prefix | `sk_` |
| Format | `sk_<64 hex characters>` (32 random bytes, hex-encoded) |
| Storage | SHA-256 hashed at rest. Dashboard- and API-minted keys hold the cleartext only in the create response. CLI-minted keys (`yorker login`) briefly stage the cleartext in `cli_device_codes.secret_key` so the polling CLI can fetch it; the column is NULLed in the same row update that marks the device-code consumed, so the cleartext is unrecoverable after the first successful poll. |
| Scope | Team-wide. Every team member's keys grant the same access; there are no per-resource scopes today. |
| Expiry | Non-expiring. Keys remain valid until you revoke them. |

## Mint a key

### From the dashboard

1. Open **Settings > API Keys**.
2. Click **Create Key**, give it a name, and confirm.
3. Copy the secret immediately. The dashboard shows it once and never again.

### From the API

```bash
curl -X POST https://yorkermonitoring.com/api/api-keys \
  -H "Cookie: <your dashboard session cookie>" \
  -H "Content-Type: application/json" \
  -d '{ "name": "ci-deploy-key" }'
```

```json
{
  "key": {
    "id": "key_abc123",
    "name": "ci-deploy-key",
    "keyPrefix": "sk_a1b2c3d4e",
    "source": "manual",
    "secret": "sk_a1b2c3d4e5f6...<full 64 hex chars>",
    "createdAt": "2026-05-14T10:00:00.000Z"
  }
}
```

The `secret` field is the only place the cleartext key appears. Store it in a secret manager before discarding the response.

| Field | Required | Default | Description |
|---|---|---|---|
| `name` | No | `"Untitled Key"` | Display name in the dashboard. Trimmed and capped at 100 characters. |
| `source` | No | `"manual"` | Either `"manual"` or `"cli"`. Informational only, used by the dashboard to badge keys minted via `yorker login`. Not a security boundary. |

`POST /api/api-keys` requires a Clerk dashboard session, not Bearer auth. You cannot mint a new key from one you already hold.

### From the CLI

`yorker login` runs an interactive device-code flow that mints a key for your account on the control plane. This is the right path for human workstations:

```bash
yorker login
# Opens https://yorkermonitoring.com/cli/auth?code=XXX in your browser.
# After you click Authorize, the CLI receives the new key and writes it
# to ~/.yorker/credentials. The key is tagged source: "cli" so the
# dashboard can badge it as CLI-issued.
```

For CI and other non-interactive environments, do not use `yorker login`. See [CI/CD Integration](/docs/guides/ci-cd) for the API-key flow.

## List keys

```bash
curl https://yorkermonitoring.com/api/api-keys \
  -H "Cookie: <your dashboard session cookie>"
```

```json
{
  "keys": [
    {
      "id": "key_abc123",
      "name": "ci-deploy-key",
      "keyPrefix": "sk_a1b2c3d4e",
      "source": "manual",
      "lastUsedAt": "2026-05-14T11:30:00.000Z",
      "createdAt": "2026-05-14T10:00:00.000Z"
    }
  ]
}
```

`lastUsedAt` updates the first time the key authenticates within a rolling 1-hour window, so a busy CLI session does not write to the row on every request. The hourly resolution is enough to identify stale keys before revocation but not granular enough to audit individual calls.

The cleartext secret is **not** included in any list response, and there is no single-key GET endpoint to fetch it later. If you've lost a secret, mint a new key and revoke the old one.

## Revoke a key

### From the dashboard

**Settings > API Keys**, click **Revoke** next to the key. Active CLI sessions and CI jobs holding that key will start receiving `401 Unauthorized` on their next call.

### From the API

```bash
curl -X DELETE https://yorkermonitoring.com/api/api-keys/key_abc123 \
  -H "Cookie: <your dashboard session cookie>"
```

```json
{ "success": true }
```

`DELETE /api/api-keys/[id]` requires a Clerk session, so this endpoint cannot be called with Bearer auth. Any signed-in member of the team can delete any of the team's keys.

### Self-revocation (Bearer auth)

There is one narrowly scoped Bearer-auth revocation path, used by `yorker logout --revoke`:

```bash
curl -X DELETE https://yorkermonitoring.com/api/api-keys/self \
  -H "Authorization: Bearer sk_..."
```

```json
{ "revoked": true }
```

This deletes the row whose hash matches the Bearer token in the request, and only that row. A holder of one key cannot use this endpoint to delete a sibling key.

The endpoint authenticates the Bearer token first, so a request with a key that was already revoked returns `401 Unauthorized` exactly like any other Bearer-auth call. The `{ "revoked": true, "alreadyRevoked": true }` response is the narrow race window where the key authenticates but is then deleted (e.g., by a concurrent dashboard click) before the DELETE statement lands.

## Rotation

Yorker has no in-place rotation endpoint. To rotate a key:

1. Mint a new key with the same `name` (or a versioned name like `ci-deploy-2026q2`).
2. Update your client to use the new secret.
3. Revoke the old key once the new one is in use everywhere.

Both keys are valid simultaneously during the cutover window, so a properly staged rotation has zero downtime.

## CLI auth resolution order

When the CLI needs to authenticate, it picks the first credential it finds in this order:

1. `YORKER_API_KEY` environment variable
2. `~/.yorker/credentials` (written by `yorker login`)
3. Fail with `Yorker is not authenticated.` (exit code `2`)

CI containers without a credentials file pick up the env var transparently. Local workstations that ran `yorker login` use the file unless `YORKER_API_KEY` is also set, in which case the env var wins.

## Using a key

```bash
curl https://yorkermonitoring.com/api/checks \
  -H "Authorization: Bearer sk_a1b2c3d4e5f6..."
```

Most REST API endpoints (`/api/checks`, `/api/checks/[id]/alerts`, `/api/slos`, `/api/events`, etc.) accept the `Authorization: Bearer sk_...` header. A handful of routes require a Clerk dashboard session instead and reject Bearer auth with a `403`:

- API-key CRUD: `/api/api-keys`, `/api/api-keys/[id]`
- Billing: `/api/billing/checkout`, `/api/billing/portal`
- Incident lifecycle actions: `/api/incidents/[id]/acknowledge`, `/api/incidents/[id]/close`, `/api/incidents/[id]/reopen`, `/api/incidents/[id]/notes`

The error envelope varies by route family: API-key CRUD and billing return `{ error: "...", code: "session_required" }`; incident lifecycle returns `{ error: "Session authentication required for lifecycle actions" }` with no `code`. Treat both as "session required, key auth not accepted here".

`/api/runner/results` and other runner-facing endpoints accept a different credential type (runner dispatch tokens or runner keys from the `runnerKeys` table), not these `sk_` API keys. See [Private Locations](/docs/guides/private-locations) for runner credentials.

For the standard Bearer auth contract, see [REST API > Authentication](/docs/reference/api#authentication).
