NORNR
Mandates, approvals and evidence for autonomous agents.
Guide / n8n
10 minutesHow to add spend controls to an n8n AI agent workflow
Gate paid tool calls in n8n with a governed wallet, approval threshold and audit trail using NORNR in under 10 minutes.
1. Why spend control matters in n8n
n8n makes it fast to wire together AI models, APIs and data sources into automated workflows. Once those workflows start calling paid AI services — OpenAI, Anthropic, data vendors — there is no native gate between the workflow trigger and the money leaving your account.
NORNR adds a decision node: the workflow asks whether a spend is permitted before the paid step runs. Low-risk calls continue automatically. Higher-value calls queue for operator review. Out-of-policy calls are blocked with a clear reason.
2. Install the SDK
pip install agentpay
The SDK is a thin wrapper around the NORNR policy engine. It submits a mandate check and returns a decision object before your n8n Code node proceeds.
3. Create the governed wallet
In an n8n Code node that runs before your paid step, create a wallet with a daily budget and approval threshold:
from agentpay import Wallet
wallet = Wallet.create(
owner="n8n-research-workflow",
daily_limit=50,
require_approval_above=15,
base_url="https://nornr.com",
)
4. Gate the paid step
Before the AI API call node runs, add a Code node that requests a decision:
decision = wallet.pay(
amount=8.00,
to="openai",
purpose="document summarisation",
)
if decision.get("status") == "approved":
# continue to the AI node
return [{"json": {"proceed": True, "decision": decision}}]
elif decision.get("status") == "queued":
# halt workflow, notify operator
return [{"json": {"proceed": False, "reason": "queued for review", "decision": decision}}]
else:
# blocked — log and stop
return [{"json": {"proceed": False, "reason": "blocked by policy", "decision": decision}}]
Add an n8n IF node after this Code node that checks proceed === true. The true branch continues to the AI step; the false branch routes to a notification or dead-letter node.
5. What the decision object looks like
{"status": "approved", "requiresApproval": false}
{"status": "queued", "requiresApproval": true}
{"status": "rejected", "reasons": ["daily_limit_exceeded"]}
6. Common n8n mistakes
- Placing the NORNR check after the AI API node instead of before it.
- Using a single hard-coded amount — estimate conservatively if the real cost varies.
- Not handling the queued path — treat it as a pause, not a failure.