API
The Watcher HTTP API gives you programmatic access to your deployment's recorded data and grading. You can query sessions, trajectories, and grades. You can ingest trajectories from your own tooling. You can integrate gateways through gateway hooks. You can run graders on demand, or request a Deep Review of a session (how). You can read or update organization settings. Set custom instructions for managed monitors through the monitor customization API. Some Analyzer administration is not on the API. API-key and member management are handled by the sign-in provider's own components. The Python SDK is a typed binding over this same API. Anything the SDK does, you can also do with plain HTTP requests. On proxy-mode deployments, the SDK authenticates through a pre-configured HTTP client (see the SDK page).
Base URL and versioning
The API is served by your Watcher deployment under the /api path, with
endpoints versioned under /v1:
https://<your-watcher-host>/api/v1/...
For a self-hosted deployment, that is the same hostname as your Analyzer. On
Apollo's hosted cloud, the base is https://app.apolloresearch.ai/api.
Authentication
How you authenticate depends on your deployment's authentication mode:
- SSO mode (Apollo cloud, and self-hosted in SSO mode): send an organization
API key in the
x-api-keyheader. Admins create and revoke API keys on the Analyzer's Organization page (see organization settings). The API also accepts the short-livedAuthorization: Bearertoken from a user's sign-in. Use an API key for unattended services. Local Python integrations can sign in through the browser without a Watcher client or reuse the installed Watcher sign-in, including token refresh. - Proxy mode (self-hosted behind your own auth proxy): there are no Watcher API keys. Requests authenticate with whatever your reverse proxy requires. This is exactly like every other request to the deployment.
curl -H "x-api-key: $WATCHER_API_KEY" \
https://watcher.example.com/api/v1/sessions
Session access
Admins receive all three session-read grants below. Org-viewers receive aggregate and findings grants. Users can read their own findings and content without a grant; API keys have no owner and need explicit grants. See organization roles.
Session findings access
sessions:findings:read:any permits browsing other users' sessions and tool
calls, including metadata, grades, and problem explanations. Grader outputs may
contain transcript excerpts; session summaries require content access.
GET /v1/sessions/{session_id}/tool-call-decision?tool_use_id=... returns a
call's recorded decision and grades with findings access. It always returns an
empty raw_tool_call and empty grade input_messages lists. has_result indicates
whether a tool response was recorded, without returning its contents.
Session content access
sessions:content:read:any grants access to other users' transcripts, messages,
raw tool payloads, and session summaries, including the Session detail narrative.
It works alone for known session URLs;
browsing other users' sessions and reading their findings require findings access.
The organization content policy
can suppress this grant, including for admins and API keys. Ownership and active
approvals still permit content reads. Read the flag through
GET /v1/organization/settings, which requires org:settings:read.
Set restrict_cross_user_session_content through
PATCH /v1/organization/settings, which requires org:settings:write.
An approved session-content request also permits the requesting user to read that session's detail, summaries, transcripts, and messages from reviewed_at until valid_until, unless revoked earlier. It grants no additional findings, aggregate, or browsing access. List previews and title searches continue to use ownership and role or credential grants.
GET /v1/users/me/session-content-access-requests lists only your own requests
in the current organization, including for admins. It accepts session_id,
status (pending, approved, denied, or revoked), limit, and offset, and returns
newest requests first. Approved history includes expired requests; check
valid_until. Set active_only=true for pending requests and currently valid
approvals. Credentials without a user identity receive HTTP 401.
POST /v1/users/me/session-content-access-requests with {"session_id": "<uuid>"}
creates a pending request for the signed-in user. Repeated submissions return
the existing pending request. Findings access is not required. Missing,
foreign, or scrubbed sessions return HTTP 404; already-readable content returns
HTTP 409. Submitting a request does not grant access.
Listing, reviewing, and revoking organization requests requires sessions:access-requests:review.
Admins receive it automatically; custom WorkOS roles can receive it explicitly.
Without it, these endpoints return HTTP 403.
GET /v1/session-content-access-requests lists organization requests.
It accepts limit, offset, and repeated status filters (for example,
?status=approved&status=denied). Responses include requester, reviewer, and revoker
identities, newest requests first. Approved results include expired approvals.
Use view=pending, view=active, or view=historical (denied, revoked or expired) to
filter before pagination. Responses also include organization-wide
pending_count and active_count, regardless of filters.
Signed-in reviewers act on a pending request with
PATCH /v1/session-content-access-requests/{request_id} and
{"status": "approved"} or {"status": "denied"}. Approval lasts eight hours
by default. An optional, timezone-aware valid_until must be in the future and
no more than eight hours after review; invalid expiries return HTTP 422.
Self-approval is allowed and records the reviewer. Completed decisions cannot
be changed (HTTP 409), and scrubbed content cannot be approved. Review credentials
without a user identity receive HTTP 401, even with the permission.
POST /v1/session-content-access-requests/{request_id}/revoke takes no body and
revokes an active approval. It requires the same permission and user identity as
review. The response includes revoked_at; organization listings also include
revoked_by_user. The original review and expiry are preserved. Missing or foreign
requests return HTTP 404; inactive or already revoked requests return HTTP 409.
Retrieving trajectory content or individual messages returns HTTP 404 when
content access is denied or the messages have been scrubbed. This applies to
truncated and full transcripts alike. Without content access, mixed responses
omit session summaries, including nested grade summaries, and return null for
raw tool-argument previews. Title searches match only sessions whose content
the caller can read.
Session aggregate access
GET /v1/sessions/aggregates requires sessions:aggregates:read:any.
Without it, requests receive HTTP 403, even when filtered to your own sessions.
The aggregate grant does not permit individual-session or transcript reads.
Omit user_id for organization-wide counts, trends, and risk metrics, or set
it to filter metrics to one owner within the organization.
Requests must include severity_threshold: low, medium, high, or
critical. For example:
curl -H "x-api-key: $WATCHER_API_KEY" \
'https://watcher.example.com/api/v1/sessions/aggregates?severity_threshold=critical'
For proxy mode, use the trusted role header described in guided setup.
Grading sessions
Users may grade their own stored sessions. For other users' sessions,
sessions:grade:any permits standard grading through POST /v1/monitors/{role}/grade
and POST /v1/sessions/{session_id}/deep-review, without content access.
POST /v1/grade runs caller-selected graders and requires content access as well,
even for shared or built-in graders. Admins receive the grading permission;
org-viewers and members may grade only their own sessions by default.
Results respect findings and content permissions. Missing, scrubbed, or unauthorized sessions return HTTP 404.
Grading supplied messages does not require session-read grants. Attaching those
results to a session requires ownership or sessions:write:any. That write grant
alone does not authorize grading stored transcripts. Automatic monitoring is
unaffected, and existing grader visibility and usage limits still apply.
Browsing the API
The API is described by an OpenAPI 3.1 document, openapi.json. The document is
maintained and versioned with the SDK. The spec is not currently published as a
standalone download.
The installed Python SDK is a complete, typed map of the same
surface. Every endpoint appears as a module under
watcher_sdk/_generated/api/<tag>/. Each client method wraps one endpoint.
Endpoints are grouped by tag: sessions, ingest, grade, monitors,
graders, hooks, organization, users, usage, tool-calls,
tool-call-decisions, auth, health, version.
Calling the API directly, note two things:
- Endpoint paths are relative to the
/apiserver prefix:/v1/sessionsishttps://<your-watcher-host>/api/v1/sessionson the wire. - The two security schemes (
ApiKeyAuth,BearerAuth) are the SSO-mode headers described above; in proxy mode your proxy's requirements apply instead.
The Python SDK
The Python SDK wraps this API with typed sync and async
clients: each of its methods calls one endpoint, and it adds retries with
backoff, auto-pagination, structured errors, and typed models on top. Its
base_url is the base URL above, /api prefix included. If you are working in
Python, start there; use the HTTP API directly from other languages or where a
dependency is unwanted.