Skip to content

Audit Logging

OnceOnly records recent governance decisions so you can answer:

  • What tool did the agent try to use?
  • Was it executed, deduplicated, or blocked?
  • Why did OnceOnly make that decision?
  • How much spend was attached to the action?

The user-facing audit surface in the current backend is centered on:

  • Agent logsGET /v1/agents/{agent_id}/logs on Pro+
  • Agent metricsGET /v1/agents/{agent_id}/metrics on Pro+

Get recent decisions for an agent:

Terminal window
curl -H "Authorization: Bearer once_live_xxxxxxxxxxxxx" \
"https://api.onceonly.tech/v1/agents/support_bot/logs?limit=100"

Query Parameters:

  • limit — Max results (default: 100, max: 500)

Typical response:

[
{
"ts": 1705322450,
"agent_id": "support_bot",
"tool": "send_email",
"allowed": true,
"decision": "executed",
"policy_reason": "ok",
"risk_level": "low",
"args_hash": "a1b2c3d4",
"spend_usd": 0.001
},
{
"ts": 1705322500,
"agent_id": "support_bot",
"tool": "delete_user",
"allowed": false,
"decision": "blocked",
"policy_reason": "tool_not_in_allowed_list",
"risk_level": "medium"
}
]
  • ok
  • tool_not_in_allowed_list
  • tool_explicitly_blocked
  • max_actions_per_hour_exceeded
  • max_calls_per_tool_exceeded
  • max_spend_usd_per_day_exceeded
  • agent_disabled
  • tool_idempotency
  • tool_error

Get aggregated activity for an agent:

Terminal window
curl -H "Authorization: Bearer once_live_xxxxxxxxxxxxx" \
"https://api.onceonly.tech/v1/agents/support_bot/metrics?period=day"

Query Parameters:

  • period — “hour”, “day”, or “week”

Response:

{
"agent_id": "support_bot",
"period": "day",
"total_actions": 450,
"blocked_actions": 12,
"total_spend_usd": 125.50,
"top_tools": [
{"tool": "send_email", "count": 400},
{"tool": "create_ticket", "count": 50}
]
}

In the current backend:

  • Agent decision logs are retained for 7 days
  • Agent metrics are queried by hour, day, or week

def investigate_blocks(agent_id: str):
logs = get_agent_logs(agent_id)
blocked = [log for log in logs if log.get("decision") == "blocked"]
blocks_by_reason = {}
for log in blocked:
reason = log.get("policy_reason") or "unknown"
blocks_by_reason[reason] = blocks_by_reason.get(reason, 0) + 1
return {
"total_blocks": len(blocked),
"blocks_by_reason": blocks_by_reason,
"recent_blocks": blocked[-5:],
}

  1. Review blocked decisions regularly
  2. Treat repeated *_exceeded reasons as a signal to tune policy caps
  3. Use agent logs together with Policies and Tools Registry

Next, see Audit API Reference for the exact endpoints.