THE SAFETY LAYER FOR AI AGENTS
Policies pause the risky action. A human approves, rejects, or edits it. Your agent resumes, and the audit log proves it.
the demo emails you a real approval · no account needed
01 · THE EMAIL
Confirm.dev
to sarah@acme.com
Confirm.dev · Approval required
SupportBot is requesting approval
Refund $10,000 to customer #4821
Review & Respond02 · THE DECISION
Refund $10,000 to customer #4821
PENDINGWhat the agent did first
01 Read ticket #5521: "charged wrong"
02 Newest order is $10.00
03 · THE RECORD
Audit log
Refund $10,000 to customer #4821
APPROVEDThe whole loop is one API call, a magic link, and a signed webhook. Around it: escalation routing, approver context, parked agent state, and an immutable audit trail.
REQUEST
Your code calls POST /v1/requests with the exact payload. The agent stops there.
DECIDE
The approver gets a magic link. No account, no app. They approve, reject, or edit the payload first. Every decision is recorded.
RESUME
We POST the verdict to your endpoint, HMAC-signed. Execute effectivePayload. Human edits win.
FULL CONTEXT
Pass reasoning and recentActions and the approver sees the agent's step-by-step trail and its own explanation, right above the payload. No archaeology before a verdict.
STATE PARKING
Attach up to 256KB of serialized agent context as agentState. The webhook hands it back when the decision lands, and a fresh worker rehydrates. Nothing holds memory while the human thinks.
YOUR CLOCK
Set a workspace-wide default expiry or per-request ttlMinutes. Unanswered requests auto-expire, your agent gets the webhook, and the action never runs.
One integration, every team's nightmare scenario:
GUARDRAILS
An ops agent proposes dropping a “stale” table that billing still reads nightly. The DBA rejects it with a note and the agent halts.
INTEGRATION
The SDK guards your whole tool layer with policies, fail-closed, so nothing slips through unwrapped. Prefer raw HTTPS? It's one POST with a bearer key. MCP agents get an approval tool with zero code. Resume on the webhook, or poll.
Full API reference →import { guard } from "@confirm/sdk";
// Wrap the whole tool layer once. Policies decide what needs a human.
const tools = guard(agentTools, {
policies: [
{ when: (t) => t.name.startsWith("delete_"), notify: "security@acme.com" },
{ when: (t) => t.name === "refund" && t.args.amount > 500, notify: "finance@acme.com" },
{ when: (t) => t.name === "search", decision: "allow" }, // read-only, never gated
],
default: "require", // fail-closed: a tool nobody ruled for still needs a human
});
// On approval the tool runs with the human-edited payload.WHY A SERVICE
| You need to | Confirm | The bot you maintain forever |
|---|---|---|
| Catch what you forgot | ✓Policies gate the whole tool layer, fail-closed, so a tool nobody wrapped still needs a human | Hand-wrap every risky call and hope you didn't miss one |
| Route by stakes | ✓notify: "group:finance" sends big refunds to finance and access grants to security, each member gets their own link | A bot, a channel map, and routing logic you maintain forever |
| Know who decided | ✓Named identity, timestamp, IP, and note on every decision | "Someone reacted with a checkmark in #approvals" |
| Fix before it runs | ✓Approvers edit the JSON inline, the agent executes the edited version | Copy the payload into a thread and hope the agent picks it up |
| Nobody answers | ✓Requests expire on your TTL and notify your agent. Silence is never consent | The run hangs, or worse, a retry loop fires the action anyway |
| Resume with context | ✓Park up to 256KB of serialized agent state with the request, get it back in the webhook hours later | Build your own checkpoint store and wire it to the bot |
| Prove it to an auditor | ✓Append-only log of requests, decisions, and delivery receipts | Search the channel scroll-back and export screenshots |
The ping is the easy 5%. The rest is a security product someone has to run forever. That's our job. Yours is one POST.
SECURITY
HASHED CREDENTIALS
API keys and magic-link tokens are stored as SHA-256 hashes. A database leak can't mint requests or approve them.
SIGNED WEBHOOKS
Every delivery carries an HMAC-SHA256 signature over a timestamped payload, with per-endpoint secrets.
256-BIT MAGIC LINKS
Approval tokens are 256 bits of entropy, single-purpose, and dead at the TTL. There is no password to phish.
APPEND-ONLY AUDIT
Requests, decisions, and delivery attempts are immutable rows. SOC2 evidence is a query.
IDENTITY ON EVERY DECISION
Approvals record the approver, timestamp, IP address, user agent, and note.
FAIL SAFE, NOT OPEN
Unanswered requests expire and notify your system. Silence never becomes consent.
The full model is documented, not marketed: read the security page.
Per approval, not per seat. Approvers are always free.
HOBBY
$0forever
PRO
$29per month
Exact limits per plan are in the docs.
Every request has a TTL (default 24 hours, up to 7 days). When it elapses, the request becomes EXPIRED and a request.expired webhook fires. Your agent fails safe instead of hanging or acting anyway.
No. Approvers get a single-purpose magic link by email, and the token in the link is the credential. Only developers who build with the API have accounts.
Yes. The approver fixes the JSON in the review screen and approves. The webhook's effectivePayload carries their version, and the original stays stored for the audit trail.
Every delivery is signed: HMAC-SHA256 over timestamp.body with your endpoint's secret, sent in X-Confirm-Signature. Verification is about six lines, shown in the samples above.
Pass it as agentState when you create the request: up to 256KB of serialized context, stored with the request and returned in the webhook. A fresh worker rehydrates from it and continues, so nothing holds memory while the human decides. Approvers never see this field.
Yes. Anywhere you can make an HTTPS request, you can gate an action: a LangChain tool, a Vercel AI SDK tool call, a CrewAI task, or a plain function.
Every request, every decision (identity, timestamp, IP, note, payload edits), and every webhook delivery attempt with its HTTP status. Rows are append-only.
Guardrails are automated filters: they catch known patterns, without judgment. Confirm puts a human on the judgment calls, like the plausible-looking $10,000 refund or the deploy at the wrong moment. Run both. Guardrails for the obvious, a human approval for the irreversible.