Skip to content

API Documentation

Michael Marras edited this page Jun 8, 2026 · 1 revision

API Documentation

The WatchTower API is served by the reporting worker (workers/api). All endpoints are prefixed with /api and require the X-Watchtower-Auth header on every request. Authenticated endpoints also require a valid session cookie (wt_session).


Authentication

WatchTower uses HMAC-signed session cookies (see ADR-0005).

  • Login via POST /api/login to receive a wt_session cookie (7-day expiry).
  • Every request must include the X-Watchtower-Auth header — requests without it are rejected with 403.
  • Authenticated endpoints check for a valid, non-expired session. Missing or invalid sessions return 401.

Endpoints

POST /api/login

Authenticates a user and sets a signed session cookie.

Body

{
  "email": "user@example.com",
  "password": "your_password"
}

Response 200

{
  "user": { "id": "user_id", "email": "user@example.com" },
  "projects": [
    { "project_id": "wt_abcd1234", "name": "My App" }
  ]
}

Errors

Status Error Reason
400 bad_json Request body is not valid JSON
400 missing_fields email or password missing
401 invalid_credentials Email not found or password incorrect

POST /api/logout

Revokes the current session server-side and clears the cookie.

Response 200

{ "ok": true }

GET /api/events

Returns a paginated list of events for a project.

Query Parameters

Parameter Required Default Description
project_id true Your WatchTower project ID
type false error Event type: error, performance, feedback, deploy, pageview
since false 24h Start of window — relative shorthand (<n>h, <n>d) or ISO-8601
until false now End of window — ISO-8601
limit false 50 Number of results (1–200)
cursor false Pagination cursor from a previous response's next_cursor

Response 200

{
  "events": [ { "event_id": "...", "event_type": "error", "timestamp": "...", "..." : "..." } ],
  "next_cursor": "base64url_cursor_or_null",
  "has_more": true
}

Errors

Status Error Reason
400 missing_param project_id not provided
400 invalid_param Bad type, since, until, limit, or cursor
403 forbidden Project not owned by session user
404 unknown_project Project ID does not exist

GET /api/events/:event_id

Returns a single event by ID, plus the nearest correlated deploy event.

Response 200

{
  "event": { "event_id": "...", "event_type": "error", "..." : "..." },
  "correlated_deploy": { "event_id": "...", "event_type": "deploy", "..." : "..." }
}

correlated_deploy is null if no deploy is found at or before the event's timestamp.

Errors

Status Error Reason
403 forbidden Project not owned by session user
404 not_found Event ID does not exist

GET /api/summary

Returns aggregated counts and timeseries for the dashboard overview.

Query Parameters

Parameter Required Description
project_id true Your WatchTower project ID
window true Time window for aggregation (e.g. 24h, 7d)

Response 200

Includes error/feedback timeseries buckets, p75 Web Vitals per metric, and a site_status derived from recent error count.

Errors

Status Error Reason
400 missing_param / invalid_param Bad or missing query params
403 forbidden Project not owned by session user
404 unknown_project Project ID does not exist

POST /api/projects

Creates a new project.

Body

{
  "project_id": "wt_abcd1234",
  "name": "My App"
}

Response 201

{
  "project": { "project_id": "wt_abcd1234", "name": "My App" }
}

Errors

Status Error Reason
400 bad_json Request body is not valid JSON
400 missing_fields project_id or name missing
409 project_already_exists project_id is already taken

GET /api/projects

Lists all projects owned by the session user.

Response 200

{
  "projects": [
    { "project_id": "wt_abcd1234", "name": "My App", "created_at": "..." }
  ]
}

PUT /api/projects

Updates the name of an existing project.

Body

{
  "project_id": "wt_abcd1234",
  "name": "New Name"
}

Response 200

{
  "project": { "project_id": "wt_abcd1234", "name": "New Name" }
}

Errors

Status Error Reason
400 bad_json Request body is not valid JSON
400 missing_fields project_id or name missing
404 project_not_found Project ID does not exist

DELETE /api/projects/:project_id

Deletes a project by ID.

Response 200

{
  "project": { "project_id": "wt_abcd1234" }
}

Errors

Status Error Reason
404 project_not_found Project ID does not exist

Pagination

GET /api/events uses cursor-based pagination. When has_more is true, pass the returned next_cursor value as the cursor parameter in your next request. Cursors are scoped to the same since/until window — reusing a cursor with a different window will return a 400.


Common Error Responses

Status Error Reason
401 unauthorized Missing or expired session
403 missing_auth_header X-Watchtower-Auth header not present
404 not_found Route does not exist

Clone this wiki locally