# API Basics

An introduction to the StatusDashboard API — authentication, base URLs, and how requests work.

Source: https://statusdashboard.com/docs/api

The StatusDashboard API is a REST API that lets you interact with your tenant programmatically. Any functionality available to your user account in the web application is available via the StatusDashboard API.

## Base URL
All API requests are made to:

```
https://api.statusdashboard.com
```

## Required headers
Every request must include the following headers:

| Header          | Value                     |
| --------------- | ------------------------- |
| `Authorization` | `Bearer {keyId}:{secret}` |
| `Content-Type`  | `application/json`        |

You can generate and manage API keys from **User Profile → API Keys** in the StatusDashboard dashboard.

## HTTP methods (PUT vs PATCH)
StatusDashboard uses HTTP verbs consistently:

| Verb        | Semantics            | When to use                                                                                                                                                 |
| ----------- | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`PUT`**   | **Full replacement** | Send the complete state of a config slice. Omitted fields are cleared or defaulted — the server does not merge with the previous record.                    |
| **`PATCH`** | **Partial update**   | Send only the fields you want to change. Omitted fields are left unchanged. At least one mutable field is required unless the endpoint documents otherwise. |

**Examples**

* `PUT /app/dashboards/{id}/content` — every module toggle, order, and uptime setting must be included.
* `PATCH /app/dashboards/{id}` — update `name`, `enabled`, or other general fields without sending the full dashboard.
* `PATCH /app/events/{id}` — change `publish`, `title`, `affectedComponents`, or other event fields without resending the entire event.

Each endpoint page states whether it is full replacement or partial update. When in doubt, read the **Request body** table on that page.

### Documented PUT exceptions (sub-resources)
These endpoints use &#x2A;*`PUT`** even though the body may contain a subset of fields, because they replace a **single sub-resource document** in one shot (not a merge across the parent event):

| Method | Path                                   | Behavior                                                                                                                |
| ------ | -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `PUT`  | `/app/events/{id}/post-mortem`         | Create or **fully replace** the post-mortem object.                                                                     |
| `PUT`  | `/app/events/{id}/notes/{noteId}`      | Replace the note text (`note` is required).                                                                             |
| `PUT`  | `/app/events/{id}/timeline/{statusId}` | Replace the editable timeline entry fields (`message` required; optional `timestamp`). Status and author are immutable. |

Workflow **status transitions*&#x2A; on the event itself use &#x2A;*`POST /app/events/{id}/timeline`*&#x2A; (new entry) or &#x2A;*`POST /app/events/{id}/reopen`**, not PATCH on the event root.

## Response format
Successful responses return JSON with the requested data at the top level.

### Endpoint errors
When your request is authenticated but rejected by the endpoint (validation, permissions, not found, etc.), the response body is JSON with an `error` field:

```json
{
  "error": "Insufficient permissions."
}
```

### Authentication failures
When authentication or tenant-level access checks fail before the endpoint runs (invalid or revoked API key, rate limit exceeded, etc.), the API returns &#x2A;*`403 Forbidden`**. The response body is typically **empty** — do not assume a JSON `error` field.

## HTTP status codes
| Code  | Meaning                                                                              |
| ----- | ------------------------------------------------------------------------------------ |
| `200` | Success                                                                              |
| `201` | Created — resource created successfully                                              |
| `400` | Bad request — check your request body                                                |
| `403` | Forbidden — authentication failed, access denied, or rate limit exceeded (see below) |
| `404` | Resource not found                                                                   |
| `409` | Conflict — quota or uniqueness constraint (per endpoint)                             |

### Authentication and access (`403`)
All `/app/*&#x60; routes require a valid API key. When authentication or tenant-level access checks fail, the API responds with &#x2A;*`403 Forbidden`** — not `401`. This includes:

* Missing, malformed, or invalid API key
* Revoked API key (including keys revoked via **User Profile → API Keys** or user deletion)
* Per-tenant rate limit exceeded
* Disabled user or missing membership (where applicable)

Do **not** expect `401&#x60; for invalid or missing API keys. Rate-limited requests also return &#x2A;*`403 Forbidden`**, not `429 Too Many Requests`.

After authentication succeeds, endpoints may return additional &#x2A;*`403`** responses (for example, your plan does not include a feature, or your role is insufficient) with a JSON `error` field as shown above.

## Rate limits
API requests are rate-limited per tenant. If you exceed the limit, the API rejects the request with &#x2A;*`403 Forbidden`** (not `429`). Limits vary by plan — check your account settings for your current limit.

## Pagination
List endpoints return at most `limit` items per request. When more results exist, the response includes a `nextToken` string — a next-page bookmark. To fetch the next page, repeat the **same** request (same query parameters, same `limit`) and pass that `nextToken` unchanged.

Do not parse, edit, or build your own `nextToken`. The server uses it to resume where the previous page left off.

* `nextToken` is `null` (or omitted) when there are no more pages.
* Filters and sort order are **not** stored inside the token. You must send the same query parameters (dates, email filters, etc.) on every page request.

Example:

```bash
# Page 1
curl "https://api.statusdashboard.com/app/audit?limit=10" \
  -H "Authorization: Bearer bcf847abf5c6:def456"

# Page 2 — same query parameters, plus nextToken from the page-1 response
curl "https://api.statusdashboard.com/app/audit?limit=10&nextToken=eyJQSyI6Ik9SRyNhMWIyYzNkNCJ9" \
  -H "Authorization: Bearer bcf847abf5c6:def456"
```

## Rich text fields
Several API string fields support formatted content — the same bold, italic, list, and link formatting available in the StatusDashboard web application. These fields are stored as strings and rendered on status dashboards.

Event fields that use this contract include `description`, `impactAnalysis` (incidents and maintenance only), `initialTimelineMessage`, timeline entry `message`, and post-mortem rich-text fields.

### Supported formatting
* **Bold** and *italic* text
* Bullet and numbered lists
* Hyperlinks

Headings, blockquotes, and code blocks are not supported.

### Accepted formats
| Format                                     | Notes                                                                                                                                                       |
| ------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Structured document JSON** (recommended) | A JSON document serialized as a string — the same format returned by GET when the field was saved via the web app. See [example](#rich-text-example) below. |
| **Plain text**                             | Accepted. Rendered as plain text on status dashboards.                                                                                                      |
| **HTML fragments**                         | Simple HTML (e.g. `<p>…</p>`) is accepted as a legacy format.                                                                                               |

**Markdown and CommonMark syntax is not parsed.** Sending `**bold**` or `# Heading` will display those characters literally, not as formatted text.

### Character limits
Limits apply to the **stored string** length. A structured document JSON string may be longer than the visible text it contains because of JSON encoding overhead.

### Integration pattern
For automation, the safest approach is to **read the current value from GET, modify it, and write it back** using the same encoding. This guarantees round-trip compatibility with the web application.

### Rich text example
A minimal structured document containing the text "Hello, world." in bold:

```json
"{\"type\":\"doc\",\"content\":[{\"type\":\"paragraph\",\"content\":[{\"type\":\"text\",\"text\":\"Hello, world.\",\"marks\":[{\"type\":\"bold\"}]}]}]}"
```

When sent in a JSON request body, the outer quotes make this a normal JSON string value.

***

## Reports endpoints
Monthly uptime reports (admin role + `uptimeReports` capability):

| Method | Path                  | Description                                                      |
| ------ | --------------------- | ---------------------------------------------------------------- |
| `GET`  | `/app/reports/uptime` | Compute a monthly uptime report for a dashboard or org component |

See [Get uptime report](/docs/api/reports/uptime/get) for query parameters and response shape.

***

## Profile endpoints
| Method | Path           | Description                           |
| ------ | -------------- | ------------------------------------- |
| `GET`  | `/app/profile` | Read the authenticated user's profile |

See [Profile](/docs/api/account-management/profile/get) in the API reference for request and response details.

## Inbound webhook endpoints
Signing keys and ingest logs for the public inbound webhook (gated by the **integrations** entitlement):

| Method   | Path                                              | Description                                                   |
| -------- | ------------------------------------------------- | ------------------------------------------------------------- |
| `POST`   | `/public/webhooks/inbound`                        | Ingest a signed trigger or update payload (public; HMAC auth) |
| `GET`    | `/app/integrations/webhooks/inbound/keys`         | List signing keys                                             |
| `POST`   | `/app/integrations/webhooks/inbound/keys`         | Create a signing key                                          |
| `DELETE` | `/app/integrations/webhooks/inbound/keys/{keyId}` | Revoke a signing key                                          |
| `GET`    | `/app/integrations/webhooks/inbound/logs`         | List inbound ingest logs (admin only)                         |

See [Ingest inbound webhook](/docs/api/integrations/webhooks/inbound/post), [Create webhook key](/docs/api/integrations/webhooks/inbound/keys/create), and [List inbound webhook logs](/docs/api/integrations/webhooks/inbound/logs/list) for field-level details.

## Outbound integration endpoints
Webhook, Microsoft Teams, and Google Chat **endpoints** (payload destinations) and delivery hygiene (gated by the **integrations** entitlement). Human email, SMS, and WhatsApp subscribers stay under `/app/subscribers/*`.

| Method   | Path                                                                                                                              | Description                                       |
| -------- | --------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------- |
| `GET`    | `/app/integrations/webhooks/outbound/endpoints · /app/integrations/teams/endpoints · /app/integrations/gchat/endpoints`           | List endpoints + unique-endpoint usage            |
| `POST`   | `/app/integrations/webhooks/outbound/endpoints · /app/integrations/teams/endpoints · /app/integrations/gchat/endpoints`           | Create a pre-verified integration endpoint        |
| `PATCH`  | `/app/integrations/webhooks/outbound/endpoints · /app/integrations/teams/endpoints · /app/integrations/gchat/endpoints`           | Update components, URL, email, paused, or locked  |
| `DELETE` | `/app/integrations/webhooks/outbound/endpoints · /app/integrations/teams/endpoints · /app/integrations/gchat/endpoints`           | Delete an endpoint (`urlHash` or `url`)           |
| `GET`    | `/app/notifications/{webhook\|teams\|gchat}/logs`                                                                                 | List delivery log summaries                       |
| `GET`    | `/app/notifications/{webhook\|teams\|gchat}/logs/{logId}`                                                                         | Get one log with bodies (`sentAt` query required) |
| `GET`    | `/app/integrations/webhooks/outbound/suppression` · `/app/integrations/teams/suppression` · `/app/integrations/gchat/suppression` | List suppressed endpoints                         |
| `DELETE` | same paths                                                                                                                        | Clear a suppression entry                         |
| `POST`   | `/app/integrations/webhooks/outbound/endpoints/signing-secret/rotate`                                                             | Rotate outbound webhook signing secret            |

See [Create webhook endpoint](/docs/api/integrations/webhooks/outbound/endpoints/create) and [List webhook delivery logs](/docs/api/notifications/webhooks/logs/list) for field-level details. Dashboard channel toggles are documented under [Update subscription config](/docs/api/status-dashboards/dashboards/subscriptions/update) (five channels required).
