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

# API authentication and conventions

> Authenticate with an API key or personal token, pick the right scope, and read or change your organization's configuration over HTTP.

export const Plan = ({tier}) => <Badge color="blue">{tier} plan</Badge>;

The configuration API lets you read and change your organization's setup over HTTP: data sources, SLOs, alert routes, teams, the status page and more. It is the same set of actions that the [MCP tools](/api-reference/mcp) offer, shaped as resources, so a script or a Terraform run can do what an MCP client does.

<Plan tier="Business" />

Every request goes to `https://sreagent.app/api/v1/config`. The OpenAPI document for the configuration API is rendered in this documentation under the API reference group.

## Authenticate

Send a credential as a Bearer token on every request.

```bash theme={null}
curl https://sreagent.app/api/v1/config/teams \
  -H "Authorization: Bearer sre_ak_xxxxxxxxxxxx"
```

<Steps>
  <Step title="Open the API keys tab">In **Settings**, open **API Keys**.</Step>

  <Step title="Generate a key">
    Select **Generate API Key**, enter a **Key Name**, tick the scopes the key needs, and select
    **Generate Key**.
  </Step>

  <Step title="Copy the key">
    The key is shown once. Copy it into your secret store before you dismiss the message. To stop a
    key working, select **Revoke** on its card.
  </Step>
</Steps>

<Warning>
  Treat an API key like a password. Never commit it, and give each job its own key so you can revoke
  one without breaking the others.
</Warning>

### Scopes

Each key carries the scopes you tick when you generate it.

| Scope | What it allows |
| - | - |
| `api:admin` | Read and write through the configuration API. It has the same reach as `mcp:admin`. |
| `api:config_read` | Read through the configuration API with `GET` only. Every other verb answers `403` with `read_only_key`. Use it for CI jobs that only plan. |
| `mcp:read` | Call the read tools on the MCP endpoint. |
| `mcp:write` | Call the read and write tools on the MCP endpoint. |
| `mcp:admin` | Call every MCP tool, including the ones that configure the organization. |

`api:config_read` is a key of its own: it cannot be combined with another scope. The configuration API accepts only `api:admin` and `api:config_read`, and the MCP endpoint accepts only the `mcp:*` scopes, so a key for one endpoint is refused at the other.

### Personal tokens

A personal access token authenticates as you instead of as an organization. Create one on your **Account** page, under **Personal access tokens**, with **Create Token**. You choose which organizations it can act in and, under **Maximum role**, a ceiling: **Viewer (read only)**, **Member (can operate)**, **Org admin**, or no limit. The ceiling can only reduce what you can do. Picking a level above your own role grants nothing.

A personal token works on the MCP endpoint, where each tool needs a minimum role: viewer for read tools, member for write tools, org admin for admin tools. The configuration API refuses personal tokens, so use an `api:admin` or `api:config_read` key there.

### Plan requirement

The configuration API and the MCP endpoint are part of the Business plan. On a lower plan the key form hides the MCP and API scopes, and a request from an existing key answers `403` with "The configuration API is not included in your plan." (or "MCP server is not included in your plan." on the MCP endpoint).

## Read

`GET /{resource}` lists a collection and `GET /{resource}/{id}` reads one row. A setting that exists once per organization, such as `organization_settings` or `slack`, is read with `GET /{resource}` and has no id.

```bash theme={null}
curl https://sreagent.app/api/v1/config/slos \
  -H "Authorization: Bearer sre_ak_xxxxxxxxxxxx"
```

A list answers `{"organization": ..., "data": [...], "truncated": false}`. Lists are not paged. When `truncated` is `true`, the list was cut at its cap.

Reading one row returns an `ETag` header that identifies the row's current configuration.

```bash theme={null}
curl -i https://sreagent.app/api/v1/config/teams/<team-id> \
  -H "Authorization: Bearer sre_ak_xxxxxxxxxxxx"
```

Secrets are never returned. A field such as `api_key` is answered as `api_key_set: true` or `false`.

## Create

`POST /{resource}` creates a row and answers `201` with the new row, its `ETag`, and a `Location` header.

```bash theme={null}
curl -X POST https://sreagent.app/api/v1/config/alert_mutes \
  -H "Authorization: Bearer sre_ak_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"pattern": "highcpu", "reason": "Planned load test", "duration_minutes": 60}'
```

If a row already matches the resource's natural key, the call answers `409` with the existing row, and nothing is overwritten.

## Update

`PUT /{resource}/{id}` changes one row, and `PUT /{resource}` changes a once-per-organization setting. Only the fields you send change, and a missing row answers `404`.

Add `If-Match` with the `ETag` you last read, so a change made by someone else in the meantime is not overwritten.

```bash theme={null}
curl -X PUT https://sreagent.app/api/v1/config/teams/<team-id> \
  -H "Authorization: Bearer sre_ak_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -H 'If-Match: "<etag-from-the-read>"' \
  -d '{"name": "Platform"}'
```

If the row changed after that version, the call answers `412` with the current row, and nothing is written. Read the row again and retry against the new `ETag`. `If-Match: *` skips the version check. Without the header the write goes through unchecked.

<Note>
  The `ETag` follows the configuration you can set, not the last-modified time. Routine activity,
  such as a check recording a result, does not change it, so a plan and an apply an hour apart still
  match when nobody edited the configuration. The check runs just before the write and is not a
  lock.
</Note>

## Delete

`DELETE /{resource}/{id}` removes one row. The API confirms the deletion for you, so you do not send `confirm`. It accepts `If-Match` the same way as an update.

```bash theme={null}
curl -X DELETE https://sreagent.app/api/v1/config/alert_mutes/<mute-id> \
  -H "Authorization: Bearer sre_ak_xxxxxxxxxxxx"
```

## Export as Terraform

`GET /export?format=hcl` answers your organization's configuration as one Terraform file, with an import block for every row. A stored secret appears only as a comment that points to the write-only argument that would manage it.

```bash theme={null}
curl "https://sreagent.app/api/v1/config/export?format=hcl" \
  -H "Authorization: Bearer sre_ak_xxxxxxxxxxxx" \
  -o sreagent.tf
```

## Errors

Every failed request answers a JSON body with an `error` code and a `message` that says what to change.

| Status | `error` | Meaning |
| - | - | - |
| `403` | `forbidden` | The key lacks the scope, the plan does not include the API, or a personal token was used. |
| `403` | `read_only_key` | An `api:config_read` key tried to change something. |
| `404` | `not_found` | No such resource or row. |
| `409` | `conflict` | A row already exists for that key. |
| `412` | `precondition_failed` | `If-Match` named a version that is no longer current. |
| `422` | `unprocessable_entity` | The body was refused. The `message` names the field. |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.