NORNRMandates, approvals and evidence for autonomous agents.
Guide / Zapier
10 minutesHow to set a budget for Zapier AI agent actions
Add a governed spend limit and approval gate to Zapier AI actions using NORNR before any paid step triggers — using Code by Zapier and a Filter or Paths branch.
1. Why Zapier AI actions need a budget gate
Zapier's built-in AI actions are convenient and Zaps are easy to share across teams. The problem is that once a Zap runs at scale, every trigger fires the AI action unconditionally. There is no built-in way to say "pause this run if the cost estimate exceeds $10" or "require a human to sign off before calling this API more than twice today."
NORNR provides that layer. Because Zapier supports JavaScript via Code by Zapier, you can make an outbound API call to NORNR inside the Zap itself, get a decision, and only continue to the paid step if the decision is approved.
2. Zap structure overview
The governance gate sits between your trigger and your paid AI step:
- Trigger — any event (new form, webhook, schedule, Gmail, etc.)
- Code by Zapier — calls NORNR, outputs
statusanddecisionId - Filter or Paths by Zapier — routes on
status - Path A (approved) — your paid AI action (OpenAI, Anthropic, etc.)
- Path B (queued) — Slack or email notification; Zap stops
- Path C (rejected) — log the block; Zap stops
3. The Code by Zapier step
Add a Code by Zapier action and select Run JavaScript. Paste the following code. Set NORNR_API_KEY and WALLET_ID as Zapier Storage values or hardcode them temporarily for testing.
// Code by Zapier — Run JavaScript
// Input data: amount (number), purpose (string), to (string)
// These map from previous Zap steps via inputData
const NORNR_API_KEY = inputData.nornr_api_key; // set via Zapier Storage or hardcode for testing
const WALLET_ID = inputData.wallet_id; // created once in NORNR control room
const response = await fetch(
`https://nornr.com/api/wallets/${WALLET_ID}/pay`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${NORNR_API_KEY}`,
},
body: JSON.stringify({
amount: parseFloat(inputData.amount || "5.00"),
to: inputData.to || "openai",
purpose: inputData.purpose || "Zapier AI action",
}),
}
);
const decision = await response.json();
// Expose status and decisionId as output fields
// so the downstream Filter / Paths step can read them
output = {
status: decision.status,
decisionId: decision.decisionId || "",
reasons: (decision.reasons || []).join(", "),
};
Map amount, to and purpose from earlier Zap steps or set them as static values if the AI step always has a fixed cost estimate.
4. Branch with Filter or Paths by Zapier
Connect the Code step output to a Filter by Zapier if you only need the approved path, or use Paths by Zapier for three separate routes.
// Option A: Simple Filter (stops the Zap if not approved)
Filter: (Code) status | (Text) Exactly matches | approved
// Option B: Paths by Zapier (three routes)
Path 1 — "Approved"
Rule: (Code) status exactly matches "approved"
→ Run your paid OpenAI or Anthropic action
Path 2 — "Queued"
Rule: (Code) status exactly matches "queued"
→ Slack: "Approval needed for decision {{decisionId}}"
→ End path (do NOT continue to paid step)
Path 3 — "Rejected"
Rule: (Code) status exactly matches "rejected"
→ Slack or Airtable log: "Spend blocked: {{reasons}}"
→ End path
5. Creating the wallet if you do not have one yet
You can create the NORNR wallet once from the control room UI at /app, or from a separate one-time Zap that calls the wallets endpoint. Copy the returned walletId and paste it into Zapier Storage or a static input field on the Code step.
// One-time wallet creation — run this in a separate Zap or cURL
const response = await fetch("https://nornr.com/api/wallets", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${NORNR_API_KEY}`,
},
body: JSON.stringify({
owner: "zapier-ai-agent",
daily_limit: 30,
require_approval_above: 10,
allowed_counterparties: ["openai", "anthropic"],
}),
});
const wallet = await response.json();
output = { walletId: wallet.id };
6. Handling queued decisions in Zapier
When a decision is queued, the intended spend is held and visible in the NORNR control room. The reviewer can approve or reject it there. To resume the Zap automatically after approval, configure NORNR to POST a webhook to a Zapier webhook trigger. Set up a second Zap that:
- Triggers on the NORNR approval webhook
- Reads the
decisionIdandstatusfrom the payload - Filters on
status == approved - Runs the paid AI action that was held
This keeps the main Zap lean and avoids polling loops that consume Zapier task credits.
7. What each decision state means for your Zap
- approved — the spend is within mandate, below the approval threshold, and the counterparty is on the allowlist. Continue to the paid AI step.
- queued — the amount crossed the review threshold. The Zap stops here. A human reviews it in the control room. Resume via webhook when resolved.
- rejected — policy blocked the action outright. Common reasons:
daily_limit_exceeded,counterparty_not_allowed,mandate_not_found. The Zap stops and logs the block.
8. Common mistakes
- Placing the Code step after the paid AI action. The governance check must run before money moves. Reorder the steps if this happens.
- Ignoring the queued state. If you only filter for
approved, a queued decision silently fails the filter. Add explicit handling so the reviewer is notified. - Using a free-text amount from the trigger without validation. Parse and cap the amount in the Code step before sending it to NORNR to prevent a malformed request.
- Not storing
decisionId. The decision ID is your audit reference. Log it to Airtable, Google Sheets or Zapier Storage alongside the Zap run timestamp.