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 -> duplicates

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 -> runaway 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 -> unsafe actions

18,204 rows exported.

The Fix

One call. Full control.

Replace the direct call. Keep the control layer.

billing-agent.py
# 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.
Why OnceOnly

They log after.
We stop before.

Most governance tools observe after the damage. OnceOnly decides before the tool runs.

Others governance tools
01
Agent calls the tool
No gate.
02
$40 loop runs
Spend already gone.
03
Logs and alerts
You see it after.
04
Damage already happened
You have a report, not a stop.
OnceOnly control layer
01
Agent calls OnceOnly
Before the tool runs.
02
Checks run first
Policy, dedup, spend, lease.
03
Blocked, deduped, or allowed
Before the tool call.
04
Tool never ran
Blocked and deduped calls never run.
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 control before real actions.

Use the Python or TypeScript SDK to route tool calls through OnceOnly.

pip install onceonly-sdk npm i @onceonly/onceonly-sdk