Skip to content

The REST API

Every capability in Sondar is reachable over a REST API — the same surface the web UI and the CLI use. This page is the entry point, and the endpoint tables below are hand-verified against a running instance.

  • Base URL — http://<host>:<port>/api/v1/… (the platform’s HTTP port, 9200 — see the ports table).
  • Authentication — there are two schemes, and they are not interchangeable:
    • The JSON API is session-based. POST /api/v1/account/login returns an X-Csrf-Token; send that back as a header on every subsequent call, along with the session cookie the login set. The two failures look different, and telling them apart saves the first hour:

      What you sentResponse
      no session cookie at all401 AccessDenied — Access denied, unauthenticated
      the session cookie, but no (or a stale) X-Csrf-Token403 AccessForbidden — Check Csrf Token failed

      The CSRF filter only runs on requests that carry a cookie (CsrfTokenFilter.isAccessAllowed returns early when WebUtils.useCookie is false), so a cookieless curl never reaches it — it fails authentication first. If you are hunting a “Check Csrf Token failed” that never appears, you are missing the cookie, not the token. Measured 1 Sep 2026 against a running instance.

    • A collect token authenticates data going IN. Generate one under Configure → Access Control → Collection Tokens — see Collection tokens for the default token, rotation and what to do if one leaks — and send it as an Authorization header on the ingest and trace endpoints (DCTokenService.validateForIngest, TraceGateway). It is what agents and OTLP clients use; it does not authorize the JSON API.

Three requests. The middle one is where every hand-written client goes wrong.

1. Fetch the public key. Unauthenticated, and you need it before you can log in:

Terminal window
curl -s http://<host>:9200/api/v1/publicKeys

The account_publicKey field is a base64 X.509 (SubjectPublicKeyInfo) RSA-2048 key.

2. Encrypt the password, then log in. The login endpoint does not take a plain-text password by default. sondar.transport.asymmetric.encryption.enable defaults to true, and when it is on the server RSA-decrypts the password field before checking it. Encrypt with RSA/ECB/PKCS1Padding and base64 the result — the Java default that EncryptionService uses:

Terminal window
# turn account_publicKey into a PEM file first
printf -- '-----BEGIN PUBLIC KEY-----\n%s\n-----END PUBLIC KEY-----\n' "$KEY" > pub.pem
ENC=$(printf '%s' "$PASSWORD" | openssl pkeyutl -encrypt -pubin -inkey pub.pem \
-pkeyopt rsa_padding_mode:pkcs1 | base64 | tr -d '\n')
curl -s -c cookies.txt -X POST http://<host>:9200/api/v1/account/login \
-H 'Content-Type: application/json' \
-d "{\"username\":\"$SONDAR_USER\",\"password\":\"$ENC\"}"

(base64 | tr -d '\n' rather than base64 -w0, which is GNU-only; and $SONDAR_USER rather than $USER, which your shell already defines as the account you are logged in as.)

The response body carries the token as X-Csrf-Token, and the session cookie lands in cookies.txt. You need both.

The trap. Send the password in plain text and the server answers 401 AccessDenied — usernameOrPasswordIsIncorrect. The credentials are not incorrect; the payload could not be decrypted, and the endpoint reports both failures identically. If a login you are sure about keeps being rejected, check this before you check the password. An operator who wants plain-text logins for a trusted network can set sondar.transport.asymmetric.encryption.enable: false in sondar.yml, which makes the field literal.

3. Call the API with the cookie and the token together:

Terminal window
curl -s -b cookies.txt -H "X-Csrf-Token: $TOKEN" \
http://<host>:9200/api/v1/repos

That returns the index list. Drop either the cookie or the token and you get one of the two failures in the table above.

Sondar does not serve a browsable API reference, and that is deliberate rather than missing.

The bundled documentation site was dropped on 29 Jul 2026 (docs/decisions/bundled-docs-dropped.md), and with it the step that copied the generated OpenAPI artifacts into the image. Until 13 Sep 2026 the three Swagger routes were still registered, so /api/v1/admin/swagger rendered the real Swagger UI shell and then returned 404 for the document it asks for — a page that could only disappoint. Those routes are now retired: they answer exactly as any unknown path does. That also took 43.5 MB of Swagger UI bundle out of the image, including a second copy in a module that never served it at all.

The OpenAPI document still exists — :sondar-server:swagger generates it into sondar-server/src/main/resources/swagger/docs/sondar.json, and a gate (tools/check-swagger-current.sh) fails the build if it drifts from the controllers beside it. It is simply not shipped or served.

So discover a call from the product, not from a spec browser. Every operation the web UI performs is an API call: perform it in the UI with the browser’s network tab open, and you have the method, path and body. The tables on this page cover the surface most callers need.

The API surface itself is real and large — hundreds of endpoints across search, collection, metrics, alerts, dashboards and administration — and every operation the web UI performs is one of them, which is the most reliable way to discover a call: perform it in the UI with the browser’s network tab open.

Anything under /api/v1/admin/ is behind the same session. Opening such a path without a logged-in session returns the JSON 401 AccessDenied above, not a login page — so fetch it from a browser tab that is already signed in, rather than with a bare curl. (Verified 1 Sep 2026, re-checked 7 Sep 2026.)

Saved searches and reports record which query language they use in splType. Send "sonql" for a SonQL query and "interact" for one built in Interactive Search. "spl", the name the API has always used, is accepted as a synonym, and it is what responses still return, so clients written against it keep working. Any other value is refused rather than guessed. A Search page link takes the same value: /logdb/search?queryString=...&splType=sonql opens the query in Advanced Search.

For scripting, the CLI wraps the most common operations — search, write, and resource management — without you having to construct requests by hand. See The Sondar CLI.