Tutorial March 15, 2026 8 min read

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:

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 →