Dashboard Get API Key →

Every action.
Under control.

Between your agent and real actions.
We stop retries, loops, and bad tool calls.

Start free → Read docs
Agent request
OnceOnly
monitoring
policy, idempotency, spend, dispatch
Tool policy
Idempotency
Spend caps
Dispatch
Executed tools
Atomic idempotency keys
Policy reasons and spend caps
Signed tool dispatch
Run timeline and metrics
Failure modes

Three ways agents break.

Small failures become real actions.

12:41:04 stripe.charge({ amt: 100 })
12:41:05 202 Accepted
12:41:08 ↳ Connection dropped. Agent assumes failure.
12:41:09 stripe.charge({ amt: 100 }) // retrying
12:41:10
↳ FATAL EXCEPTION
DUPLICATE CHARGE
Duplicate Side Effects

Retry -> duplicate

Same charge ran twice.

14:02:11 search.query("market map") -$0.50
14:02:18 browse.page("/pricing") -$1.20
14:02:31 extract.data("vendors") -$4.00
14:04:52 still looping... total_spend=$38.70
14:05:09
↳ search.deep_research("competitors") -$12.00
SPEND KEPT GOING
Runaway Spend

Loop -> spend

$480 burned before anyone noticed.

09:18:11 user asked for "all customer emails"
09:18:12 model selected crm.export_contacts
09:18:13 crm.export_contacts({ scope: "all_customers" })
09:18:14 200 OK — rows=18,204
09:18:15
↳ TOOL OUTSIDE ALLOWLIST
DATA LEAK
Tool Allowlist

Tool -> data leak

18,204 rows exported.

The Fix

One call. Full control.

Replace the direct call. Keep the control layer.

billing-agent.py
python sdk path
# direct call
result = stripe.charge(amount=100)
# route through onceonly
result = client.ai.run_tool(
    agent_id="billing-agent",
    tool="stripe.charge",
    args={"amount": 100},
    spend_usd=0.5,
)
Same tool call. Routed through OnceOnly.
Returns allowed, blocked, or dedup.
01

Policy

Checks tool scope.

02

Idempotency

Dedups retries.

03

Spend

Blocks over budget.

04

Dispatch

Forwards approved calls.

pip install onceonly-sdk Get API Key →
For LangChain, CrewAI, or your own runtime.
AI Lease

One run. One result.

The work runs once. Other agents poll, then read the same result.

Agent 1
idle
Agent 2
idle
lease key: invoice_8421.pdf
OCR + extraction
invoice_8421.pdf
01

Acquire the lease

The first agent gets the lock and starts the run.

02

Second agent polls

The same job returns polling instead of running again.

03

Read the same result

After completion, waiting agents can read the same result.

Decision Trail

Every decision is recorded.

Executed, blocked, and dedup outcomes leave a trace you can inspect later.

Run timeline billing-agent · run_01hzk9
12:41:04
Executed stripe.charge
decision=executed · spend=$0.50 · dispatch=signed
12:41:11
Dedup same args hash already completed
decision=dedup · reason=idempotency_key_hit
12:42:02
Blocked crm.export_contacts
decision=blocked · reason=tool_not_allowed · agent=billing-agent
12:42:18
Blocked search.deep_research
decision=blocked · reason=daily_spend_exceeded · spend=$50.00

Executed

The call ran after checks passed.

Dedup

The repeat was skipped before execution.

Blocked

The call stopped with a reason.

Executed
124
Blocked
17
Dedup
9
We log decisions and hashes, not raw prompts or tool arguments.
Policy Setup

Set the rules once.

Define what the agent can do before it runs.

billing-agent policy active
agent_id
"billing-agent"
allowed_tools
["stripe.charge", "email.send", "jira.create_task"]
blocked_tools
["crm.export_contacts", "refund.issue"]
max_spend_usd_per_day
50
max_actions_per_hour
30

Allowed tools

Only approved tools can run.

Blocked tools

Risky tools stay blocked.

Action and spend caps

Calls stop before they exceed limits.

Policies live outside the prompt.
Where It Matters

Where control matters most.

Three places agents can do real damage.

Money moves

Charges and refunds.

stripe.charge
refund.issue
invoice.send
Customer data

Exports and updates.

crm.export_contacts
crm.update_row
email.send
Paid tools

Search and research.

search.deep_research
browser.extract
scrape.run

Put a control layer between your agent and real actions.

Start with the Python SDK, set your first policy, and route every tool call through OnceOnly.

pip install onceonly-sdk