Docs: APIs
Documentation / Reference

APIs

The parts of the OBSESC node's HTTP API you can script against: health checks, authentication, roles, SQL over your raw events, and governance endpoints.

Every OBSESC node serves the web console and an HTTP API on the same port. The console’s investigation features, such as What changed?, Seen this before? and What tends to follow?, are used through the console and aren’t offered as a supported scripting API. This page covers the parts of the API you can script against.

Base URL and ports

On a stack deployed from the AWS Marketplace CloudFormation template, each node serves the console and the API on port 18080:

http://obsesc.your-domain.internal:18080

The stack’s UiUrl output gives the address to open the console. If you deployed the optional internal load balancer, use the load balancer’s name instead of a node address (see System requirements).

If you configure TLS (see Encryption), the port serves HTTPS only; there is no plaintext fallback.

API routes are versioned under /v1.

Health checks

RouteAuthenticationPurpose
GET /readyNoneReadiness probe for load balancers. Returns 200 while the node can serve, and 503 with a short plain-text reason when it can’t.
GET /v1/healthRequiredA JSON health summary, including ingest and storage status.

/ready is unauthenticated, so keep port 18080 reachable only from inside your VPC. See Network configuration.

Ingest endpoints (OTLP, Elasticsearch _bulk, Splunk HEC and others) listen on their own ports and are covered in Supported sources.

Authentication

How a request authenticates depends on how you deployed.

Single token. If you set an API token without role-based access control (RBAC), every /v1/* request must carry:

Authorization: Bearer <query_api_token>

A missing or wrong token returns 401. If no token is configured at all, the API runs unauthenticated. Don’t run production this way.

RBAC. If you set the CloudFormation AuthSecretArn parameter, the stack turns RBAC on and gives the secret’s query_api_token the admin role. Every /v1/* request must then resolve to a role, or it gets 401. A request resolves to a role in one of two ways:

  • a bearer token you’ve mapped to a role, or
  • your identity provider, through sign-in on the stack’s load balancer. With EnableUiPerUserRbac, everyone who signs in to the console gets their own role, based on a claim such as their email address.

A request that authenticates but whose role isn’t allowed to do something returns 403.

Configuration keys are listed in the Configuration reference.

Roles

OBSESC ships three built-in roles:

RoleWho it’s for
viewerPeople who search, explore and investigate. Read-only.
operatorOn-call engineers. Everything a viewer can do, plus on-call actions such as silencing alerts.
adminAdministrators. Everything, including legal holds, the query audit trail, erasure and credentials.

You can also define your own roles. Contact us via the contact page if you need help choosing permissions for a custom role.

SQL over raw events: POST /v1/sql

You can run SQL over your raw events in the raw_events table.

curl -s -X POST "http://obsesc.your-domain.internal:18080/v1/sql?format=ndjson" \
  -H "Authorization: Bearer $OBSESC_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "sql": "SELECT timestamp_ns, service, body FROM raw_events WHERE service = '\''checkout'\'' AND timestamp_ns >= 1776556800000000000 AND timestamp_ns < 1776643200000000000 LIMIT 100",
    "max_scan_bytes": 10737418240
  }'

Times are nanoseconds since 1 January 1970 UTC.

The raw_events table has these columns: timestamp_ns, source, service, body, idempotency_key, an attributes map, and the dimension columns host, env, namespace and tenant. See the SQL reference for syntax.

Your raw events are also stored as open Parquet files with an Iceberg catalog in your own S3 bucket, so you can query them with Amazon Athena or another engine without going through OBSESC at all.

Scan limit. Before any data is read, OBSESC works out an upper bound on how much the query could read and how long it could take. If that’s above your limit, it returns 412 Precondition Failed and reads nothing. Set max_scan_bytes or max_scan_seconds in the request to use your own limit for that query. To run the query anyway, resubmit it with "confirm": true.

Exporting results

POST /v1/sql accepts ?format=json (the default), ?format=ndjson or ?format=csv. NDJSON and CSV responses contain data rows only and are sent as file downloads. An unknown format returns 400 before any work runs.

Governance and alerts

Method and pathWhat it doesRole
GET /v1/auditThe query audit trail: who read what, and whenadmin
GET, POST /v1/holds; DELETE /v1/holds/{id}Lists, places and releases legal holdsAny to list, admin to change
GET /v1/alertsCurrent alert stateAny
GET /v1/alerts/historyHistory of alert fires and resolutionsAny
GET, POST /v1/alerts/silences; DELETE /v1/alerts/silences/{id}Lists, creates and removes silencesoperator or admin to change

Erasure must be enabled before you can use it. Contact us via the contact page to enable erasure before you need it.

Errors

StatusMeaning
400Malformed request: bad JSON, an inverted range, or a parameter outside its limit (see Limits)
401Missing or invalid credentials
403Authenticated, but your role isn’t allowed to do this
412Rejected by the scan limit
503A feature isn’t configured, or the node isn’t ready