Skip to content

HTTP routes

All routes registered by the Opslane API (packages/ingestion/handler/routes.go). Auth column legend: none (public), poll token (X-Opslane-Poll-Token for one agent setup session), SDK (X-API-Key project-scoped public ingest key; rate-limited per project, and origin-gated on browser requests), and session (signed-in dashboard session).

These are curated tables, not a stability contract. The API is early-stage and may change. The drift check fails the repository test gate (pnpm test, which CI runs) if this page and routes.go disagree.

MethodPathAuthPurpose
GET/healthnoneLiveness + dependency checks
GET/metricsnoneInternal metrics
POST/auth/refreshnoneRotate session tokens
GET/auth/confignoneDiscover embedded sign-in, sign-up, and password-reset capabilities
POST/auth/passwordnoneSign in with provider-managed email and password; issues local session cookies
POST/auth/signupnoneCreate a provider account and begin required email verification
POST/auth/verify-emailnoneComplete email verification and issue local session cookies
POST/auth/oauth/verify-emailflow cookie + same originComplete a hosted OAuth email challenge and resume sign-in
POST/auth/password/forgotnoneSend a password-reset email with an enumeration-safe response
POST/auth/password/resetnoneSet a new password from a reset token and revoke local refresh sessions
GET/auth/loginnoneBegin the configured identity-provider sign-in
GET/auth/githubnoneCompatibility redirect to /auth/login
GET/auth/callbacknoneConfigured identity-provider callback
GET/auth/github/callbacknoneCompatibility callback alias for existing GitHub App configurations
GET+POST/oauth/authorizenoneBegin an authorization request using PKCE
POST/oauth/tokennoneExchange a PKCE authorization code for a session token
POST/api/v1/agent/setupnoneRegister a two-hour setup session with project_name, optional agent_name and git_remote; return the approval link and poll token
GET/api/v1/agent/poll/{sessionID}poll tokenRead approval status, approved keys, and server facts; wait=0..30 long-polls approval, or the first event with until=event
GET/agent/auth/{sessionID}noneRedirect to the dashboard approval page; expired links return 410
POST/api/v1/github/webhookHMACReceive GitHub pull_request and default-branch push events; both require X-GitHub-Delivery (400 without it). State-based installation and installation_repositories events keep installation records current without a delivery ID.
POST/mcpMCP key in Authorization: Bearer ...Call the remote MCP tools for one project

Agent setup uses normal dashboard sign-in and an explicit approval. Approval creates or attaches a project and seals ingest, MCP, and source-map keys to the session. GitHub is an optional later integration. The agent uses only X-Opslane-Poll-Token for polling and session actions; expired sessions return 410 before facts or keys. Agent responses use Cache-Control: no-store.

MethodPathAuthPurpose
GET/api/v1/agent/approve/{sessionID}sessionRead proposed setup, available projects, suggested match, and bound project progress
POST/api/v1/agent/approve/{sessionID}session; admin on cloudApprove a new project or existing_project_id owned by the active organization
POST/api/v1/agent/approve/{sessionID}/denysession; admin on cloudDecline a pending setup
POST/api/v1/agent/github/{sessionID}/install-urlsession; admin on cloudCreate a GitHub App installation URL and callback state for the session’s organization
GET/api/v1/agent/poll/{sessionID}/statepoll tokenRead server facts and reported progress; wait=0..30, until=event, github, slack, or change (default)
POST/api/v1/agent/poll/{sessionID}/githubpoll tokenValidate and attach {repo}. Errors include 400 repo_not_in_installation with add_repo_url, 400 github_not_installed with github_connect_url, 409 github_installation_gone after retirement, and 503 github_unreachable with Retry-After.
POST/api/v1/agent/poll/{sessionID}/slackpoll tokenStore an encrypted webhook disabled, test delivery, then enable; failed tests remove the disabled destination
POST/api/v1/agent/poll/{sessionID}/progresspoll tokenReport SDK, MCP, and pull-request progress, or failed/skipped diagnostics for server-derived steps
POST/api/v1/agent/poll/{sessionID}/completepoll tokenComplete onboarding after this session’s first event, or return 422 with missing: ["first_event"]; an already-onboarded org still needs the event
MethodPathOrigin-gatedPurpose
POST/api/v1/eventsbrowser callers onlyStore an error event and queue source-map processing. Receiving an error does not immediately create an issue, investigation, or alert.
POST/api/v1/replays/inityesBegin a replay upload
POST/api/v1/replays/{replayID}/completeyesFinish a replay upload
POST/api/v1/replays/{replayID}/failyesRecord a replay upload failure
POST/api/v1/sessions/inityesRegister a tenant-owned session with optional payload environment; returns whether the project allows session recording
POST/api/v1/sessions/{sessionID}/chunks/{seq}yesStore and commit one gzipped replay chunk (max 5MiB)
POST/api/v1/ingest/pingnoVerify that a public ingest key still authenticates; returns 204 without project data
MethodPathAuthPurpose
PUT/api/v1/sourcemaps/{debugID}secret source-map keyUpload one immutable source map after the server verifies its build identifier, which matches the map to a built file
MethodPathPurpose
GET/api/v1/auth/meCurrent user
GET/api/v1/auth/verifyValidate session
POST/api/v1/auth/logoutEnd session
POST/auth/switch-orgCloud only: rotate the current session into another member organization
GET/api/v1/invitationsCloud org admin: list active-org invitations
POST/api/v1/invitationsCloud org admin: create an active-org invitation
DELETE/api/v1/invitations/{invitationID}Cloud org admin: revoke an outstanding invitation
POST/api/v1/invitations/acceptCloud: accept a single-use, verified-email-bound invitation
GET/api/v1/billing/summaryBilling-enabled deployments: read the active org’s plan and feature balances (admin on cloud)
POST/api/v1/billing/checkoutBilling-enabled deployments: start Pro checkout for the active org (admin on cloud)
POST/api/v1/billing/portalBilling-enabled deployments: open the active org’s billing portal (admin on cloud)
GET/api/v1/admin/overviewOperator-only cross-tenant monitoring overview, including best-effort progress through automated repository setup (404 unless allowlisted)
GET/api/v1/admin/jobsOperator-only recent jobs (404 unless allowlisted)
POST/api/v1/onboarding/setupCreate or resume the first project and return a fresh ingest key
GET/api/v1/onboarding/stateRead server-derived onboarding facts and the next step
POST/api/v1/onboarding/completeMark onboarding complete after the project receives its first event; GitHub and Slack are optional (admin on cloud)
GET/api/v1/projectsList projects
POST/api/v1/projectsCreate project
PATCH/api/v1/projects/{projectID}Update project settings. friction_autonomy (ask_first or auto_fix) controls automatic fixes for session-recording issues; the retired auto_fix_ux is accepted as a deprecated alias and stored as auto_fix; pr_posture controls whether unverified fixes may open as drafts. A same-project default_environment_id must be an explicit UUID string when present.
GET/api/v1/projects/{projectID}/fix-statsFix-attempt and pull-request outcome counts by issue type
GET/api/v1/projects/{projectID}/environmentsList all environments, or only environments that contain issues with used_by=incidents or sessions with used_by=sessions
GET/api/v1/projects/{projectID}/event-countReturn has_events and the nullable latest_error_group_id
GET/api/v1/projects/{projectID}/digest/latestLatest delivered daily summary, or an empty summary when none has been delivered
POST/api/v1/projects/{projectID}/api-keysCreate an api (MCP), ingest, or sourcemaps key; secret returned once; only api accepts expiry (admin)
GET/api/v1/projects/{projectID}/api-keysList the project’s MCP, ingest, and sourcemaps keys without showing their secrets (admin)
DELETE/api/v1/projects/{projectID}/api-keys/{keyID}Revoke an MCP, ingest, or sourcemaps key (admin)
GET/api/v1/projects/{projectID}/incidentsList issues
GET/api/v1/projects/{projectID}/incidents/{incidentID}Issue detail
GET/api/v1/projects/{projectID}/incidents/{incidentID}/evidenceSaved stack frames, failed requests, links to recordings, and available supporting data for the current issue
GET/api/v1/projects/{projectID}/notification-destinationsList project notification destinations and recent delivery state
POST/api/v1/projects/{projectID}/notification-destinationsCreate a Slack notification destination
PATCH/api/v1/projects/{projectID}/notification-destinations/{destID}Update a notification destination
DELETE/api/v1/projects/{projectID}/notification-destinations/{destID}Delete a notification destination
POST/api/v1/projects/{projectID}/notification-destinations/{destID}/testSend a test notification
GET/api/v1/projects/{projectID}/replays/{replayID}Fetch a replay
GET/api/v1/projects/{projectID}/sessionsList sessions with filters and keyset pagination
GET/api/v1/projects/{projectID}/sessions/{sessionID}Session detail and recording metadata with sensitive values removed
GET/api/v1/projects/{projectID}/sessions/{sessionID}/narrativeFetch the session narrative, finding grades, and verification timestamp
GET/api/v1/projects/{projectID}/sessions/{sessionID}/chunks/{seq}Fetch one decoded, redacted part of the recording
GET/api/v1/projects/{projectID}/incidents/{incidentID}/affected-usersAffected users
GET/api/v1/projects/{projectID}/incidents/{incidentID}/sample-eventFetch the redacted representative event with available source-mapped frames, the raw stack, breadcrumbs, and request context
POST/api/v1/projects/{projectID}/incidents/{incidentID}/fixStart a fix for an issue that is ready to fix, whether it came from an error or a session recording. Optional body fields: guidance (up to 2000 characters) and intent, the signed fix action from a digest link. An intent is scoped to this project and issue; an expired or mismatched intent returns 409 fix link has expired or no longer matches this issue
POST/api/v1/projects/{projectID}/incidents/{incidentID}/reviewRequest another short repository review for the current issue; reuses an investigation already in progress
POST/api/v1/projects/{projectID}/incidents/{incidentID}/link-prRecord a same-repository GitHub pull request without marking the issue resolved
POST/api/v1/projects/{projectID}/incidents/{incidentID}/resolveResolve issue
POST/api/v1/projects/{projectID}/incidents/{incidentID}/archiveArchive issue
POST/api/v1/projects/{projectID}/incidents/{incidentID}/snoozeSnooze an actionable issue for up to 30 days; a null or past until clears the snooze
POST/api/v1/projects/{projectID}/incidents/{incidentID}/unarchiveRestore archived issue
GET/api/v1/projects/{projectID}/accountsList B2B accounts
GET/api/v1/projects/{projectID}/accounts/{accountID}Account detail
GET/api/v1/projects/{projectID}/accounts/{accountID}/incidentsIssues for one account
GET/api/v1/github/setupGitHub App install callback
GET/api/v1/github/statusGitHub App status: installed, installation_id, and install_available; never creates install state
POST/api/v1/github/install-urlStart a GitHub App installation for the active organization: returns install_url and sets its single-use, 30-minute callback state; admin on cloud; 400 github_app_not_configured without an App
GET/api/v1/github/reposList installable repos; returns typed 400/409 installation errors or 503 github_unreachable with Retry-After
PUT/api/v1/projects/{projectID}/githubSet project repo config; returns 400 repo_not_in_installation with add_repo_url, 400 github_not_installed with github_connect_url, 409 github_installation_gone, or 503 github_unreachable with Retry-After
GET/api/v1/projects/{projectID}/githubGet project repo config
DELETE/api/v1/projects/{projectID}/githubRemove project repo config
MethodPathAuthPurpose
GET/internal/v1/projects/{projectID}/sessions/{sessionID}/chunks/{seq}X-Internal-TokenWorker fetch of one decoded, redacted part of the recording
GET/internal/v1/projects/{projectID}/incidents/{incidentID}/statusX-Internal-TokenRead one issue’s status for the deployment smoke test

A request whose path is registered but whose method is not returns a JSON 404, not a 405. The router sets one MethodNotAllowed handler, so this holds for every route above; an unregistered method is indistinguishable from an unregistered path. Handlers that write 405 themselves (password-reset flows) are unaffected.

Any other path serves the dashboard SPA from DASHBOARD_DIR (missing static assets 404 rather than falling back to index.html).