# Update a page

`PUT https://evohub.io/api/v1/pages/{pageID}`

Part of the [Status API](https://docs-dev.evohub.io/status.md) reference · operationId `updatePage`.

A partial update: a field left out keeps its stored value. `logo_url` and
`brand_color` clear on `null`; `theme: ""` means `auto`. `slug` and `team_id`
cannot change here: sent with a different value they are refused with
`VALIDATION_ERROR`, sent with the stored value they are accepted.

**Permission (API-key scope):** `status:page:write`.

## Authorization

Any one of:

- `bearerAuth` (status:page:write)
- `apiKeyHeader` (status:page:write)

Where:

- `bearerAuth`: HTTP Bearer — An EvoHub API key (`evohub_…`) as a bearer token.
- `apiKeyHeader`: API key in the header `X-API-Key` — An EvoHub API key (`evohub_…`).

## Path parameters

- `pageID` (string (uuid), required, example `3f6c2a1e-8b4d-4f7a-9c21-5d0e7a9b1c42`): The status page's id (a UUID).

## Request body (required)

Content type: `application/json`

Type: `PageUpdate`

- `name` (string): Left out keeps the stored name; may not be empty.
- `logo_url` (string | null): Left out keeps the stored logo; `null` clears it.
- `brand_color` (string | null): Left out keeps the stored colour; `null` clears it.
- `is_public` (boolean, default `true`): Left out keeps the stored visibility.
- `theme` (string, one of `auto`, `light`, `dark`): Left out keeps the stored theme; `""` means `auto`.
- `slug` (string): Cannot change. A different value is refused (`VALIDATION_ERROR`); the stored value is accepted.
- `team_id` (string | null): Cannot change here. A different value is refused (`VALIDATION_ERROR`); the stored value is accepted.

## Responses

### 200 — The page.

Content type: `application/json`

Type: `object`

- `data` (Page, required)
  - `id` (string (uuid), required)
  - `org_id` (string, required)
  - `team_id` (string, required): The team that manages the page; `""` for the whole organization. Never affects the public page.
  - `slug` (string, required): Unique in the organization.
  - `name` (string, required)
  - `logo_url` (string)
  - `favicon_url` (string)
  - `brand_color` (string): `#rrggbb`.
  - `custom_domain` (string)
  - `is_public` (boolean, required): Whether visitors can read it.
  - `theme` (string, required, one of `auto`, `light`, `dark`)
  - `site_theme` (SiteTheme, required)
    - `font` (string, one of ``, `Inter`, `Roboto`, `Open Sans`, `Lato`, `Source Sans 3`, `IBM Plex Sans`, `Nunito Sans`, `Work Sans`, `Manrope`, `DM Sans`, `Plus Jakarta Sans`, `Figtree`, `Geist`, `Poppins`, `Merriweather`, `Source Serif 4`, `Lora`): `""` is the system font.
    - `radius` (string, one of `none`, `small`, `medium`, `large`, default `medium`)
    - `background` (string, one of `default`, `tinted`, `slate`, `warm`, default `default`)
    - `mode` (string, one of `system`, `light`, `dark`, default `system`): The same setting as the page's `theme` (`system` there is `auto`).
  - `subscriptions_enabled` (boolean)
  - `reply_to_email` (string): Where replies to subscriber emails go.
  - `page_description` (string)
  - `footer_text` (string)
  - `support_url` (string)
  - `support_label` (string)
  - `privacy_url` (string)
  - `terms_url` (string)
  - `ga_tag` (string): The older field for the Google Analytics id, kept in step with `analytics.ga4_measurement_id`.
  - `search_indexable` (boolean)
  - `history_window_days` (integer, one of `30`, `90`): How far back the public page shows past incidents.
  - `product_groups` (boolean): Groups fold into one line each on the public page.
  - `open_groups` (array of string): Groups that start open.
  - `product_pages` (boolean): Each group has a page of its own.
  - `header_links` (array of HeaderLink, max items 5)
    - `label` (string, required, min length 1, max length 40): One line of text.
    - `url` (string (uri), required, max length 2048): An `https://` URL.
  - `show_page_name` (boolean): `false` shows the logo alone.
  - `analytics` (AnalyticsSettings)
    - `enabled` (boolean): Whether visitor analytics are collected.
    - `retention_days` (integer, one of `30`, `90`, `180`, `365`, `730`): How long daily counts are kept.
    - `ga4_measurement_id` (string): A Google Analytics 4 id (`G-…`) the public page loads, or `""`.
    - `honor_privacy_signals` (boolean): Load Google Analytics only for visitors who sent neither `DNT: 1` nor `Sec-GPC: 1`.
  - `created_at` (string (date-time), required)
  - `updated_at` (string (date-time), required)
- `success` (boolean, required, value `true`)

### 400 — A field is missing or invalid (`VALIDATION_ERROR`); the message names it, or the body is not valid (`INVALID_BODY`).

Content type: `application/json`

Type: `Error`

- `error` (object, required)
  - `code` (string, required): Machine-readable code. Branch on this.
  - `message` (string, required): Human-readable explanation.
  - `request_id` (string): This request's id, also in `X-Request-ID`.

### 401 — No API key was sent, or it is unknown, revoked or expired (`UNAUTHORIZED`).

Content type: `application/json`

Type: `Error`

- `error` (object, required)
  - `code` (string, required): Machine-readable code. Branch on this.
  - `message` (string, required): Human-readable explanation.
  - `request_id` (string): This request's id, also in `X-Request-ID`.

### 403 — The key lacks the scope this endpoint needs (`FORBIDDEN`).

Content type: `application/json`

Type: `Error`

- `error` (object, required)
  - `code` (string, required): Machine-readable code. Branch on this.
  - `message` (string, required): Human-readable explanation.
  - `request_id` (string): This request's id, also in `X-Request-ID`.

### 404 — No such item, or one the caller cannot see (`NOT_FOUND`).

Content type: `application/json`

Type: `Error`

- `error` (object, required)
  - `code` (string, required): Machine-readable code. Branch on this.
  - `message` (string, required): Human-readable explanation.
  - `request_id` (string): This request's id, also in `X-Request-ID`.

### 429 — Too many requests (`RATE_LIMITED`). Wait `Retry-After` seconds.

Headers:

- `Retry-After` (integer): Seconds to wait.

Content type: `application/json`

Type: `Error`

- `error` (object, required)
  - `code` (string, required): Machine-readable code. Branch on this.
  - `message` (string, required): Human-readable explanation.
  - `request_id` (string): This request's id, also in `X-Request-ID`.

### 500 — Something went wrong on EvoHub's side (`INTERNAL_ERROR`). Retry later.

Content type: `application/json`

Type: `Error`

- `error` (object, required)
  - `code` (string, required): Machine-readable code. Branch on this.
  - `message` (string, required): Human-readable explanation.
  - `request_id` (string): This request's id, also in `X-Request-ID`.

## Example request

```bash
curl -X PUT 'https://evohub.io/api/v1/pages/3f6c2a1e-8b4d-4f7a-9c21-5d0e7a9b1c42' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer <TOKEN>' \
  -d '{
  "name": "Acme Status",
  "theme": "dark",
  "logo_url": "https://assets.evohub.io/logos/acme.png",
  "is_public": true
}'
```
