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

# Authentication

> Authenticate API requests with an API key, choose a scope, and select your organization and project

UptimeIO API requests are authenticated with an **API key** sent in the `X-API-Key` header. API keys are the recommended way to call the API from scripts, CI/CD pipelines and backend services.

Two credential types are accepted by the endpoints in this reference:

| Credential | Header | Typical use |
| - | - | - |
| API key | `X-API-Key: YOUR_API_KEY` | Scripts, CI/CD, backend services, integrations |
| Session token (JWT) | `Authorization: Bearer YOUR_JWT` | The UptimeIO dashboard |

If a request carries both headers, the `Authorization: Bearer` token is used.

<Note>
  Some endpoints only accept a session token (JWT) and reject API keys. These include API key management, project management (create, rename, delete a project), billing, organization and team management, and the dashboard overview endpoints. Every page in this reference states when an endpoint is JWT-only.
</Note>

## Create an API key

<Steps>
  <Step title="Open the API Keys settings">
    Sign in at [app.uptimeio.com](https://app.uptimeio.com) and go to **Settings > API Keys**.
  </Step>

  <Step title="Create the key">
    Click **Create API Key**, give it a descriptive name (for example `CI/CD pipeline`) and choose a scope (see below).
  </Step>

  <Step title="Copy and store the key">
    Copy the key immediately. The full key is shown once; afterwards only a preview such as `uio_1a2b...9f3c` is visible.
  </Step>
</Steps>

<Warning>
  Only organization **owners and admins** can create, rotate or delete API keys. See [API keys](/account/api-keys) for managing keys in the dashboard. If you lose a key, rotate it or create a new one and delete the old one.
</Warning>

## Use an API key

Add the key to the `X-API-Key` header of every request:

```bash theme={null}
curl https://api.uptimeio.com/api/monitors \
  -H "X-API-Key: YOUR_API_KEY"
```

Keys have the form `uio_` followed by 64 hexadecimal characters.

## Scopes

Each key has one scope, chosen when it is created. The default is `read`.

| Scope | Allowed methods | Description |
| - | - | - |
| `read` | `GET`, `HEAD` | Read-only. Can retrieve data but cannot create, update or delete anything. |
| `read_write` | `GET`, `POST`, `PUT`, `PATCH`, `DELETE` | Full access to the endpoints that accept API keys. |

A `read` key that sends `POST`, `PUT`, `PATCH` or `DELETE` receives `403` with code `READ_ONLY_API_KEY`:

```json theme={null}
{
  "success": false,
  "error": {
    "code": "READ_ONLY_API_KEY",
    "message": "This API key has read-only access and cannot perform write operations"
  }
}
```

<Tip>
  Use `read` keys for dashboards and reporting, and `read_write` keys only where you need to change things.
</Tip>

## Organization and project

An API key is issued for one organization and always acts on that organization. The key cannot be redirected to another organization with a header.

Monitors, groups and incidents belong to a project. By default requests act on your organization's default project. To target another project, send its ID in the `X-Project-ID` header:

```bash theme={null}
curl https://api.uptimeio.com/api/monitors \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "X-Project-ID: YOUR_PROJECT_ID"
```

* A project that does not exist returns `404` with code `PROJECT_NOT_FOUND`.
* A project that belongs to a different organization returns `403` (for example `PROJECT_ORGANIZATION_MISMATCH`, or `API_KEY_ORGANIZATION_MISMATCH` on project-scoped status page routes).

Status page endpoints take the project in the URL instead: `/api/projects/{projectId}/status-pages`.

## Manage API keys

These endpoints require a session token (JWT) and owner or admin role. They are what the **Settings > API Keys** screen uses.

| Method | Path | Description |
| - | - | - |
| `POST` | `/api/auth/api-keys` | Create a key. Body: `{ "name": string, "scope": "read" \| "read_write" }`. Returns `201` with the full `key` once. |
| `GET` | `/api/auth/api-keys` | List your active keys (`limit` 1-100, `offset`, `sort_by` = `created_at` \| `name` \| `last_used_at`, `sort_order`). The response contains `keys`, `total_count`, `limit`, `offset` and `has_more`. |
| `POST` | `/api/auth/api-keys/{id}/rotate` | Issue a replacement key with the same name and scope and revoke the old one. Returns `201` with the new `key`. |
| `DELETE` | `/api/auth/api-keys/{id}` | Revoke a key. |

A created or rotated key looks like this:

```json theme={null}
{
  "success": true,
  "data": {
    "id": "0b6c1a52-7a49-4b3c-9f1e-2d3c4b5a6f70",
    "name": "CI/CD pipeline",
    "key": "uio_...",
    "key_preview": "uio_1a2b...9f3c",
    "scope": "read",
    "created_at": "2026-09-30T10:00:00.000Z",
    "message": "API key created successfully. Store this key securely - it will not be displayed again."
  }
}
```

## Security best practices

<AccordionGroup>
  <Accordion title="Keep keys out of code" icon="lock">
    Store keys in environment variables or a secrets manager:

    ```bash theme={null}
    export UPTIMEIO_API_KEY="YOUR_API_KEY"
    ```

    ```javascript theme={null}
    const apiKey = process.env.UPTIMEIO_API_KEY;
    ```
  </Accordion>

  <Accordion title="Rotate keys regularly" icon="rotate-right">
    Rotate from **Settings > API Keys** (or `POST /api/auth/api-keys/{id}/rotate`). The old key stops working immediately, so update your applications straight after rotating.
  </Accordion>

  <Accordion title="Use one key per service" icon="key">
    Give CI/CD, background jobs and each integration their own key. If one leaks you can revoke it without affecting the others. The key list shows each key's scope and when it was last used.
  </Accordion>
</AccordionGroup>

## Code examples

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    # List monitors
    curl https://api.uptimeio.com/api/monitors \
      -H "X-API-Key: YOUR_API_KEY"

    # Create an HTTP monitor (requires a read_write key)
    curl -X POST https://api.uptimeio.com/api/monitors \
      -H "X-API-Key: YOUR_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "name": "Production API",
        "type": "HTTP",
        "target": "https://api.example.com/health",
        "interval_seconds": 300,
        "monitoring_regions": [],
        "http_config": { "method": "GET", "expected_status_codes": [200] }
      }'
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    const response = await fetch('https://api.uptimeio.com/api/monitors', {
      headers: { 'X-API-Key': process.env.UPTIMEIO_API_KEY },
    });

    const body = await response.json();
    if (body.success) {
      console.log(body.data.monitors);
    }
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import os
    import requests

    response = requests.get(
        'https://api.uptimeio.com/api/monitors',
        headers={'X-API-Key': os.environ['UPTIMEIO_API_KEY']},
    )

    body = response.json()
    if body['success']:
        print(body['data']['monitors'])
    ```
  </Tab>
</Tabs>

## Authentication errors

| Status | Code | Meaning |
| - | - | - |
| `401` | `MISSING_AUTH` | Neither an `Authorization: Bearer` nor an `X-API-Key` header was sent. |
| `401` | `MISSING_API_KEY` | The `X-API-Key` header is empty. |
| `401` | `INVALID_API_KEY` | The key is unknown, malformed or has been revoked. |
| `401` | `INVALID_TOKEN` / `TOKEN_EXPIRED` | A session token is invalid or expired. |
| `401` | `AUTHENTICATION_REQUIRED` | The request reached a protected resource without an authenticated user. |
| `403` | `READ_ONLY_API_KEY` | A `read` key attempted a write. |
| `403` | `JWT_REQUIRED` | The endpoint only accepts a session token, not an API key. |
| `403` | `EMAIL_NOT_VERIFIED` | The account's email address has not been verified. |
| `403` | `INSUFFICIENT_PERMISSIONS` / `FORBIDDEN` | The user's role does not allow the action. |

See [Error Handling](/api-reference/errors) for the full list.

## Troubleshooting

<AccordionGroup>
  <Accordion title="401 - the key works in curl but not in code" icon="code">
    * The environment variable is not set in the runtime (`echo $UPTIMEIO_API_KEY`).
    * The key has a trailing space or newline - trim it.
    * The header name must be exactly `X-API-Key`.
  </Accordion>

  <Accordion title="403 READ_ONLY_API_KEY" icon="lock">
    The key has `read` scope. Create a `read_write` key in **Settings > API Keys**.
  </Accordion>

  <Accordion title="403 on a project or status page route" icon="shield">
    The key was issued for a different organization than the project you are addressing. Use a key created in the owning organization.
  </Accordion>
</AccordionGroup>


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