CONSOLE V1 / CUSTOMER GUIDE
Query hot & historical evidence
Typed filters now; SQL preview is not unrestricted SQL execution.
Hot filters
POST /api/v1/events/query accepts start_time_ms, end_time_ms, source_id, class_uid, status_id, text and limit. Unknown fields—including sql—are rejected. Time defaults to the last 24 hours; maximum range is 31 days. limit defaults to 100 with a maximum of 500. text is at most 256 UTF-8 bytes and is a case-insensitive substring over activity_name or actor, not arbitrary JSON/full-text search. Tenant scope is injected server-side.
Execution bounds
The hot path uses parameterized ClickHouse SQL with a five-second engine limit, 256 MiB memory bound, 64 MiB read-byte bound, two threads and shared query concurrency control. The response includes items, scope:hot and query:{sql,rows,elapsed_ms}. SQL is a preview of the authorized operation, not a credential or an executable permission grant. A row cap alone is not a scan-cost guarantee; dependency errors and resource limits must remain visible.
Historical scope is explicit
POST /api/v1/history/query uses the authorized PyIceberg archive path over Iceberg/Parquet. Only start_time_ms, end_time_ms, source_id and limit are supported with the same time/row bounds. class_uid, status_id and text are explicitly rejected as unsupported_history_filter; no silent fallback to hot data. Archive unavailability fails explicitly. Historical event retrieval is not historical audit retrieval. Presto/Trino integration and an advanced SQL editor/gateway are planned, not connected.
Python standard-library example
Use only an authorized read/query session. SALAD_SESSION contains the opaque cookie value from your own private environment; never place it in source or print it. Set the origin variables to your operator-provided values. The example prints evidence IDs, not raw records or the cookie.
import json, os, urllib.request
body = json.dumps({"limit": 25, "status_id": 2}).encode()
request = urllib.request.Request(
os.environ["CONSOLE_URL"] + "/api/v1/events/query",
data=body, method="POST", headers={
"Origin": os.environ["CONSOLE_ORIGIN"],
"X-Console-CSRF": "1", "Content-Type": "application/json",
"Cookie": "salad_session=" + os.environ["SALAD_SESSION"],
})
with urllib.request.urlopen(request, timeout=10) as response:
result = json.load(response)
print([event["id"] for event in result["items"]])Node standard-library example
Node.js 18+ has built-in fetch; no third-party SDK or package is required. Do not reuse a human approval session as an autonomous agent credential. This GET only lists alerts in the authorized workspace.
const response = await fetch(process.env.CONSOLE_URL + "/api/v1/alerts", {
headers: {Cookie: "salad_session=" + process.env.SALAD_SESSION},
signal: AbortSignal.timeout(10000)
});
if (!response.ok) throw new Error("HTTP " + response.status);
const result = await response.json();
console.log(result.items.map(alert => alert.id));