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
| Route | Authentication | Purpose |
|---|---|---|
GET /ready | None | Readiness 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/health | Required | A 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:
| Role | Who it’s for |
|---|---|
viewer | People who search, explore and investigate. Read-only. |
operator | On-call engineers. Everything a viewer can do, plus on-call actions such as silencing alerts. |
admin | Administrators. 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 path | What it does | Role |
|---|---|---|
GET /v1/audit | The query audit trail: who read what, and when | admin |
GET, POST /v1/holds; DELETE /v1/holds/{id} | Lists, places and releases legal holds | Any to list, admin to change |
GET /v1/alerts | Current alert state | Any |
GET /v1/alerts/history | History of alert fires and resolutions | Any |
GET, POST /v1/alerts/silences; DELETE /v1/alerts/silences/{id} | Lists, creates and removes silences | operator 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
| Status | Meaning |
|---|---|
400 | Malformed request: bad JSON, an inverted range, or a parameter outside its limit (see Limits) |
401 | Missing or invalid credentials |
403 | Authenticated, but your role isn’t allowed to do this |
412 | Rejected by the scan limit |
503 | A feature isn’t configured, or the node isn’t ready |