---
title: API keys API
description: Programmatic key management — create, list, revoke. Requires a signed-in user.
---

These endpoints manage the API keys attached to your account. They require a **Clerk session JWT** (not an `sf_…` token) — `sf_…` tokens cannot mint or revoke other keys.

The dashboard's [/settings/api-keys](/settings/api-keys) page wraps these endpoints visually.

## `GET /me/keys`

List all keys for the signed-in user.

```ts
ApiKeyRow[] = {
  id:        string;          // k_…
  name:      string | null;
  active:    boolean;         // false after revocation
  createdAt: string;          // ISO
  tail:      string;          // last 4 chars of the token, for display
}[]
```

Plaintext values are **never** included — they're hashed at rest.

## `POST /me/keys`

Create a new key.

```
POST /me/keys
Authorization: Bearer <Clerk JWT>
Content-Type:  application/json

{ "name": "ci-runner" }   // optional, trimmed; null if empty
```

Response includes the plaintext **once**:

```ts
{
  id:        string;        // k_…
  name:      string | null;
  active:    true;
  createdAt: string;
  tail:      string;        // last 4 chars of the token, for display
  plaintext: string;        // sf_… — copy now, it's never returned again
}
```

Lose the plaintext → revoke and create a new one. There is no recovery.

## `DELETE /me/keys/:id`

Deactivate a key. `200` on success, `404` if the id doesn't belong to you.

```
DELETE /me/keys/k_…
Authorization: Bearer <Clerk JWT>
```

```json
{ "ok": true }
```

Revoked keys remain queryable in `GET /me/keys` (with `active: false`), and existing executions still reference them. Subsequent requests using the revoked plaintext return `401 invalid api key`.

## `GET /me`

Current user profile — handy for confirming a token resolves.

```json
{ "id": "user_…", "email": "ada@example.com" }
```
