> ## 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.

# API Introduction

> Getting started with the UptimeIO REST API for programmatic monitoring

The UptimeIO REST API lets you create and manage monitors, groups, incidents and status pages, and read monitoring results, from your own scripts and pipelines.

## Quick start

<Steps>
  <Step title="Create an API key">
    In the dashboard go to **Settings > API Keys** and create a key. See [Authentication](/api-reference/authentication).
  </Step>

  <Step title="Make a request">
    ```bash theme={null}
    curl https://api.uptimeio.com/api/monitors \
      -H "X-API-Key: YOUR_API_KEY"
    ```
  </Step>

  <Step title="Read the response">
    Every response is JSON with a `success` flag. On success the payload is in `data`; on failure the problem is in `error`.
  </Step>
</Steps>

## Base URL

All API requests should be made to:

```
https://api.uptimeio.com
```

## API Version

The current public API version is **1.0**. Version information is returned in the `X-API-Version: 1.0` response header and in the OpenAPI specification metadata.

Versioning is metadata only at present: API URLs use the `/api/...` route prefix, not `/api/v1/...`, and clients do not need to send an `X-API-Version` request header.

## Request Format

All requests use JSON for both request bodies and responses.

### Headers

| Header | Required | Description |
| - | - | - |
| `X-API-Key` | Yes (or `Authorization: Bearer`) | Your API key. See [Authentication](/api-reference/authentication). |
| `Content-Type: application/json` | On requests with a body | All request bodies are JSON. |
| `X-Project-ID` | No | Project to act on. Defaults to your organization's default project. |

### Request Example

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

## Response Format

All API responses follow a consistent format for predictable error handling and data access.

### Success Response

Successful requests return a `200-299` HTTP status code with the following structure:

```json theme={null}
{
  "success": true,
  "data": {
    "keys": [
      {
        "id": "0b6c1a52-7a49-4b3c-9f1e-2d3c4b5a6f70",
        "name": "CI/CD pipeline",
        "key_preview": "uio_1a2b...9f3c",
        "scope": "read",
        "is_active": true,
        "last_used_at": null,
        "created_at": "2026-09-30T10:00:00.000Z"
      }
    ],
    "total_count": 1,
    "limit": 20,
    "offset": 0,
    "has_more": false
  }
}
```

### Error Response

Failed requests return a `4xx` or `5xx` HTTP status code with this structure. `details` is optional and its shape depends on the error:

```json theme={null}
{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Validation failed: interval_seconds: Interval must be at least 30 seconds"
  }
}
```

### Paginated Response

Endpoints that paginate use one of two conventions, so check the specific endpoint's reference page before assuming a shape. (Key listing, shown above, nests `keys` and the pagination fields directly under `data`.)

**Offset-based** (used by list endpoints such as `GET /api/monitors`) nests results and pagination metadata under `data`:

```json theme={null}
{
  "success": true,
  "data": {
    "monitors": [
      { "id": "monitor-1", "name": "API 1" },
      { "id": "monitor-2", "name": "API 2" }
    ],
    "pagination": {
      "total_count": 150,
      "limit": 50,
      "offset": 0,
      "has_more": true
    }
  }
}
```

**Page-based** (used by endpoints such as organization member listings) returns:

```json theme={null}
{
  "success": true,
  "data": [
    { "id": "member-1" },
    { "id": "member-2" }
  ],
  "pagination": {
    "page": 1,
    "pageSize": 20,
    "total": 150,
    "totalPages": 8,
    "hasNext": true,
    "hasPrevious": false
  }
}
```

## Pagination

Offset-based list endpoints, such as `GET /api/monitors`, accept:

| Parameter | Type | Default | Description |
| - | - | - | - |
| `limit` | integer | `50` | Results per page (1-100) |
| `offset` | integer | `0` | Number of results to skip |

### Pagination Example

```bash theme={null}
# Get the next 50 monitors after the first 50
curl "https://api.uptimeio.com/api/monitors?limit=50&offset=50" \
  -H "X-API-Key: YOUR_API_KEY"
```

<Tip>
  For large result sets, increase `limit` (up to the maximum of 100) to reduce the number of API calls.
</Tip>

## Rate Limiting

UptimeIO implements rate limiting to ensure fair access and service stability.

### Rate Limit Headers

All responses include rate limit information in the headers:

```
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1704067200
```

| Header | Description |
| - | - |
| `X-RateLimit-Limit` | Maximum requests allowed in the window |
| `X-RateLimit-Remaining` | Requests remaining in current window |
| `X-RateLimit-Reset` | Unix timestamp when the limit resets |

### Rate Limit

The API applies a single global limit, the same on every plan:

| Scope | Limit |
| - | - |
| Per authenticated user (or per IP if unauthenticated) | 1,000 requests / 15 minutes |

There are no separate per-plan or per-minute tiers today - Free, Pro, and Scale all share this one limit.

Some unauthenticated, security-sensitive endpoints carry their own stricter limits, notably login attempts (5 per account per 15 minutes) and registration (10 per IP per 15 minutes).

### Handling Rate Limits

If you exceed the rate limit, you'll receive a `429 Too Many Requests` response with a `Retry-After` header (seconds until the window resets):

```json theme={null}
{
  "success": false,
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Too many requests, please try again later",
    "retryAfter": 60
  }
}
```

**Best practices:**

<Steps>
  <Step title="Check Rate Limit Headers">
    Monitor the `X-RateLimit-Remaining` header to anticipate when you're approaching limits.
  </Step>

  <Step title="Wait for Retry-After">
    When rate limited, wait the number of seconds in the `Retry-After` header before retrying:

    ```javascript theme={null}
    const retryAfter = Number(response.headers.get('Retry-After') ?? 60);
    await sleep(retryAfter * 1000);
    ```
  </Step>

  <Step title="Avoid redundant requests">
    Use filters and pagination rather than fetching everything repeatedly, and use the batch endpoints where they exist.
  </Step>
</Steps>

## HTTP Status Codes

The UptimeIO API uses standard HTTP status codes to indicate request success or failure:

| Status | Code | Meaning | Example |
| - | - | - | - |
| **2xx** | 200 | OK | Successful GET/POST request |
| **2xx** | 201 | Created | Successful resource creation |
| **4xx** | 400 | Bad Request | Invalid parameters or malformed request |
| **4xx** | 401 | Unauthorized | Missing or invalid authentication |
| **4xx** | 403 | Forbidden | Authenticated but lacking permissions |
| **4xx** | 404 | Not Found | Resource doesn't exist |
| **4xx** | 409 | Conflict | Resource already exists or the request conflicts with current state |
| **4xx** | 429 | Too Many Requests | Rate limit exceeded |
| **5xx** | 500 | Internal Error | Server error (retry recommended) |
| **5xx** | 503 | Service Unavailable | Server temporarily unavailable (retry recommended) |

## Request Examples

<Tabs>
  <Tab title="curl">
    ```bash theme={null}
    curl -X GET https://api.uptimeio.com/api/monitors \
      -H "X-API-Key: YOUR_API_KEY" \
      -H "Content-Type: application/json"
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    const response = await fetch('https://api.uptimeio.com/api/monitors', {
      method: 'GET',
      headers: {
        'X-API-Key': 'YOUR_API_KEY',
        'Content-Type': 'application/json'
      }
    });

    const data = await response.json();
    if (data.success) {
      console.log('Monitors:', data.data.monitors);
    } else {
      console.error('Error:', data.error);
    }
    ```
  </Tab>

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

    headers = {
        'X-API-Key': 'YOUR_API_KEY',
        'Content-Type': 'application/json'
    }

    response = requests.get(
        'https://api.uptimeio.com/api/monitors',
        headers=headers
    )

    data = response.json()
    if data['success']:
        print('Monitors:', data['data']['monitors'])
    else:
        print('Error:', data['error'])
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    interface ApiResponse<T> {
      success: boolean;
      data?: T;
      error?: {
        code: string;
        message: string;
        details?: unknown;
      };
    }

    const response = await fetch('https://api.uptimeio.com/api/monitors', {
      method: 'GET',
      headers: {
        'X-API-Key': 'YOUR_API_KEY',
        'Content-Type': 'application/json'
      }
    });

    const data: ApiResponse<{ monitors: unknown[] }> = await response.json();
    if (data.success && data.data) {
      console.log('Monitors:', data.data.monitors);
    }
    ```
  </Tab>
</Tabs>

## Common Patterns

### Handling Errors

Always check the `success` flag and handle errors gracefully:

```javascript theme={null}
try {
  const response = await fetch('https://api.uptimeio.com/api/monitors', {
    headers: { 'X-API-Key': apiKey }
  });

  const data = await response.json();

  if (!data.success) {
    console.error(`API Error (${data.error.code}):`, data.error.message);

    if (response.status === 429) {
      // Handle rate limiting
      console.log('Rate limited, retry after:', response.headers.get('Retry-After'));
    }
    return;
  }

  return data.data;
} catch (error) {
  console.error('Network error:', error);
}
```

### Pagination Loop

Iterate through all results using `limit`/`offset`:

```javascript theme={null}
async function getAllMonitors(apiKey) {
  const limit = 100;
  let offset = 0;
  let allMonitors = [];

  while (true) {
    const response = await fetch(
      `https://api.uptimeio.com/api/monitors?limit=${limit}&offset=${offset}`,
      { headers: { 'X-API-Key': apiKey } }
    );

    const { success, data } = await response.json();
    if (!success) break;

    allMonitors = allMonitors.concat(data.monitors);

    if (!data.pagination.has_more) break;
    offset += limit;
  }

  return allMonitors;
}
```


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