Skip to main content
Working with an agent? Give them a link to this page as markdown.

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-key header. Admins create and revoke API keys on the Analyzer's Organization page (see organization settings). The API also accepts the short-lived Authorization: Bearer token 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 /api server prefix: /v1/sessions is https://<your-watcher-host>/api/v1/sessions on 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.