# REST API

> Each endpoint of the Checkend REST API: method, path, access, parameters, request body and response fields.

> **Note: Generated page**
> Generated from the Checkend repository at `ee1e2be` (`ee1e2be`) by `npm run sync`. Do not edit this page by hand.

The REST API is at `<public URL>/v1`. Send the token in a header: `Authorization: Bearer ce_...`. The web UI, MCP and `ce` use the same API. The OpenAPI document of this page is `internal/api/contract/openapi.json` in the repository.

Each endpoint lists its access: no token, an API token, or an API token with the `admin` scope. Where they exist, the page names the MCP tool and the `ce` command that do the same work.

## Admin

### GET /v1/audit

The audit log: each write by a token (sites, goals, tokens, annotations, findings, webhooks), with the actor, the scopes and the interface. Admin only.

**Access:** an API token with the `admin` scope · **CLI:** `ce audit`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `before` | query | string | no | an entry ID: only older entries (the next page) |
| `token` | query | string | no | a token ID: only the writes of this token |
| `action` | query | string | no | an action (finding.claim) or its first part (finding): only these writes |
| `limit` | query | integer | no | the most entries, 1 to 500 (default 100) |

**Responses:** `200`, and an error object for other codes.

**Response fields:** `entries` (object[]), `next` (string).

### GET /v1/health/detail

The health report of the server: disk and the disk budgets, the data folder, the GeoIP file, the DuckDB extensions, the event log and the writer lag, the backups, and the newest run and error of each job. Admin only.

**Access:** an API token with the `admin` scope · **CLI:** `ce health`

**Responses:** `200`, and an error object for other codes.

**Response fields:** `status` (string), `checked_at` (string), `version` (string), `checks` (object[]), `jobs` (object[]), `disk` (object), `event_log` (object), `backups` (object).

### GET /v1/projects

List the projects that the token can read, with the daily event limit and today's count.

**Access:** an API token with the scope that the summary names · **CLI:** `ce projects list`

**Responses:** `200`, and an error object for other codes.

**Response fields:** `projects` (object[]).

### PATCH /v1/projects/&#123;id&#125;

Set the daily event limit of a project. Admin only.

**Access:** an API token with the `admin` scope · **CLI:** `ce projects limit`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes | the project ID |

**Request body**

| Name | Type | Required | Description |
|---|---|---|---|
| `daily_event_limit` | integer | yes | the most events in one UTC day; 0 means no limit |

**Responses:** `200`, and an error object for other codes.

**Response fields:** `id` (string), `name` (string), `daily_event_limit` (integer), `events_today` (integer).

### GET /v1/retention

The raw-data retention of each module of the organization (default 24 months, decision D26), the oldest raw event and what stays (rollups and search rows). Admin only.

**Access:** an API token with the `admin` scope · **CLI:** `ce retention`

**Responses:** `200`, and an error object for other codes.

**Response fields:** `modules` (object[]).

### PATCH /v1/retention

Set the raw-data retention of a module in months (1 to 120). The nightly retention job deletes the older raw months as file deletes; the rollups and search rows stay. Admin only.

**Access:** an API token with the `admin` scope · **CLI:** `ce retention set`

**Request body**

| Name | Type | Required | Description |
|---|---|---|---|
| `module` | string | yes | the module, for example analytics |
| `raw_months` | integer | yes | months of raw events to keep, 1 to 120 (default 24) |

**Responses:** `200`, and an error object for other codes.

**Response fields:** `modules` (object[]).

## Analytics

### GET /v1/stats

Page views, visitors, top pages, top countries, conversions, revenue and goals of one site.

**Access:** an API token with the scope that the summary names · **CLI:** `ce query` · **MCP:** `query`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `site` | query | string | yes | the site domain, for example example.com |
| `period` | query | string | no | the period: 24h, 7d, 30d or 365d (default 30d) |

**Responses:** `200`, and an error object for other codes.

**Response fields:** `site` (string), `period` (string), `from` (string), `to` (string), `pageviews` (integer), `visitors` (integer), `top_pages` (object[]), `top_countries` (object[]), `top_sources` (object[]), `top_channels` (object[]), `data_until` (string), `sample_size` (integer), `events` (integer), `conversions` (integer), `conversion_rate` (number), `conversions_unit` (string), `visitors_note` (string), `conversions_note` (string), `revenue` (object[]), `goals` (object[]), `previous` (object).

### GET /v1/timeseries

Page views, visitors, conversions and revenue for each hour (24h) or each UTC day of one site.

**Access:** an API token with the scope that the summary names · **CLI:** `ce query --series` · **MCP:** `timeseries`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `site` | query | string | yes | the site domain, for example example.com |
| `period` | query | string | no | the period: 24h, 7d, 30d or 365d (default 30d) |
| `goal` | query | string | no | a goal ID: the conversions and the revenue of this goal only; all goals when empty |

**Responses:** `200`, and an error object for other codes.

**Response fields:** `site` (string), `period` (string), `interval` (string), `from` (string), `to` (string), `points` (object[]), `goal` (string), `conversions_unit` (string), `data_until` (string), `sample_size` (integer).

## Annotations

### GET /v1/sites/&#123;domain&#125;/annotations

List the annotations (changes and releases) of a site in a period that ends now, newest first. Needs read access. The brief has the same annotations.

**Access:** an API token with the scope that the summary names · **CLI:** `ce annotations list` · **MCP:** `get_brief`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `domain` | path | string | yes | the site domain, for example example.com |
| `period` | query | string | no | the period that ends now: 24h, 7d, 30d (default) or 365d |

**Responses:** `200`, and an error object for other codes.

**Response fields:** `site` (string), `from` (string), `to` (string), `annotations` (object[]).

### POST /v1/sites/&#123;domain&#125;/annotations

Record a change on a site at a time: an agent change, a release or a note, optionally for a finding. Needs write access to the project.

**Access:** an API token with the scope that the summary names · **CLI:** `ce annotate` · **MCP:** `annotate`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `domain` | path | string | yes | the site domain, for example example.com |

**Request body**

| Name | Type | Required | Description |
|---|---|---|---|
| `text` | string | yes | what changed, 1 to 500 characters, for example: Title changed on /pricing |
| `kind` | string | no | agent_change (default), release or note |
| `at` | string | no | the time of the change: RFC 3339 or a UTC date (2026-10-22); default now |
| `finding` | string | no | the ID of the finding that the change is for |
| `link` | string | no | an http or https URL about the change, for example the pull request |

**Responses:** `201`, and an error object for other codes.

**Response fields:** `id` (string), `site` (string), `at` (string), `kind` (string), `text` (string), `finding` (string), `link` (string), `actor` (object), `created_at` (string).

## Crawlers and logs

### GET /v1/sites/&#123;domain&#125;/crawlers

AI and search crawler hits of a site (GPTBot, ClaudeBot, PerplexityBot, Googlebot, Bingbot and others) from the pushed access logs: the hits of each bot, and the top pages with the hits of each bot.

**Access:** an API token with the scope that the summary names · **CLI:** `ce crawlers` · **MCP:** `ai_crawlers`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `domain` | path | string | yes | the site domain, for example example.com |
| `period` | query | string | no |  |
| `bot` | query | string | no |  |
| `limit` | query | integer | no |  |

**Responses:** `200`, and an error object for other codes.

**Response fields:** `site` (string), `period` (string), `from` (string), `to` (string), `data_until` (string), `sample_size` (integer), `bots` (object[]), `pages` (object[]), `notes` (string[]), `next` (string).

### POST /v1/sites/&#123;domain&#125;/logs

Push web server access log lines as text/plain (at most 10 MB): the Nginx or Apache combined format, or Caddy JSON. Checkend keeps only the hits of the known crawlers (the day, the page, the bot, the status; no IP address, no user agent). Needs write access to the site's project.

**Access:** an API token with the scope that the summary names · **CLI:** `ce logs push`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `domain` | path | string | yes | the site domain, for example example.com |

**Responses:** `200`, and an error object for other codes.

**Response fields:** `site` (string), `lines` (integer), `hits` (integer), `not_crawlers` (integer), `unparsed` (integer), `other_host` (integer), `too_old` (integer), `bots` (object[]), `from` (string), `to` (string), `next` (string).

## Device

### POST /v1/device

The device page of ce login: what a user code asks for (the token name and the scopes), and the scopes that the person can give. A person gets 5 wrong codes in 15 minutes. A web UI session only.

**Access:** an API token with the scope that the summary names

**Request body**

| Name | Type | Required | Description |
|---|---|---|---|
| `user_code` | string | yes |  |

**Responses:** `200`, and an error object for other codes.

**Response fields:** `user_code` (string), `client` (string), `name` (string), `requested` (string[]), `allowed` (string[]), `selected` (string[]), `role` (string), `email` (string), `expires_at` (string).

### POST /v1/device/decision

The device page of ce login: approve a user code with the chosen scopes (inside the role), or deny it. Then ce gets a token of the person. A web UI session only.

**Access:** an API token with the scope that the summary names

**Request body**

| Name | Type | Required | Description |
|---|---|---|---|
| `user_code` | string | yes |  |
| `approve` | boolean | yes |  |
| `scopes` | string[] | no |  |

**Responses:** `200`, and an error object for other codes.

**Response fields:** `approved` (boolean), `scopes` (string[]).

## Events

### POST /v1/events

Send one custom event from a server, for example a purchase. Needs write access to the site's project.

**Access:** an API token with the scope that the summary names · **CLI:** `ce event send`

**Request body**

| Name | Type | Required | Description |
|---|---|---|---|
| `site` | string | yes | the site domain, for example example.com |
| `name` | string | yes | the custom event name, for example Purchase |
| `url` | string | no | the absolute URL of the page, on the site domain; default https://<site>/ |
| `ts` | string | no | the event time in RFC 3339; the server time when empty |
| `vid` | string | no | a persistent visitor ID; used only in extended privacy mode |
| `props` | object | no | custom properties: at most 20 |
| `revenue` | object | no | the money value of the event |

**Responses:** `202`, and an error object for other codes.

**Response fields:** `id` (string), `dropped` (string).

## Findings

### GET /v1/brief

The brief of a site, a project or all readable sites: top changes with a significance test, open findings, annotations, outcomes and data dates.

**Access:** an API token with the scope that the summary names · **CLI:** `ce brief` · **MCP:** `get_brief`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `site` | query | string | no | a site domain; give a site or a project, or nothing for all readable sites |
| `project` | query | string | no | a project ID |
| `period` | query | string | no | the period that ends now: 24h, 7d (default), 30d or 365d |

**Responses:** `200`, and an error object for other codes.

**Response fields:** `version` (string), `site` (string), `project` (string), `sites` (string[]), `period` (string), `from` (string), `to` (string), `generated_at` (string), `top_changes` (object[]), `open_findings` (object[]), `annotations` (object[]), `outcomes` (object[]), `warnings` (string[]), `data_dates` (object[]), `sample_size` (integer).

### GET /v1/findings

List the findings of the readable sites, high priority first, with evidence, impact, priority, confidence and status. Filters: site, project, status, token (the name of the claimer), action and period.

**Access:** an API token with the scope that the summary names · **CLI:** `ce findings list` · **MCP:** `get_findings`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `site` | query | string | no | a site domain; all readable sites when empty |
| `project` | query | string | no | a project ID; all readable projects when empty |
| `status` | query | string | no | statuses, comma-separated, for example open,claimed; default: all |
| `limit` | query | integer | no | the most findings to return, 1 to 200 (default 50) |
| `token` | query | string | no | the name of the token that claimed the finding |
| `action` | query | string | no | action types, comma-separated, for example fix_redirect,investigate |
| `period` | query | string | no | only findings with a change in the period that ends now: 24h, 7d, 30d or 365d; default: all |

**Responses:** `200`, and an error object for other codes.

**Response fields:** `findings` (object[]).

### POST /v1/findings/run

Run the findings rules now for the sites of the organization, start measuring done findings, and set the outcomes of complete windows (the job also runs each hour). Admin only.

**Access:** an API token with the `admin` scope · **CLI:** `ce findings run`

**Responses:** `200`, and an error object for other codes.

**Response fields:** `sites` (integer), `created` (integer), `updated` (integer), `measuring` (integer), `outcomes` (integer), `data_until` (string), `skipped` (object[]).

### GET /v1/findings/&#123;id&#125;

Show one finding with its history (who changed the status, when and through which interface), its outcome and the outcome history.

**Access:** an API token with the scope that the summary names · **CLI:** `ce findings show` · **MCP:** `get_findings`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes | the finding ID |

**Responses:** `200`, and an error object for other codes.

**Response fields:** `id` (string), `site` (string), `project` (string), `type` (string), `action` (string), `page` (string), `query` (string), `summary` (string), `page_now` (object), `evidence` (object), `impact` (object), `priority` (string), `confidence` (string), `status` (string), `claimed_by` (object), `annotation` (string), `change_at` (string), `data_until` (string), `first_seen` (string), `last_seen` (string), `updated_at` (string), `history` (object[]), `outcome` (object), `outcome_history` (object[]).

### PATCH /v1/findings/&#123;id&#125;

Claim, finish (done, with an annotation), dismiss, reopen or remeasure (admin: compute the outcome again, with history) a finding. Needs write access to the project. dry_run checks only.

**Access:** an API token with the scope that the summary names · **CLI:** `ce findings claim done dismiss reopen remeasure` · **MCP:** `update_finding`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes | the finding ID |

**Request body**

| Name | Type | Required | Description |
|---|---|---|---|
| `action` | string | yes | claim, done, dismiss, reopen or remeasure (admin: compute the outcome again) |
| `note` | string | no | why, at most 500 characters; it goes to the history |
| `annotation` | string | no | done: the ID of the annotation of the change |
| `text` | string | no | done: the text of a new annotation of the change (kind agent_change) |
| `link` | string | no | done: a URL about the change for the new annotation, for example the pull request |
| `at` | string | no | done: the time of the change for the new annotation; default now |
| `dry_run` | boolean | no | true: check the change and return the result, but do not make it |

**Responses:** `200`, and an error object for other codes.

**Response fields:** `id` (string), `site` (string), `project` (string), `type` (string), `action` (string), `page` (string), `query` (string), `summary` (string), `page_now` (object), `evidence` (object), `impact` (object), `priority` (string), `confidence` (string), `status` (string), `claimed_by` (object), `annotation` (string), `change_at` (string), `data_until` (string), `first_seen` (string), `last_seen` (string), `updated_at` (string), `history` (object[]), `outcome` (object), `outcome_history` (object[]).

## Goals

### GET /v1/sites/&#123;domain&#125;/goals

List the goals of a site. Needs read access to the project.

**Access:** an API token with the scope that the summary names · **CLI:** `ce goals list` · **MCP:** `manage_goals`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `domain` | path | string | yes | the site domain, for example example.com |

**Responses:** `200`, and an error object for other codes.

**Response fields:** `site` (string), `goals` (object[]).

### POST /v1/sites/&#123;domain&#125;/goals

Add a goal to a site: a page path pattern or a custom event name. Needs write access to the project.

**Access:** an API token with the scope that the summary names · **CLI:** `ce goals add` · **MCP:** `manage_goals`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `domain` | path | string | yes | the site domain, for example example.com |

**Request body**

| Name | Type | Required | Description |
|---|---|---|---|
| `name` | string | no | the goal name, unique on the site; default: the event name or the page pattern |
| `page` | string | no | a page path pattern, for example /pricing or /blog/*; '*' matches any characters |
| `event` | string | no | a custom event name, for example Signup |

**Responses:** `201`, and an error object for other codes.

**Response fields:** `id` (string), `site` (string), `name` (string), `kind` (string), `page` (string), `event` (string), `created_at` (string).

### DELETE /v1/sites/&#123;domain&#125;/goals/&#123;id&#125;

Delete a goal of a site. Needs write access to the project. The events stay.

**Access:** an API token with the scope that the summary names · **CLI:** `ce goals delete` · **MCP:** `manage_goals`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `domain` | path | string | yes | the site domain, for example example.com |
| `id` | path | string | yes | the goal ID |

**Responses:** `204`, and an error object for other codes.

## IndexNow

### GET /v1/sites/&#123;domain&#125;/indexnow

The IndexNow state of a site: on or off, the key and the key file URL, the proxy snippets, the key check, the last submit and the queue of changed URLs.

**Access:** an API token with the scope that the summary names · **CLI:** `ce indexnow status` · **MCP:** `indexnow`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `domain` | path | string | yes | the site domain, for example example.com |

**Responses:** `200`, and an error object for other codes.

**Response fields:** `site` (string), `enabled` (boolean), `mode` (string), `key` (string), `key_url` (string), `served_at` (string), `verified_at` (string), `last_submit_at` (string), `last_status` (integer), `last_error` (string), `next_at` (string), `pending` (integer), `submitted_24h` (integer), `max_per_day` (integer), `endpoint` (string), `queue` (object[]), `proxy` (object[]), `queued` (integer), `next` (string).

### PATCH /v1/sites/&#123;domain&#125;/indexnow

Admin: turn IndexNow on or off for a site, set the key file mode (proxy or manual) or make a new key.

**Access:** an API token with the `admin` scope · **CLI:** `ce indexnow set`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `domain` | path | string | yes | the site domain, for example example.com |

**Request body**

| Name | Type | Required | Description |
|---|---|---|---|
| `enabled` | boolean | no | turn IndexNow on or off |
| `mode` | string | no | proxy (default: Checkend serves the key file through the site's proxy route) or manual (you host the key file) |
| `new_key` | boolean | no | make a new key (the old key file stops working) |

**Responses:** `200`, and an error object for other codes.

**Response fields:** `site` (string), `enabled` (boolean), `mode` (string), `key` (string), `key_url` (string), `served_at` (string), `verified_at` (string), `last_submit_at` (string), `last_status` (integer), `last_error` (string), `next_at` (string), `pending` (integer), `submitted_24h` (integer), `max_per_day` (integer), `endpoint` (string), `queue` (object[]), `proxy` (object[]), `queued` (integer), `next` (string).

### POST /v1/sites/&#123;domain&#125;/indexnow/submit

Add changed URLs of the site host to the IndexNow queue (at most 100). The job sends the queue every 10 minutes. Needs write access to the site's project.

**Access:** an API token with the scope that the summary names · **CLI:** `ce indexnow submit` · **MCP:** `indexnow`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `domain` | path | string | yes | the site domain, for example example.com |

**Request body**

| Name | Type | Required | Description |
|---|---|---|---|
| `urls` | string[] | yes | 1 to 100 absolute URLs on the site host, for example https://example.com/pricing |
| `reason` | string | no | why the pages changed, for example new pricing page |

**Responses:** `200`, and an error object for other codes.

**Response fields:** `site` (string), `enabled` (boolean), `mode` (string), `key` (string), `key_url` (string), `served_at` (string), `verified_at` (string), `last_submit_at` (string), `last_status` (integer), `last_error` (string), `next_at` (string), `pending` (integer), `submitted_24h` (integer), `max_per_day` (integer), `endpoint` (string), `queue` (object[]), `proxy` (object[]), `queued` (integer), `next` (string).

## Ingest

### POST /api/e

Send one page view or custom event. The tracking script calls this. Keyed by the site domain.

**Access:** no token

**Request body**

| Name | Type | Required | Description |
|---|---|---|---|
| `site` | string | yes | the site domain, for example example.com |
| `url` | string | yes | the absolute URL of the page |
| `referrer` | string | no | the absolute URL of the referrer |
| `ts` | string | no | the event time in RFC 3339; the server time when empty |
| `vid` | string | no | a persistent visitor ID; used only in extended privacy mode |
| `dnt` | boolean | no | true when the browser sends Do Not Track or Global Privacy Control; the server keeps the event in strict mode |
| `name` | string | no | the custom event name, for example Signup; empty for a page view |
| `props` | object | no | custom properties of a custom event: at most 20, keys of 1 to 64 letters, digits, '_', '-' or '.', values of 1 to 256 characters |
| `revenue` | object | no | the money value of a custom event |
| `vitals` | object | no | the web vitals of the page load: a report, not a page view |

**Responses:** `202`, and an error object for other codes.

**Response fields:** `id` (string), `dropped` (string).

## Install

### GET /v1/sites/&#123;domain&#125;/install

The install status of a site: waiting, test_only or receiving, with the first and the newest event of the last 7 days. The install token of the site, or a read token, can call it.

**Access:** an API token with the scope that the summary names · **CLI:** `ce sites verify` · **MCP:** `verify_install`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `domain` | path | string | yes | the site domain, for example example.com |

**Responses:** `200`, and an error object for other codes.

**Response fields:** `site` (string), `site_id` (string), `status` (string), `pageviews` (integer), `events` (integer), `test_events` (integer), `first_event_at` (string), `newest_event_at` (string), `newest_path` (string), `checked_at` (string), `test_event` (object), `next` (string).

### POST /v1/sites/&#123;domain&#125;/install-prompt

Make a new install prompt for a site, with a new install token (scope install:<site>, 24 hours). Needs write access. create_site also returns a prompt.

**Access:** an API token with the scope that the summary names · **CLI:** `ce sites prompt`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `domain` | path | string | yes | the site domain, for example example.com |

**Responses:** `201`, and an error object for other codes.

**Response fields:** `site` (string), `site_id` (string), `server_url` (string), `snippet` (string), `install_token` (string), `expires_at` (string), `prompt` (string), `recipes` (object[]), `proxy` (object[]), `goals` (object[]), `verify` (object).

### POST /v1/sites/&#123;domain&#125;/install/test

Send one test event (a custom event named "Checkend install test") to a site, to check that the server takes events. The install token of the site, or a write token.

**Access:** an API token with the scope that the summary names · **CLI:** `ce sites verify --send-test` · **MCP:** `verify_install`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `domain` | path | string | yes | the site domain, for example example.com |

**Responses:** `202`, and an error object for other codes.

**Response fields:** `id` (string), `dropped` (string).

## Oauth

### GET /v1/oauth/consent

The consent page: check an authorization request of an MCP client (the query of /oauth/authorize), and show the client, the redirect host, and the scopes that the person can give (never more than the role). A web UI session only.

**Access:** an API token with the scope that the summary names

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `response_type` | query | string | yes |  |
| `client_id` | query | string | yes |  |
| `redirect_uri` | query | string | no |  |
| `state` | query | string | no |  |
| `scope` | query | string | no |  |
| `code_challenge` | query | string | yes |  |
| `code_challenge_method` | query | string | yes |  |
| `resource` | query | string | no |  |

**Responses:** `200`, and an error object for other codes.

**Response fields:** `client` (object), `redirect_uri` (string), `redirect_host` (string), `loopback` (boolean), `requested` (string[]), `allowed` (string[]), `selected` (string[]), `role` (string), `resource` (string), `email` (string).

### POST /v1/oauth/consent

The consent page: approve an authorization request with the chosen scopes (inside the role), or deny it. The answer is the redirect to the client with the code or the error, the state and the issuer. A web UI session only.

**Access:** an API token with the scope that the summary names

**Request body**

| Name | Type | Required | Description |
|---|---|---|---|
| `response_type` | string | yes |  |
| `client_id` | string | yes |  |
| `redirect_uri` | string | no |  |
| `state` | string | no |  |
| `scope` | string | no |  |
| `code_challenge` | string | yes |  |
| `code_challenge_method` | string | yes |  |
| `resource` | string | no |  |
| `approve` | boolean | yes |  |
| `scopes` | string[] | no |  |

**Responses:** `200`, and an error object for other codes.

**Response fields:** `redirect_to` (string).

## People and invites

### POST /v1/invite

Public: the email address and the role of an invite link, and whether this server URL can use passkeys. The accept page reads it. Same origin only.

**Access:** no token

**Request body**

| Name | Type | Required | Description |
|---|---|---|---|
| `invite_token` | string | yes | the secret of the invite link (ceinv_...) |

**Responses:** `200`, and an error object for other codes.

**Response fields:** `email` (string), `role` (string), `expires_at` (string), `passkeys` (object).

### POST /v1/invite/passkey

Accept an invite in the web UI: check the new passkey, make the person with the role of the invite and start a web UI session (HttpOnly cookie). Same origin only.

**Access:** no token

**Request body**

| Name | Type | Required | Description |
|---|---|---|---|
| `invite_token` | string | yes |  |
| `challenge_id` | string | yes |  |
| `credential` | any | yes |  |

**Responses:** `201`, and an error object for other codes.

**Response fields:** `csrf_token` (string), `expires_at` (string), `me` (object).

### POST /v1/invite/passkey/options

Accept an invite in the web UI: check the link and start the passkey registration of the person. Same origin only.

**Access:** no token

**Request body**

| Name | Type | Required | Description |
|---|---|---|---|
| `invite_token` | string | yes | the secret of the invite link (ceinv_...) |

**Responses:** `200`, and an error object for other codes.

**Response fields:** `challenge_id` (string), `options` (any).

### POST /v1/invite/token

Accept an invite where passkeys cannot work (an IP address, or plain HTTP): make the person and an API token with the scopes of the role. The answer shows the secret one time.

**Access:** no token · **CLI:** `ce invites accept`

**Request body**

| Name | Type | Required | Description |
|---|---|---|---|
| `invite_token` | string | yes | the secret of the invite link (ceinv_...) |

**Responses:** `201`, and an error object for other codes.

**Response fields:** `token` (object), `secret` (string).

### GET /v1/invites

List the invites with their status: pending, accepted, expired or revoked. The link is not in the list: it shows one time. Admin only.

**Access:** an API token with the `admin` scope · **CLI:** `ce invites list`

**Responses:** `200`, and an error object for other codes.

**Response fields:** `invites` (object[]).

### POST /v1/invites

Invite a person with an email address and a role. The answer has the one-time link (7 days, single use); Checkend sends no email, so give the link to the person. Admin only.

**Access:** an API token with the `admin` scope · **CLI:** `ce people invite`

**Request body**

| Name | Type | Required | Description |
|---|---|---|---|
| `email` | string | yes | the email address of the person to invite |
| `role` | string | yes | admin, member or viewer |

**Responses:** `201`, and an error object for other codes.

**Response fields:** `invite` (object), `link` (string).

### DELETE /v1/invites/&#123;id&#125;

Revoke a pending invite: its link stops working. Admin only.

**Access:** an API token with the `admin` scope · **CLI:** `ce invites revoke`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes |  |

**Responses:** `204`, and an error object for other codes.

### GET /v1/people

List the people of the organization: email address, role (admin, member or viewer), last sign-in and passkey count. An admin and each person can read it; an agent token without a person cannot.

**Access:** an API token with the scope that the summary names · **CLI:** `ce people list`

**Responses:** `200`, and an error object for other codes.

**Response fields:** `people` (object[]).

### DELETE /v1/people/&#123;id&#125;

Remove a person: the sessions end at once, the API tokens are revoked and the passkeys are deleted. The last admin stays. Admin only.

**Access:** an API token with the `admin` scope · **CLI:** `ce people remove`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes |  |

**Responses:** `204`, and an error object for other codes.

### PATCH /v1/people/&#123;id&#125;

Change the role of a person. The sessions of the person have the new role on the next request; the person's tokens outside the new role are revoked. The last admin stays. Admin only.

**Access:** an API token with the `admin` scope · **CLI:** `ce people role`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes |  |

**Request body**

| Name | Type | Required | Description |
|---|---|---|---|
| `role` | string | yes | admin, member or viewer |

**Responses:** `200`, and an error object for other codes.

**Response fields:** `id` (string), `email` (string), `role` (string), `created_at` (string), `last_sign_in_at` (string), `passkeys` (integer), `you` (boolean).

## Reports

### GET /v1/report

One stored report (report_v1): by id, or the newest of a site, a project, a frequency and a date. format=md gives the report as Markdown text (text/markdown) from a fixed template. Needs read access.

**Access:** an API token with the scope that the summary names · **CLI:** `ce report show` · **MCP:** `get_report`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | query | string | no | a report ID; without it, the newest report that matches the other inputs |
| `site` | query | string | no | a site domain: the reports of this site |
| `project` | query | string | no | a project ID: the project reports (all sites) of this project |
| `frequency` | query | string | no | daily, weekly or monthly |
| `date` | query | string | no | a local date (YYYY-MM-DD): the report whose window has this day |
| `format` | query | string | no | json (default) or md: the report also as Markdown text from a fixed template, to paste |

**Responses:** `200`, and an error object for other codes.

**Response fields:** `version` (string), `id` (string), `title` (string), `site` (string), `project` (string), `sites` (string[]), `schedule` (string), `frequency` (string), `time_zone` (string), `window` (object), `previous` (object), `summary` (string[]), `warnings` (string[]), `site_reports` (object[]), `findings` (object), `outcomes` (object), `annotations` (object[]), `data_dates` (object[]), `sample_size` (integer), `generated_at` (string), `created_by` (string).

### GET /v1/report-schedules

List the report schedules of the projects that the token can read, with the next run and its window.

**Access:** an API token with the scope that the summary names · **CLI:** `ce report schedules list`

**Responses:** `200`, and an error object for other codes.

**Response fields:** `schedules` (object[]).

### POST /v1/report-schedules

Add a report schedule of a site or a project: daily, weekly (a weekday) or monthly (the first day), at a local hour of a time zone. The job makes each report one time and sends report.ready to the webhooks that want it. Needs write access (Admin or Member).

**Access:** an API token with the scope that the summary names · **CLI:** `ce report schedules add`

**Request body**

| Name | Type | Required | Description |
|---|---|---|---|
| `site` | string | no | a site domain; give a site or a project |
| `project` | string | no | a project ID: a report of all sites of the project |
| `frequency` | string | yes | daily, weekly or monthly |
| `weekday` | string | no | weekly: monday (default) to sunday |
| `hour` | integer | no | the local hour of the report, 0 to 23 (default 6) |
| `time_zone` | string | no | an IANA time zone, for example Europe/Berlin; default UTC |
| `dry_run` | boolean | no | true: check the schedule and return it, but do not store it |

**Responses:** `201`, and an error object for other codes.

**Response fields:** `id` (string), `site` (string), `project` (string), `frequency` (string), `weekday` (string), `hour` (integer), `time_zone` (string), `next_run_at` (string), `next_window` (object), `created_by` (string), `created_at` (string).

### DELETE /v1/report-schedules/&#123;id&#125;

Delete a report schedule. Its reports stay until the retention (13 months) deletes them. Needs write access (Admin or Member).

**Access:** an API token with the scope that the summary names · **CLI:** `ce report schedules delete`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes | the schedule ID |

**Responses:** `204`, and an error object for other codes.

### PATCH /v1/report-schedules/&#123;id&#125;

Change the frequency, the weekday, the hour or the time zone of a report schedule. Needs write access (Admin or Member).

**Access:** an API token with the scope that the summary names · **CLI:** `ce report schedules set`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes | the schedule ID |

**Request body**

| Name | Type | Required | Description |
|---|---|---|---|
| `frequency` | string | no | daily, weekly or monthly |
| `weekday` | string | no | weekly: monday to sunday |
| `hour` | integer | no | the local hour, 0 to 23 |
| `time_zone` | string | no | an IANA time zone |
| `dry_run` | boolean | no | true: check the change and return it, but do not make it |

**Responses:** `200`, and an error object for other codes.

**Response fields:** `id` (string), `site` (string), `project` (string), `frequency` (string), `weekday` (string), `hour` (integer), `time_zone` (string), `next_run_at` (string), `next_window` (object), `created_by` (string), `created_at` (string).

### GET /v1/reports

List the stored reports that the token can read, newest first, in pages (before). Filters: site, project (the project reports), frequency.

**Access:** an API token with the scope that the summary names · **CLI:** `ce report list` · **MCP:** `get_report`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `site` | query | string | no | a site domain: only the reports of this site |
| `project` | query | string | no | a project ID: only the project reports (all sites) of this project |
| `frequency` | query | string | no | daily, weekly or monthly |
| `before` | query | string | no | a report ID: only older reports (the next page) |
| `limit` | query | integer | no | the most reports, 1 to 100 (default 20) |

**Responses:** `200`, and an error object for other codes.

**Response fields:** `reports` (object[]), `next` (string).

### POST /v1/reports

Make a report now of the newest complete window (daily: yesterday; weekly: the 7 days before today; monthly: the month before), in a time zone, and store it. Needs write access. Sends no webhook. dry_run returns only the window.

**Access:** an API token with the scope that the summary names · **CLI:** `ce report run`

**Request body**

| Name | Type | Required | Description |
|---|---|---|---|
| `site` | string | no | a site domain; give a site or a project |
| `project` | string | no | a project ID: a report of all sites of the project |
| `frequency` | string | no | daily (yesterday), weekly (the 7 days before today; default) or monthly (the month before) |
| `time_zone` | string | no | an IANA time zone, for example Europe/Berlin; default UTC |
| `schedule` | string | no | a schedule ID: use its site or project, frequency and time zone |
| `dry_run` | boolean | no | true: check the request and return the window, but make no report |

**Responses:** `201`, and an error object for other codes.

**Response fields:** `window` (object), `dry_run` (boolean), `report` (object).

## Search

### GET /v1/search

Search Console and Bing rows of a site by query or by page: clicks, impressions, CTR and position, joined to the Checkend page views, visitors and conversions of each page. Needs read access.

**Access:** an API token with the scope that the summary names · **CLI:** `ce search` · **MCP:** `search_performance`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `site` | query | string | yes | the site domain, for example example.com |
| `period` | query | string | no | 7d, 28d (default), 90d or 365d; the period ends at the newest search date |
| `by` | query | string | no | query (default) or page |
| `position` | query | string | no | keep rows with an average position in this range, for example 8-20 (striking distance) |
| `source` | query | string | no | google, bing or all (default) |
| `query` | query | string | no | keep rows whose query contains this text |
| `page` | query | string | no | keep rows whose page URL contains this text |
| `limit` | query | integer | no | the most rows (default 50, at most 500) |

**Responses:** `200`, and an error object for other codes.

**Response fields:** `site` (string), `period` (string), `by` (string), `source` (string), `from` (string), `to` (string), `totals` (object), `previous` (object), `rows` (object[]), `data_until` (string), `sample_size` (integer), `connections` (object[]), `conversions_unit` (string), `notes` (string[]), `next` (string).

### GET /v1/search/oauth/callback

The OAuth redirect URI of Search Console. Google sends the browser here after the consent page; Checkend checks the state, stores the refresh token encrypted and redirects to the Search tab.

**Access:** no token

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `code` | query | string | no | the authorization code |
| `state` | query | string | yes | the state of the flow |
| `error` | query | string | no | the error of the consent page, for example access_denied |

**Responses:** `302`, and an error object for other codes.

### GET /v1/sites/&#123;domain&#125;/pages

What the crawler found on the pages of a site: title, meta description, H1, canonical URL, indexability, and the URL Inspection result. Needs read access.

**Access:** an API token with the scope that the summary names · **CLI:** `ce pages` · **MCP:** `get_page`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `domain` | path | string | yes | the site domain, for example example.com |
| `path` | query | string | no | one page path, for example /pricing; all crawled pages when empty |

**Responses:** `200`, and an error object for other codes.

**Response fields:** `site` (string), `pages` (object[]), `user_agent` (string), `next` (string).

### GET /v1/sites/&#123;domain&#125;/search/connections

The Search Console and Bing connection of a site: status, property, the synced dates and the last error with the next step. Needs read access.

**Access:** an API token with the scope that the summary names · **CLI:** `ce search status` · **MCP:** `connect_search_console`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `domain` | path | string | yes | the site domain, for example example.com |

**Responses:** `200`, and an error object for other codes.

**Response fields:** `site` (string), `connections` (object[]), `google_client` (boolean), `redirect_url` (string), `dev` (boolean).

### POST /v1/sites/&#123;domain&#125;/search/connections

Connect Search Console (google: returns the consent page URL for a person to open) or Bing Webmaster Tools (bing: give the API key). Needs write access to the project.

**Access:** an API token with the scope that the summary names · **CLI:** `ce search connect` · **MCP:** `connect_search_console`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `domain` | path | string | yes | the site domain, for example example.com |

**Request body**

| Name | Type | Required | Description |
|---|---|---|---|
| `source` | string | yes | google (Search Console) or bing (Bing Webmaster Tools) |
| `property` | string | no | google: sc-domain:example.com (domain property) or https://example.com/ (URL-prefix property); bing: the site URL, for example https://example.com/; default: sc-domain:<site> (google) or https://<site>/ (bing) |
| `api_key` | string | no | bing only: the API key from Bing Webmaster Tools (Settings, API Access); Checkend stores it encrypted |

**Responses:** `201`, and an error object for other codes.

**Response fields:** `site` (string), `connection` (object), `authorize_url` (string), `expires_at` (string), `next` (string).

### DELETE /v1/sites/&#123;domain&#125;/search/connections/&#123;source&#125;

Disconnect a search source: delete the stored token or API key (and revoke the Google token). The synced rows stay. Needs write access to the project.

**Access:** an API token with the scope that the summary names · **CLI:** `ce search disconnect` · **MCP:** `connect_search_console`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `domain` | path | string | yes | the site domain, for example example.com |
| `source` | path | string | yes | google or bing |

**Responses:** `204`, and an error object for other codes.

### POST /v1/sites/&#123;domain&#125;/search/sync

Sync the search sources of a site now (the job also runs each hour). Needs write access to the project.

**Access:** an API token with the scope that the summary names · **CLI:** `ce search sync` · **MCP:** `connect_search_console`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `domain` | path | string | yes | the site domain, for example example.com |

**Responses:** `200`, and an error object for other codes.

**Response fields:** `site` (string), `synced` (integer), `failed` (integer), `rows` (integer), `inspected` (integer), `connections` (object[]).

## Sign-in and setup

### DELETE /v1/session

Web UI sign-out: end the session of the cookie and clear the cookie.

**Access:** an API token with the scope that the summary names

**Responses:** `204`, and an error object for other codes.

### GET /v1/session

Show the web UI session of the cookie, with its CSRF token. Only for a session cookie.

**Access:** an API token with the scope that the summary names

**Responses:** `200`, and an error object for other codes.

**Response fields:** `csrf_token` (string), `expires_at` (string), `me` (object).

### POST /v1/session

Web UI sign-in: check an API token and set an HttpOnly session cookie. Needs Content-Type: application/json.

**Access:** no token

**Request body**

| Name | Type | Required | Description |
|---|---|---|---|
| `token` | string | yes | an API token (ce_...); the web UI sign-in page sends it |

**Responses:** `201`, and an error object for other codes.

**Response fields:** `csrf_token` (string), `expires_at` (string), `me` (object).

### POST /v1/session/passkey

Web UI sign-in with a passkey: check the answer of the browser and start a web UI session (HttpOnly cookie). Same origin only.

**Access:** no token

**Request body**

| Name | Type | Required | Description |
|---|---|---|---|
| `challenge_id` | string | yes |  |
| `credential` | any | yes |  |

**Responses:** `201`, and an error object for other codes.

**Response fields:** `csrf_token` (string), `expires_at` (string), `me` (object).

### POST /v1/session/passkey/options

Web UI sign-in with a passkey: start the ceremony (a discoverable passkey: no email address). Same origin only.

**Access:** no token

**Responses:** `200`, and an error object for other codes.

**Response fields:** `challenge_id` (string), `options` (any).

### GET /v1/setup

Public: is the first admin still to make, and can this server URL use passkeys (with the reason when not)? The setup and sign-in pages read it.

**Access:** no token

**Responses:** `200`, and an error object for other codes.

**Response fields:** `setup_needed` (boolean), `passkeys` (object), `public_url` (string), `mcp_url` (string), `version` (string).

### POST /v1/setup

First boot: make the first admin with the one-time setup token. Returns an admin API token.

**Access:** no token · **CLI:** `ce setup`

**Request body**

| Name | Type | Required | Description |
|---|---|---|---|
| `setup_token` | string | yes | the one-time setup token that the server printed at first start |
| `email` | string | yes | the email address of the first admin |

**Responses:** `201`, and an error object for other codes.

**Response fields:** `token` (object), `secret` (string).

### POST /v1/setup/passkey

First boot in the web UI: check the new passkey, make the first admin and start a web UI session (HttpOnly cookie). Same origin only.

**Access:** no token

**Request body**

| Name | Type | Required | Description |
|---|---|---|---|
| `setup_token` | string | yes |  |
| `challenge_id` | string | yes |  |
| `credential` | any | yes |  |

**Responses:** `201`, and an error object for other codes.

**Response fields:** `csrf_token` (string), `expires_at` (string), `me` (object).

### POST /v1/setup/passkey/options

First boot in the web UI: check the setup token and start the passkey registration of the first admin. Same origin only.

**Access:** no token

**Request body**

| Name | Type | Required | Description |
|---|---|---|---|
| `setup_token` | string | yes | the one-time setup token from the setup URL |
| `email` | string | yes | the email address of the first admin |

**Responses:** `200`, and an error object for other codes.

**Response fields:** `challenge_id` (string), `options` (any).

## Sites

### GET /v1/sites

List the sites that the token can read.

**Access:** an API token with the scope that the summary names · **CLI:** `ce sites list` · **MCP:** `list_sites`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `project` | query | string | no | a project ID; all readable projects when empty |

**Responses:** `200`, and an error object for other codes.

**Response fields:** `sites` (object[]).

### POST /v1/sites

Create a site. Needs write access to the project. Returns the script snippet.

**Access:** an API token with the scope that the summary names · **CLI:** `ce sites add` · **MCP:** `create_site`

**Request body**

| Name | Type | Required | Description |
|---|---|---|---|
| `domain` | string | yes | the site domain, for example example.com |
| `project` | string | no | the project ID; the default project when empty |
| `privacy_mode` | string | no | strict, standard (default) or extended |

**Responses:** `201`, and an error object for other codes.

**Response fields:** `id` (string), `project` (string), `domain` (string), `privacy_mode` (string), `outcome_mde` (number), `created_at` (string), `snippet` (string), `install` (object).

### DELETE /v1/sites/&#123;domain&#125;

Delete a site. Needs write access to the project. The raw events stay until retention deletes them.

**Access:** an API token with the scope that the summary names · **CLI:** `ce sites delete`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `domain` | path | string | yes | the site domain, for example example.com |

**Responses:** `204`, and an error object for other codes.

### PATCH /v1/sites/&#123;domain&#125;

Change the privacy mode of a site (needs write access to the project) or its outcome sensitivity, outcome_mde (admin only, decision D52: applies to new outcomes).

**Access:** an API token with the scope that the summary names · **CLI:** `ce sites set`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `domain` | path | string | yes | the site domain, for example example.com |

**Request body**

| Name | Type | Required | Description |
|---|---|---|---|
| `privacy_mode` | string | no | strict, standard or extended; empty: no change |
| `outcome_mde` | number | no | admin only: the outcome sensitivity, a relative change from 0.05 (5 %) to 0.5 (50 %); empty: no change |

**Responses:** `200`, and an error object for other codes.

**Response fields:** `id` (string), `project` (string), `domain` (string), `privacy_mode` (string), `outcome_mde` (number), `created_at` (string), `snippet` (string), `install` (object).

## Tokens

### GET /v1/tokens

List the API tokens of the organization (admin), or the own tokens of the person of the token (member or viewer).

**Access:** an API token with the scope that the summary names · **CLI:** `ce tokens list`

**Responses:** `200`, and an error object for other codes.

**Response fields:** `tokens` (object[]).

### POST /v1/tokens

Create an API token. The answer shows the secret one time. An admin can give any scope; a person can make an own token with scopes inside the role (D56). No token can make a token with more access than its own.

**Access:** an API token with the scope that the summary names · **CLI:** `ce tokens create`

**Request body**

| Name | Type | Required | Description |
|---|---|---|---|
| `name` | string | yes | a name that tells people what uses the token |
| `scopes` | string[] | yes | admin, read:*, write:*, read:<project> or write:<project> |

**Responses:** `201`, and an error object for other codes.

**Response fields:** `token` (object), `secret` (string).

### DELETE /v1/tokens/&#123;id&#125;

Revoke an API token: any token of the organization (admin), or an own token of the person.

**Access:** an API token with the scope that the summary names · **CLI:** `ce tokens revoke`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes | the token ID |

**Responses:** `204`, and an error object for other codes.

## Web vitals

### GET /v1/sites/&#123;domain&#125;/vitals

Web vitals of a site: the p75 of LCP, INP, CLS and TTFB for the site and its top pages, with n, the web.dev rating and the share of good loads.

**Access:** an API token with the scope that the summary names · **CLI:** `ce vitals` · **MCP:** `web_vitals`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `domain` | path | string | yes | the site domain, for example example.com |
| `period` | query | string | no |  |
| `path` | query | string | no |  |
| `limit` | query | integer | no |  |

**Responses:** `200`, and an error object for other codes.

**Response fields:** `site` (string), `period` (string), `from` (string), `to` (string), `data_until` (string), `sample_size` (integer), `metrics` (object[]), `pages` (object[]), `thresholds` (object[]), `notes` (string[]), `next` (string).

## Webhooks

### GET /v1/webhooks

List the webhooks of the organization, without the secrets. Admin only.

**Access:** an API token with the `admin` scope · **CLI:** `ce webhooks list`

**Responses:** `200`, and an error object for other codes.

**Response fields:** `webhooks` (object[]).

### POST /v1/webhooks

Add a webhook URL for finding.created, finding.updated, annotation.created, disk.pressure and report.ready. The answer shows the signing secret one time. Admin only.

**Access:** an API token with the `admin` scope · **CLI:** `ce webhooks add`

**Request body**

| Name | Type | Required | Description |
|---|---|---|---|
| `url` | string | yes | an http or https URL that gets the POST requests |
| `events` | string[] | no | finding.created, finding.updated, annotation.created, disk.pressure, report.ready; default all |

**Responses:** `201`, and an error object for other codes.

**Response fields:** `webhook` (object), `secret` (string).

### DELETE /v1/webhooks/&#123;id&#125;

Delete a webhook and its delivery log. Admin only.

**Access:** an API token with the `admin` scope · **CLI:** `ce webhooks delete`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes | the webhook ID |

**Responses:** `204`, and an error object for other codes.

### GET /v1/webhooks/&#123;id&#125;/deliveries

The delivery log of a webhook: the newest 100 deliveries with status, attempts and the last answer. Admin only.

**Access:** an API token with the `admin` scope · **CLI:** `ce webhooks deliveries`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes | the webhook ID |

**Responses:** `200`, and an error object for other codes.

**Response fields:** `deliveries` (object[]).

### POST /v1/webhooks/&#123;id&#125;/test

Send one ping event to a webhook now, and return the delivery with the result. Admin only.

**Access:** an API token with the `admin` scope · **CLI:** `ce webhooks test`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes | the webhook ID |

**Responses:** `200`, and an error object for other codes.

**Response fields:** `id` (string), `webhook` (string), `event` (string), `event_id` (string), `status` (string), `attempts` (integer), `next_attempt_at` (string), `code` (integer), `error` (string), `created_at` (string), `delivered_at` (string).

## Your account

### GET /v1/me

Show the token that makes the request.

**Access:** an API token with the scope that the summary names · **CLI:** `ce login`

**Responses:** `200`, and an error object for other codes.

**Response fields:** `token_id` (string), `token_name` (string), `organization` (string), `scopes` (string[]), `role` (string).

### GET /v1/me/passkeys

The passkeys of the person of the token (not of an agent token), and whether this server URL can use passkeys.

**Access:** an API token with the scope that the summary names · **CLI:** `ce passkeys list`

**Responses:** `200`, and an error object for other codes.

**Response fields:** `email` (string), `passkeys` (object[]), `available` (boolean), `reason` (string).

### POST /v1/me/passkeys

Finish the registration of a passkey. A person without a web sign-in also gets one, so that the passkey signs in to the web UI.

**Access:** an API token with the scope that the summary names

**Request body**

| Name | Type | Required | Description |
|---|---|---|---|
| `challenge_id` | string | yes |  |
| `credential` | any | yes |  |

**Responses:** `201`, and an error object for other codes.

**Response fields:** `email` (string), `passkeys` (object[]), `available` (boolean), `reason` (string).

### POST /v1/me/passkeys/options

Start the registration of a new passkey for the person of the token (for example an admin that ce setup made). The browser answers with POST /v1/me/passkeys.

**Access:** an API token with the scope that the summary names

**Responses:** `200`, and an error object for other codes.

**Response fields:** `challenge_id` (string), `options` (any).

### DELETE /v1/me/passkeys/&#123;id&#125;

Delete a passkey of the person of the token.

**Access:** an API token with the scope that the summary names · **CLI:** `ce passkeys delete`

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes |  |

**Responses:** `204`, and an error object for other codes.

### GET /v1/me/settings

The web UI settings of the caller (the Agent work layout): of the person for a passkey sign-in, else of the token. Also the defaults of the organization: the new-org state and the layout default with its reason (decision D47).

**Access:** an API token with the scope that the summary names

**Responses:** `200`, and an error object for other codes.

**Response fields:** `work_view` (string), `work_view_saved` (boolean), `work_view_for` (string), `work_view_default` (string), `work_view_reason` (string), `new_to_agents` (boolean), `agent_changes` (integer), `write_tokens` (integer), `scheduled_agents` (integer), `sites` (integer).

### PATCH /v1/me/settings

Save a web UI setting of the caller: the Agent work layout (queue or table). A passkey sign-in saves it for the person, an API token for the token. Each token can do this, viewers too.

**Access:** an API token with the scope that the summary names

**Request body**

| Name | Type | Required | Description |
|---|---|---|---|
| `work_view` | string | yes | the layout of the Agent work page: queue or table |

**Responses:** `200`, and an error object for other codes.

**Response fields:** `work_view` (string), `work_view_saved` (boolean), `work_view_for` (string), `work_view_default` (string), `work_view_reason` (string), `new_to_agents` (boolean), `agent_changes` (integer), `write_tokens` (integer), `scheduled_agents` (integer), `sites` (integer).
