Audit Log
Every outbound call from your sandbox is recorded automatically. No setup. The Audit Log tab on each sandbox/computer is the source of truth for “what did my workload actually do on the network?”
What’s in each row
| Column | Description |
|---|---|
timestamp | When the request happened (microsecond precision) |
host | Upstream hostname |
method | GET, POST, PUT, … |
path | URL path (query string redacted) |
action | allow, reject, stub, error, client_cancel |
status_code | Upstream response code (or 0 if no response) |
duration_ms | Wall-clock time |
bytes_in / bytes_out | Volume |
request_transforms | Which transforms fired (secrets, allowlist, header allowlist, …) |
mcp | MCP message trace, when the call was an MCP JSON-RPC request |
Live tail
The Audit Log tab streams new events in real time over WebSocket. New rows appear at the top as your sandbox makes calls.
Filtering
In the UI, use the filter bar to scope by:
- Time range - last hour, 24h, 7d, 30d, custom
- Host - exact or wildcard
- HTTP method
- Action - show only blocked, only allowed, only errors
- Transform - show only requests that swapped a particular secret, or only MCP tool calls
- Status code - show only 4xx, only 5xx, etc.
All filters are URL-shareable.
From the SDK
Common queries
“Why did this fail?”
Filter by action=reject for the last hour. Each row tells you which rule blocked it (rejected_by column).
“Which secret did this request use?”
Each row’s request_transforms JSON includes a secrets entry listing the secret names swapped. UI surfaces this in the detail drawer; SDK exposes it as event.request_transforms.secrets.swapped.
“What did our AI agent do last quarter?”
Tenant-admin filter by date range and resource type. Export CSV.
“Show me all calls by Dr. Smith”
For white-label deployments, filter by external_user_id. See White-label Credentials.
Export
Every filtered view can be exported as CSV or JSON via the “Export” button (UI) or the SDK:
sandbox.audit.export(since="30d", format="csv", path="audit-30d.csv") Retention
| Plan | Retention |
|---|---|
| All plans (default) | 90 days |
| Custom retention (longer) | available on enterprise plans |
Beyond the retention window, rows are deleted from egress_audit. Export your data if you need a longer record.
Programmatic alerting (Phase 5)
You’ll be able to wire saved queries into alerting:
“Notify me if any sandbox makes more than 100 requests to a never-before-seen host in 5 minutes.”
This ships in Phase 5 of the Security rollout.
Real-world example - compliance dashboard for a multi-tenant healthcare app
You’re building a healthcare SaaS where each clinician uses a sandbox. Compliance requires you to surface all outbound calls per clinician in your own dashboard, with the ability to export a 30-day report.
Troubleshooting
Audit log is empty even though the sandbox is running. The audit log only records outbound calls from the sandbox. If the sandbox is just waiting for input or doing in-process computation with no network calls, no rows appear. Trigger an outbound call and re-query.
audit.tail() disconnects after a few seconds. Tail connections are kept alive with WebSocket pings. If your network has a short idle-connection timeout, the connection can drop. Reconnect in your retry loop:
while True:
try:
for event in sandbox.audit.tail():
process(event)
except ConnectionError:
time.sleep(1) # reconnect request_transforms.secrets.swapped is empty - but I have secrets bound. If the sandbox’s env var contains the real key (e.g., from a .env file that overrode the placeholder), the proxy has nothing to swap. Run sandbox.exec("echo $OPENAI_API_KEY") - if it prints the real sk-proj-... instead of miosa-tok-..., the .env file is winning.
Tenant-wide client.audit.list() returns too many rows. Narrow with external_user_id, external_workspace_id, host, or action filters. Maximum limit per call is 1000. For larger exports, use audit.export().
I need audit rows older than 90 days. Default retention is 90 days. For longer retention, contact support to enable custom retention on your tenant. Export regularly if you need a permanent archive.
For more issues, see the Security troubleshooting hub.
Frequently asked
Does the audit log capture request bodies? Not by default - only headers (redacted) and metadata. You can opt in to body capture per-resource if you need it for compliance, with a “may contain sensitive data” warning.
Are response bodies captured? No. Audit is request-side only.
Can I disable the audit log entirely? No - audit is the platform baseline. You can shorten retention but not disable it.
Will live-tail consume my plan’s API quota? No. Audit streaming is over a WebSocket and doesn’t count against REST API rate limits.