---
title: "API Keys"
description: "Generate API keys to call the Baz API and the Baz MCP server without an interactive login."
---

API keys let you authenticate with Baz outside of a browser session, for scripts, CI pipelines, and agents that call the Baz API or the Baz MCP server directly. Each key acts as the user who created it and carries that user's permissions. There is no separate scope picker: a key can do whatever the person who generated it can do, on the endpoints listed below.

## Generate a key

1. Go to **Settings → Account Settings → API Keys**
2. Click **Generate key**
3. Give the key a name, for example `CI pipeline`, and confirm
4. Copy the key immediately

The key's secret is shown once, right after creation. Baz does not store it in reversible form, so if you close the dialog without copying it, revoke the key and generate a new one.

## Using a key

Send the key in an `x-api-key` header on every request:

```bash
curl https://baz.co/api/v2/reviewer/reviewers \
  -H "x-api-key: YOUR_API_KEY"
```

## Available endpoints

Twelve endpoints accept an API key today. Baz opts endpoints in individually rather than exposing the full API, so the surface stays intentionally narrow, and it grows over time. A request to any other endpoint is rejected, even with a valid key.

| Method | Path | Use it to |
| --- | --- | --- |
| GET | `/api/v2/reviewer/config` | Read the org's live reviewer configuration |
| GET | `/api/v2/reviewer/reviewers` | List built-in and custom reviewers |
| GET | `/api/v2/discussions/by-branch` | Read review discussions on a branch's newest PR |
| GET | `/api/v2/remote-fs/file-search` | Find files in an indexed repo by glob pattern |
| POST | `/api/v2/remote-fs/grep` | Text-search a path in an indexed repo |
| POST | `/api/v2/cross-repo/search` | Search architecture summaries org-wide |
| POST | `/api/v2/mcp-sessions/events` | Record a planner event for an agent session |
| POST | `/api/v2/plans` | Create a plan, or a new version of one |
| GET | `/api/v2/plans/:seriesId/comments` | List a plan's comments |
| POST | `/api/v2/plans/:seriesId/comments` | Add a comment or reply on a plan |
| PATCH | `/api/v2/plans/:seriesId/comments/:commentId` | Edit or triage a plan comment |
| POST | `/api/v2/plans/:seriesId/pull-requests` | Link a pull request to a plan |

Each entry below expands with its parameters and the shape of its body, using the field's type (`str`, `number`, `bool`, `uuid`, `object`, `array`, `str[]`, or `type | null` for a nullable field) in place of an example value.

<details>

<summary><code>GET /api/v2/reviewer/config</code>, the organization's reviewer configuration</summary>

The feature switches and the paths that reviews skip. No parameters.

```json
{
  "excludedConfig": [
    {
      "repoName": str,
      "paths": str[],
      "repoId": uuid
    }
  ],
  "orgConfig": [
    {
      "key": str,
      "configurationId": uuid,
      "enabled": bool,
      "configurationMetadata": object
    }
  ]
}
```

</details>

<details>

<summary><code>GET /api/v2/reviewer/reviewers</code>, the organization's reviewers</summary>

| Query param | Required | Description |
| --- | --- | --- |
| `enabled` | No | Keep only enabled or only disabled reviewers |
| `repoName` | No | Keep only reviewers that apply to this repository |

```json
{
  "reviewers": [
    {
      "id": uuid,
      "title": str,
      "description": str,
      "enabled": bool,
      "activeVersion": number,
      "scopes": array,
      "discussions": array,
      "canEdit": bool,
      "createdAt": str,
      "updatedAt": str
    }
  ]
}
```

</details>

<details>

<summary><code>GET /api/v2/discussions/by-branch</code>, review discussions on a branch</summary>

Discussions on the newest pull request on a branch: file location, commented code, status, and the full comment thread.

| Query param | Required | Description |
| --- | --- | --- |
| `repository` | Yes | Repository name |
| `branch` | Yes | Branch name |
| `status` | No | `open` or `all`, defaults to `open` |

```json
[
  {
    "id": uuid,
    "file": str,
    "startLine": number,
    "endLine": number,
    "commentedCode": str,
    "status": str,
    "reviewerTitle": str,
    "comments": [
      {
        "author": str,
        "body": str,
        "createdAt": str
      }
    ]
  }
]
```

`status` in the reply is `open`, `resolved`, or `addressed`.

</details>

<details>

<summary><code>GET /api/v2/remote-fs/file-search</code>, find files by glob</summary>

| Query param | Required | Description |
| --- | --- | --- |
| `repository` | Yes | Repository name |
| `pattern` | Yes | Glob pattern, 1 to 1000 characters |
| `ref` | No | Branch, tag, or commit |

```json
{
  "items": str[],
  "total": number,
  "truncated": bool
}
```

An ambiguous `repository` returns a candidate list instead: `{ "candidates": str[] }`.

</details>

<details>

<summary><code>POST /api/v2/remote-fs/grep</code>, text-search a repository</summary>

```json
{
  "repository": str,
  "pattern": str,
  "path": str,
  "ref": str
}
```

| Field | Required | Description |
| --- | --- | --- |
| `repository` | Yes | Repository name |
| `pattern` | Yes | Search pattern, maximum 2000 characters |
| `path` | Yes | Path inside the repository |
| `ref` | No | Branch, tag, or commit |

Reply: `{ "text": str }`, or a candidate list if `repository` is ambiguous.

</details>

<details>

<summary><code>POST /api/v2/cross-repo/search</code>, search every repo's architecture summary</summary>

```json
{
  "keywords": str[],
  "domains": str[]
}
```

| Field | Required | Description |
| --- | --- | --- |
| `keywords` | Yes | 1 to 32 keywords |
| `domains` | No | Up to 50 domain names, to narrow the search |

```json
{
  "summaries": [
    {
      "repoId": uuid,
      "repoName": str,
      "domain": str,
      "summary": str
    }
  ]
}
```

</details>

<details>

<summary><code>POST /api/v2/mcp-sessions/events</code>, record a planner event</summary>

```json
{
  "sessionId": uuid,
  "eventType": str,
  "repository": str,
  "agentVendor": str,
  "payload": object
}
```

| Field | Required | Description |
| --- | --- | --- |
| `sessionId` | Yes | UUID of the agent session |
| `eventType` | Yes | Planner event type |
| `repository` | No | Repository name, maximum 300 characters |
| `agentVendor` | No | Agent client name, maximum 100 characters |
| `payload` | No | Free-form event data |

Reply: `204` with no body.

</details>

<details>

<summary><code>POST /api/v2/plans</code>, create or version a plan</summary>

Baz matches the plan by `seriesKey`, so posting again with the same key adds a version instead of a new plan.

```json
{
  "seriesKey": uuid,
  "content": str,
  "agentVendor": str,
  "repoNames": str[],
  "modelId": str,
  "tokensUsed": {
    "input_tokens": number,
    "output_tokens": number
  }
}
```

| Field | Required | Description |
| --- | --- | --- |
| `seriesKey` | Yes | UUID of the plan series; reusing it updates the same plan |
| `content` | Yes | Plan text in Markdown |
| `agentVendor` | Yes | `claude-code`, `cursor`, or `codex` |
| `repoNames` | No | Repository names the plan applies to |
| `repoIds` | No | Repository UUIDs, in place of `repoNames` |
| `modelId` | No | Model that wrote the plan |
| `tokensUsed` | No | `input_tokens` and `output_tokens` |

Reply: `201` for a new plan, `200` for a new version, with `status` one of `pending`, `approved`, `implemented`, `closed`, `deleted`.

</details>

<details>

<summary><code>GET /api/v2/plans/:seriesId/comments</code>, a plan's comments</summary>

Path parameter: `seriesId` (UUID).

```json
{
  "comments": [
    {
      "id": uuid,
      "versionId": uuid,
      "parentId": uuid | null,
      "body": str,
      "authorName": str,
      "anchor": str | null,
      "triageState": str | null,
      "createdAt": str
    }
  ],
  "mutedThreadIds": uuid[]
}
```

`triageState` is `open`, `dismissed`, or `null`.

</details>

<details>

<summary><code>POST /api/v2/plans/:seriesId/comments</code>, comment or reply on a plan</summary>

Path parameter: `seriesId` (UUID).

```json
{
  "body": str,
  "versionId": uuid,
  "parentId": uuid,
  "anchor": str
}
```

| Field | Required | Description |
| --- | --- | --- |
| `body` | Yes | Comment text, maximum 65536 characters |
| `versionId` | Yes | UUID of the plan version the comment belongs to |
| `parentId` | No | UUID of the parent comment, to reply in a thread |
| `anchor` | No | Place in the plan text the comment points to |

Reply: `201` with the new comment, shaped like the list above.

</details>

<details>

<summary><code>PATCH /api/v2/plans/:seriesId/comments/:commentId</code>, edit or triage a comment</summary>

Path parameters: `seriesId` (UUID), `commentId` (UUID).

```json
{
  "body": str,
  "triageState": str
}
```

| Field | Required | Description |
| --- | --- | --- |
| `body` | No | New comment text, maximum 65536 characters |
| `triageState` | No | `open`, `dismissed`, or `null` to clear it |

Reply: `200` with the updated comment.

</details>

<details>

<summary><code>POST /api/v2/plans/:seriesId/pull-requests</code>, link a pull request to a plan</summary>

Path parameter: `seriesId` (UUID). If the plan is still pending, linking a PR marks it implemented.

```json
{
  "repoName": str,
  "prNumber": number
}
```

| Field | Required | Description |
| --- | --- | --- |
| `prNumber` | Yes | Pull request number |
| `repoName` | No | Repository name |
| `repoId` | No | Repository UUID, in place of `repoName` |

Reply: `200` with the plan, shaped like the reply to `POST /api/v2/plans`.

</details>

## Connect the MCP server

An API key also authenticates the [Baz MCP server](/docs/basics/plugins), for clients that cannot complete an interactive OAuth sign-in, such as an agent running unattended in CI. Send it in the same `x-api-key` header when you register the server.

**Claude Code**

```shell
claude mcp add --transport http baz https://baz.co/mcp --header "x-api-key: <key>"
```

**Cursor**

Add to `~/.cursor/mcp.json`, or to `.cursor/mcp.json` for one project:

```json
{
  "mcpServers": {
    "baz": {
      "url": "https://baz.co/mcp",
      "headers": { "x-api-key": "<key>" }
    }
  }
}
```

**Codex**

Add to `~/.codex/config.toml`:

```toml
[mcp_servers.baz]
url = "https://baz.co/mcp"
http_headers = { "x-api-key" = "<key>" }
```

## Revoke a key

1. Go to **Settings → Account Settings → API Keys**
2. Find the key in the table and click **Revoke**
3. Confirm the revocation

Every request using that key starts failing immediately. Revoking a key does not affect any other key, and it cannot be undone, so generate a new key first if something still depends on it.

## FAQ

<details>

<summary>Can I see a key's secret again after I create it?</summary>

No. The secret is shown once, at creation. If you lose it, revoke the key and generate a new one.

</details>

<details>

<summary>Can I limit what a key can access?</summary>

Not beyond the [endpoints listed above](#available-endpoints). A key carries the full permissions of the user who created it on those endpoints; there is no separate scope or role picker when generating one.

</details>

<details>

<summary>Does revoking a key affect my other keys or my login session?</summary>

No. Revoking a key only stops requests authenticated with that specific key. Your other keys, and your normal login session, are unaffected.

</details>
