Skip to content

Policies

Policies: Agent Governance and Access Control

Section titled “Policies: Agent Governance and Access Control”

Policies define what an agent can call and which limits apply when it uses a tool.

Depending on your plan, some policy fields are trimmed when the policy is stored:

  • Freeallowed_tools, blocked_tools
  • Starter — adds max_actions_per_hour, max_calls_per_tool, max_spend_usd_per_day
  • Pro / Agency — adds pricing_rules and built-in templates
{
"agent_id": "support_bot",
"allowed_tools": [
"send_email",
"read_knowledge_base",
"create_ticket"
],
"blocked_tools": [
"delete_user",
"process_refund"
],
"max_actions_per_hour": 100,
"max_spend_usd_per_day": 500.00,
"max_calls_per_tool": {
"send_email": 200,
"create_ticket": 50
},
"pricing_rules": [
{"tool": "send_email", "price_usd": 0.001},
{"tool": "create_ticket", "price_usd": 0.05},
{"tool": "read_knowledge_base", "price_usd": 0.0}
]
}
ComponentPurpose
allowed_toolsWhitelist of tools this agent can call
blocked_toolsBlacklist of tools this agent cannot call
max_actions_per_hourRate limit: max actions per hour
max_spend_usd_per_dayBudget: max USD spend per day
max_calls_per_toolPer-tool daily limits
pricing_rulesCost in USD per tool call

Terminal window
curl -X POST https://api.onceonly.tech/v1/policies/support_bot \
-H "Authorization: Bearer once_live_xxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"agent_id": "support_bot",
"allowed_tools": ["send_email", "read_knowledge_base"],
"max_actions_per_hour": 100
}'

Response:

{
"agent_id": "support_bot",
"policy": {
"allowed_tools": ["send_email", "read_knowledge_base"],
"max_actions_per_hour": 100
}
}

max_actions_per_hour is available on Starter and higher. On Free, only the allow/block lists are retained.

Terminal window
curl -X POST https://api.onceonly.tech/v1/policies/billing_bot \
-H "Authorization: Bearer once_live_xxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"agent_id": "billing_bot",
"allowed_tools": [
"send_email",
"read_invoice",
"process_payment",
"create_refund"
],
"blocked_tools": [
"delete_invoice",
"delete_payment_history"
],
"max_actions_per_hour": 500,
"max_spend_usd_per_day": 10000,
"max_calls_per_tool": {
"send_email": 1000,
"process_payment": 200,
"create_refund": 50
},
"pricing_rules": [
{"tool": "send_email", "price_usd": 0.001},
{"tool": "read_invoice", "price_usd": 0.0},
{"tool": "process_payment", "price_usd": 0.1},
{"tool": "create_refund", "price_usd": 0.1}
]
}'

POST /v1/policies/{agent_id}/from-template is available on Pro and higher.

The built-in templates intentionally set only numeric guardrails and do not add tool allow/deny lists for you.

TemplateMax Actions/hrMax Spend/day
strict50$2
moderate200$10
permissive1000$50
read_only200$0
support_bot500$10

When an agent attempts an action:

POST /v1/ai/run
{
"agent_id": "support_bot",
"tool": "send_email",
"args": {"customer_id": "123"},
"spend_usd": 0.001
}
OnceOnly Policy Check:
┌─ Tool allowed?
│ allowed_tools contains "send_email"? YES ✓
│ blocked_tools contains "send_email"? NO ✓
├─ Rate limit OK?
│ Actions this hour: 45
│ Max per hour: 100
│ 45 < 100? YES ✓
├─ Per-tool limit OK?
│ Calls to send_email today: 180
│ Max for send_email: 200
│ 180 < 200? YES ✓
└─ Budget OK?
Estimated cost: $0.001
Spent today: $49.50
Daily budget: $50
$49.50 + $0.001 < $50? YES ✓
All checks pass → ALLOWED ✓
Return: {"allowed": true, "decision": "executed", ...}

Response (Allowed):

{
"ok": true,
"allowed": true,
"decision": "executed",
"policy_reason": "ok",
"risk_level": "low",
"result": {"status": "sent"}
}

Response (Blocked):

{
"ok": true,
"allowed": false,
"decision": "blocked",
"policy_reason": "tool_not_in_allowed_list",
"risk_level": "medium"
}

Every policy decision is logged:

{
"ts": 1705322400,
"agent_id": "support_bot",
"tool": "send_email",
"allowed": true,
"decision": "executed",
"policy_reason": "ok",
"risk_level": "low",
"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"
}
{
"ts": 1705322600,
"agent_id": "support_bot",
"tool": "send_email",
"allowed": false,
"decision": "blocked",
"policy_reason": "max_actions_per_hour_exceeded",
"risk_level": "critical"
}
{
"ts": 1705322700,
"agent_id": "billing_bot",
"tool": "process_payment",
"allowed": false,
"decision": "blocked",
"policy_reason": "max_spend_usd_per_day_exceeded",
"risk_level": "critical"
}

Update a policy to add/remove tools or change limits:

Terminal window
curl -X POST https://api.onceonly.tech/v1/policies/support_bot \
-H "Authorization: Bearer once_live_xxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"agent_id": "support_bot",
"allowed_tools": [
"send_email",
"create_ticket",
"read_knowledge_base",
"process_refund"
],
"max_actions_per_hour": 200,
"max_spend_usd_per_day": 100
}'

When to update:

  • Agent needs new permissions
  • Rate limits need adjustment
  • New tools become available
  • Suspected abuse pattern

Get audit logs for an agent (Pro+):

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

Response:

[
{
"ts": 1705322400,
"agent_id": "support_bot",
"tool": "send_email",
"allowed": true,
"decision": "executed",
"policy_reason": "ok",
"risk_level": "low"
},
{
"ts": 1705322450,
"agent_id": "support_bot",
"tool": "delete_user",
"allowed": false,
"decision": "blocked",
"policy_reason": "tool_not_in_allowed_list",
"risk_level": "medium"
}
]

Monitor logs for patterns:

def check_for_abuse(agent_id: str):
"""Detect suspicious activity patterns"""
logs = get_agent_logs(agent_id, limit=200)
blocked_count = sum(1 for log in logs if log["allowed"] == False)
budget_blocks = sum(1 for log in logs if log.get("policy_reason") == "max_spend_usd_per_day_exceeded")
rate_blocks = sum(1 for log in logs if log.get("policy_reason") == "max_actions_per_hour_exceeded")
if blocked_count > 10:
logger.warning(f"Agent {agent_id} had {blocked_count} blocked actions")
if budget_blocks > 0:
logger.warning(f"Agent {agent_id} exceeded budget {budget_blocks} times")
# Consider disabling the agent
disable_agent(agent_id, reason="repeated_budget_violations")
if rate_blocks > 3:
logger.warning(f"Agent {agent_id} exceeded rate limit {rate_blocks} times")
# Consider lowering limits
update_policy(agent_id, max_actions_per_hour=50)

  1. Start restrictive — Begin with minimal permissions, expand as needed
  2. Use allowed_tools — Whitelist beats blacklist
  3. Set realistic limits — Account for peak usage
  4. Monitor blocks — High block rate indicates too-strict policies
  5. Use templates — Start from templates and override
# Good policy progression
policy = {
"agent_id": "new_support_bot",
"allowed_tools": ["send_email"],
"max_actions_per_hour": 50,
"max_spend_usd_per_day": 10
}
# After 1 week of safe operation, expand
update_policy({
"allowed_tools": ["send_email", "create_ticket"],
"max_actions_per_hour": 100,
"max_spend_usd_per_day": 25
})
  1. Don’t use only blocked_tools — Whitelist is safer
  2. Don’t ignore policy blocks — They’re alerts
  3. Don’t set limits too low — Causes agent to fail
  4. Don’t allow write access by default — Reads only
  5. Don’t set unlimited spend — Always cap budget

Different OnceOnly plans have different policy capabilities:

FeatureFreeStarterProAgency
Allow / block tool lists
Rate limits-
Budget controls-
Per-tool limits-
Policy templates--
Pricing rules--
Agent disable / enable--
Agent logs & metrics--

  • Policies define agent permissions and limits
  • Allowed/blocked tools control access
  • Rate & budget limits prevent abuse
  • Pricing rules track costs
  • Audit logs show recent decisions
  • Templates provide safe starting points
  • Monitoring detects violations

Next, learn about Audit Logging to investigate agent behavior.