Skip to main content

What approval flows solve

Some agent actions are too sensitive to run without a human saying yes first. File deletions, financial transfers, permission escalations, these benefit from a checkpoint before execution. KavachOS supports this with a permission constraint called requireApproval. When the permission engine sees it, authorization is denied with the reason "This action requires human approval before execution". Your application catches that signal, creates an approval request, notifies a human, and retries the action after a response comes back. The flow is async. The agent does not block waiting. The human can respond minutes or hours later, within the request’s TTL.
KavachOS creates the approval request and persists it. Delivering the notification to the human, email, Slack, push notification, is your application’s job. Use webhookUrl or onApprovalNeeded to hook into your existing notification stack.

How the flow works

1
Agent triggers approvalThe agent calls an action protected by requireApproval: true. Authorization is denied. Your application detects the denial reason and calls kavach.approval.request().
2
Human gets notifiedKavachOS fires your webhookUrl or onApprovalNeeded handler with the request details. Your app sends an email, opens a Slack DM, or surfaces a notification in your dashboard.
3
Human approves or deniesThe human clicks a button in your UI. Your UI calls your backend, which calls kavach.approval.approve(requestId) or kavach.approval.deny(requestId).
4
Agent retriesOnce approved, your application retries the original action. For maximum simplicity, pass the request ID back to the agent so it can poll or be woken up when a decision arrives.

ApprovalRequest fields

string
Unique identifier prefixed apr_.
string
The agent requesting approval.
string
The user who owns the agent and should receive the notification.
string
The action the agent wants to perform.
string
The resource the action targets.
The arguments the agent passed at the time of the call.
'pending' | 'approved' | 'denied' | 'expired'
Current state. Transitions are one-way.
Date
When the request expires if no response is received. Default TTL is 5 minutes.
Date | undefined
When the human responded.
string | undefined
Identifier of the person who approved or denied.
Date
When the request was created.

Configuration

Pass approval config to createKavach:
Or use a custom handler for full control over delivery:
Both webhookUrl and onApprovalNeeded fire asynchronously so the request() call is not delayed by notification latency.

How webhooks work

When webhookUrl is set, KavachOS sends a POST to that URL with a JSON body:
Webhook delivery failures are non-fatal. The request is already persisted, your app can poll listPending() as a fallback.

Code examples

Set up a permission that requires approval

Catch the denial and create a request

Approve or deny from your UI handler

List pending requests for a user

Expire stale requests

Requests that exceed their TTL are still stored with status: 'pending' until you run cleanup. Call this from a cron job:

Check the status before retrying

Next steps

Permissions

Add requireApproval constraints to individual permissions.

Trust scoring

Use trust levels to decide which agents need approval.

Audit trail

Every approval decision is linked to an audit entry.
Last modified on April 18, 2026