How to Add Human Approval Gates to AI Agents
Time to implement: 20–30 minutes for a basic integration
Prerequisites: Node.js 18+ or Python 3.9+, a Zehrava account
If your AI agent takes actions — sends messages, modifies records, calls APIs — you need approval gates on the write path. This tutorial shows how to implement them using Zehrava Gate.
Step 1: Install the Package
Node.js:
npm install zehrava-gate
Python:
pip install zehrava-gate
Step 2: Set Up Your API Key
ZEHRAVA_API_KEY=your_key_here
Get your API key at zehrava.com/dashboard → Settings → API Keys.
Step 3: Wrap Your Write Operations
Before (no gate):
await sendEmail({
to: lead.email,
subject: 'Following up',
body: generatedContent
})
After (with gate):
import { ZehravaGate } from 'zehrava-gate'
const gate = new ZehravaGate({
apiKey: process.env.ZEHRAVA_API_KEY
})
const intent = await gate.propose('send_email', {
to: lead.email,
subject: 'Following up',
body: generatedContent
})
if (intent.status === 'approved') {
await sendEmail(intent.payload)
} else if (intent.status === 'pending') {
console.log(`Intent ${intent.id} awaiting approval`)
} else {
console.log(`Intent ${intent.id} blocked`)
}
Step 4: Configure Approval Policies
In the Zehrava dashboard, configure how each intent type gets approved:
- Human review: Every intent routes to a named approver via dashboard or Slack
- Auto-approve: Intents matching a policy auto-approve without human action
- Auto-block: Intents outside defined parameters get blocked and logged
Step 5: Handle Async Approval
// Submit intent, continue without waiting
const intent = await gate.propose('update_crm', payload, {
mode: 'async'
})
// Webhook handler
app.post('/zehrava-webhook', (req, res) => {
const { intent_id, status } = req.body
if (status === 'approved') {
executeQueuedOperation(intent_id)
}
res.sendStatus(200)
})
Full Python Example
import os
from zehrava_gate import ZehravaGate
gate = ZehravaGate(api_key=os.environ["ZEHRAVA_API_KEY"])
def send_outreach_email(lead, content):
intent = gate.propose(
action="send_email",
payload={
"to": lead["email"],
"subject": f"Quick question about {lead['company']}",
"body": content,
}
)
if intent.status == "approved":
result = email_service.send(intent.payload)
gate.complete(intent.id, result={"message_id": result.id})
return result
elif intent.status == "pending":
print(f"Email pending approval: {intent.id}")
return None
else:
print(f"Email blocked: {intent.block_reason}")
return None
Next Steps
Add a commit checkpoint to your agent stack.
MIT license. Self-hostable. Framework-agnostic. Takes under an hour to wrap your first agent.
Get started free →