Statio keeps two records, because they answer two different questions:
| Record | Answers | In the dashboard |
|---|---|---|
| Tool calls | Who called which tool, and what happened? | Activity |
| Changes | Who changed what: servers, credentials, keys, agents, access? | Audit Logs |
Both are written by Statio as the work happens, not reported by your agents, so an agent cannot leave something out.
Every tool call through the gateway is a row, whether it was allowed or refused.
| Field | What it means |
|---|---|
| Outcome | allowed, or failed for anything that did not succeed, including a refusal |
| Tool and server | The tool that was called, and the server it is on |
| Caller | The person or the agent that made the call |
| Status | The HTTP status of the response |
| Latency | How long the call took through the gateway, in milliseconds |
| Error | For a failed call, an error code and message (below) |
| Environment | production, or preview when the call went to a preview version |
| IP address | Where the call came from |
| Time | When it happened |
Each row also carries the request and response size, the client's user agent and a request ID.
The error code says who said no:
| Code | Meaning |
|---|---|
STATIO_403, STATIO_429, ... | Statio refused the call: no permission, a usage or rate limit, the security scan, a suspended server |
HTTP_401, HTTP_500, ... | The call reached the upstream API, and that is what it answered |
PROXY_ERROR | The gateway could not reach the server at all |
So a refusal by your policy and a rejection by the vendor never look the same.
A run of HTTP_401 after a key was rotated upstream usually means the
credential in Statio needs replacing too.
initialize, tools/list and session requests are
how a client connects, not tool calls, so they are not recorded or metered.Filter by tool name, server, outcome (failed or success) and a date range. The quickest audit question, "what was refused this week", is the failed filter with a date range.
Audit Logs records administrative changes in one timeline: servers, deployments, credentials, API keys, catalog installs, webhooks and integrations, plus the changes made to agents and their access.
| Field | What it means |
|---|---|
| What | A sentence describing the change, with its action code (such as server.create) |
| Who | The person who made it, by email, or the API key it was made with |
| Kind | What was changed: server, deployment, secret, API key, agent, access and so on |
| Result | success, failed or denied |
| When | When it happened |
| IP address | Where the change came from |
Filter by text, action code, kind, result and date range. denied is the row to watch: someone tried to make a change their role does not allow.
Credential changes are recorded as changes; the value never is. See Credentials.
On Business and Enterprise, both records can be delivered to an HTTPS endpoint you run: your SIEM, a log pipeline or an observability stack. Set it up under Webhooks in the dashboard:
A destination can be paused, edited or deleted at any time.
Every event is a POST with a JSON body and these headers:
| Header | What it carries |
|---|---|
X-Statio-Event-Type | The event type: audit.* for changes, invocation.* for tool calls |
X-Statio-Delivery-Id | A unique ID for the delivery. Retries reuse it, so deduplicate on it |
X-Statio-Timestamp | When it was signed, in Unix seconds |
X-Statio-Signature | v1= followed by the signature |
The signature is an HMAC-SHA256, keyed with your signing secret, over the timestamp, a full stop, and the raw body, written as hex:
To verify one: compute the same value from the raw body and the timestamp header, compare it with the header in constant time, and reject a timestamp more than five minutes from your clock. The timestamp is part of what is signed, so a captured delivery cannot be replayed later with a new one.
Answer with any 2xx to accept the event. Other answers are retried, except a
4xx: sending the same payload again would get the same answer, so a 4xx
is not retried.