Guides

Approval Workflows

Designate approvers, route pending requests, and act on them from email or the Control Room.

When a policy requires approval, airlock creates a pending request and notifies designated approvers.

How Approvals Work

AI Agent calls tool
       │
       ▼
Policy evaluates to REQUIRE_APPROVAL
       │
       ▼
Pending request created
       │
       ▼
Approvers notified by email
       │
       ▼
Approver reviews and decides
       │
       ├── APPROVED → Execute operation
       ├── REJECTED → Return error to agent
       │
       └── EXPIRED → Auto-expire after timeout

Configuring Approvers

Approval Rules

Set up who can approve requests for specific operations:

  1. Open the Rules page and find the connector under Connectors
  2. Set the tool's category to Approval, or give the single tool an Approval exception
  3. Choose who approves: the requester, the space owner, the admins, or named people
  4. The integration's Tools tab shows the result read-only; it no longer changes a tool's setting

Multiple approvers can be assigned, and any one of them can approve the request.

Self-Approval

Whoever may decide a request may decide their own: an organization administrator, or an approver the Rules page names. What self-approval controls is the person who is not otherwise an approver, which is the usual case for the member an agent is working for. For lower-risk operations, choose Self as the approver on the Rules page and the requester can approve their own request: a confirmation step rather than a second-person review. A request raised because of a soft security block works the same way.

When someone tries to approve or reject a request they are not allowed to decide, the attempt is refused and recorded in the audit history as Approval Refused, with where it came from. A requester whose tool does not allow self-approval is told exactly that, rather than simply that they are not an approver.

Default Approvers

If the Rules page names nobody, any organization administrator can approve or reject the request.

The space owner as approver

Choose Space owner as the approver and the owner of the space a connection is homed in approves its calls. In the Organization space, which has no owner, the admins approve instead.

The Approval Process

For Approvers

When a request needs approval:

  1. Email Notification: Receive an email with Approve and Reject buttons
  2. Click to Review: Either button opens the request in the Control Room with your choice ready. Nothing is decided until you confirm there
  3. Review Details: See why it needs approval, every field the call will send, the agent's explanation, and who is involved (see Request Details)
  4. Decide: Confirm with one click, or pick the other option

If the request was raised in Claude or ChatGPT, you can also decide it on the approval card in the conversation (see below).

For AI Agents

When a tool call requires approval, airlock's response depends on what the agent's MCP client supports:

  • SEP-2663 Tasks Extension: if the request used the 2026-07-28 protocol version and declared the tasks extension on that same tools/call (via _meta['io.modelcontextprotocol/clientCapabilities'].extensions['io.modelcontextprotocol/tasks']), airlock returns a CreateTaskResult instead of the payloads below: a flat object with resultType: "task", taskId, status: "working", createdAt, lastUpdatedAt, ttlMs, pollIntervalMs, and statusMessage (which includes the approval URL). The client polls tasks/get with the taskId, repeating the same declaration on each poll, to check for resolution: when approved, status becomes "completed" and the result includes the tool's output; when rejected, status becomes "cancelled". On an older protocol version the declaration is ignored and one of the surfaces below applies. Microsoft 365 Copilot is excepted even when it declares the extension, because it polls a task without telling the user anything; it receives the polling payload below instead. See MCP Tasks for the wire details, including tasks/cancel.
  • In-agent approval card (MCP Apps): if the client supports the MCP Apps UI extension (but did not declare the tasks extension), airlock returns an interactive approval card that renders directly in the conversation via the airlock_approval_card tool. In Claude and ChatGPT, when the person viewing it may decide the request, the card shows Approve and Reject, so they decide without leaving the conversation. The buttons follow the same rules as the Control Room (who may approve, self-approval, security blocks, the AI Use Policy), and the trail records the decision as made in AI chat. The agent cannot press them: they work only from the card itself, and only in apps that keep the agent away from the card. Other AI apps, and everyone who may not decide the request, see a link to the request in the Control Room, which every card also carries. After you approve on the card in Claude, tell Claude to continue: the card does not write a message into the conversation for you, so the agent picks up the result on your next message. In ChatGPT the card hands the agent its turn itself. An admin can turn the buttons off under Settings → Security → Approvals in AI chat. In ChatGPT, if the buttons are missing or do nothing after an update, open ChatGPT's settings, find the airlock connector under Apps & Connectors, choose Refresh, and start a new chat: ChatGPT keeps its own copy of a connector's tools.
  • SEP-1036 Elicitation: if the client implements URL elicitation (but not the tasks extension), airlock sends an elicitation asking the human user to open the approval URL directly.
  • Polling: otherwise, airlock returns a structured PENDING_APPROVAL response containing a requestId, an approvalUrl, a taskId, and a human-readable message, and the agent tells the user about the pending request with its approval link, then checks the airlock/check_status tool with the requestId when the user asks (the response message spells out the call to make). An agent running unattended polls it instead, roughly every 15 seconds.

Once the approver decides:

  • Approved: The operation executes and returns results on the next poll/elicitation completion. For tasks extension clients, tasks/get returns status: "completed" with the tool's output.
  • Rejected: the operation is not executed. For tasks extension clients, tasks/get returns status: "cancelled". For other clients, airlock/check_status returns a REJECTED status (no reason is returned).

Approvers are notified on whichever channels your organization has enabled under Settings → Organization → Notifications: email, Slack, and Microsoft Teams. Email is on by default and can be turned off there. Every notification carries a direct link to the approval page in the Control Room.

Request Details

The request page shows, from top to bottom:

  • Header: who wants to do what, in which integration, with the risk, the status, the time left before it expires, when it was requested, and the AI client it came through. The client is shown by product name (for example Claude Code), with the name and version the client itself reported beside it when they differ
  • Why this needs approval: the policy rule that matched, or, when a security block on the requester escalated the call, that block instead of a rule
  • Call path: the client, airlock, and the target service, the same view the requests list draws
  • What will happen if you approve: every field the call will send, in a Friendly view (one line per field, nested values flattened) or as Raw JSON. Secret-looking fields are redacted
  • Agent's explanation (not verified by Airlock): the agent's own account of the call, if it gave one (see approval_note). It is the agent's claim: compare it with the fields above, which are what will actually be sent
  • Who's involved: who requested it, who it was requested on behalf of when a service account named someone (marked (caller-asserted), because the caller supplied it), and who can approve
  • Trail: every step of the request so far, with when and where it happened (Control Room, AI chat, Slack, or Teams): requested, a refused attempt to decide (with the reason), approved (with whether the call then ran or failed, what was written, and the result), rejected, or expired
  • Technical details: request ID, session, client, transport, source IP, and policy ID

Who can see a request

Admins see every request in the organization. A member sees a request, on Pending Requests and on its own page, when they:

  • raised it themselves
  • are the person a service account raised it on behalf of, when that name matched a member of your organization
  • are an assigned approver, directly or through a space

Seeing a request is not the same as deciding it. A member a service account acted for can follow the request and its trail, but approving or rejecting it still takes an admin or an assigned approver.

Opening the record in the target system

When a request acts on one specific existing record, the request page, the Slack message and the Teams card also carry a link that opens that record in the target system itself, for example Open in Odoo for a sale order waiting to be confirmed. That way you can check the record where it lives before you decide.

The link is built by airlock from two things only: the instance address and database your admin configured on the server, and the record id in the call's arguments. airlock never contacts the target system to build it, and never turns anything the agent wrote into a link. A link always points at the configured instance and nowhere else.

Today this covers the Odoo integration: confirming, cancelling, posting and validating records, and reading, updating, deleting or messaging a single record. A call that names several records, or creates a new one, gets no link, because there is no single existing record to open.

Anything you do in the target system itself happens outside airlock. If you confirm the order in Odoo directly, Odoo records that change, and the airlock request is still waiting for a decision.

Notifications

Each channel has its own on/off toggle under Settings → Organization → Notifications.

Email

Approvers receive emails containing:

  • Operation (tool) name
  • Request ID
  • Approve and Reject buttons. Each opens the request in the Control Room with that choice ready, and you confirm with one click. The link alone decides nothing, so a mail scanner that opens it, or someone you forward the email to, cannot approve anything: confirming needs your own sign-in as an approver
  • A plain link to review the request first (full parameters are shown on the request page)

Slack

An admin connects Slack under Settings → Organization → Notifications and picks a channel. Every new approval request is posted there, and unless messages go to the channel only, each person who can approve it also gets the same message as a direct message from the airlock app. The message shows the tool name, the requester, the person it was requested on behalf of (if any), and the reviewers. A service account that raised the request is named as such, for example Billing bot (service account), and a person it named is shown as On behalf of with (caller-asserted) after the name.

Below that, What will be sent to the tool lists the call's fields one per line (up to 40, with long values cut). When some don't fit, the message says how many more fields are not shown and points to the request page, which has every field. The agent's explanation follows in its own section, under the same not verified label as on the request page.

Assigned reviewers are @-mentioned when their Slack account matches their airlock email. The channel message and every direct message are updated in place when the request is approved, rejected, or expires.

Send approval requests to chooses where messages go: the channel and a direct message to each approver (the default), direct messages only, or the channel only. Direct messages go to a request's named approvers, the members of an approving space, or your admins when nobody is named, at most 10 per request. People are matched to Slack by their airlock email, and anyone without a match is skipped; the channel still has the request. A Slack connection made before direct messages existed posts to the channel only until an admin reconnects it once.

Approve and Reject decide the request from Slack, in the channel or in a direct message. Approving a destructive call asks you to confirm first. A click counts only when your Slack account belongs to the workspace your organization connected and its confirmed email is an active airlock user who may approve this request; the same rules apply as in the Control Room, including whether you may approve your own request. A click that does not count decides nothing, and only you see a short reply saying why; airlock records it in the request's trail. Every copy of the message then shows the outcome, who decided and when. Review request opens the request in the Control Room, which always works.

A skill or rules change is shown in Slack as one line, how many lines change and in what, rather than the new text itself. Open the request to see the full change.

Microsoft Teams

Connect Microsoft Teams in the same place and pick a team and channel. New requests arrive as an Adaptive Card, and the resolution is posted as a reply in the same thread. The card carries the same content as the Slack message: the requester (with (service account) after a service account's name), On behalf of with (caller-asserted) when a service account named someone, What will be sent to the tool (up to 40 lines, with a count of any fields not shown), and the agent's explanation. Unlike Slack, the card has no Approve or Reject buttons: it links to the Control Room, where the decision is made.

Agent Observation

Agents observe the decision via the mechanism they received, as described in "For AI Agents" above. Clients that received a CreateTaskResult poll tasks/get with the taskId. Other clients poll the airlock/check_status tool (with the requestId) or complete the elicitation, roughly every 15 seconds, until the request resolves.

Request Expiration

Pending requests expire automatically. The default is 24 hours; an admin can change it for the whole organization on the Rules page → Approval timeout (from 10 minutes to 7 days). The timeout is set when a request is raised, so a change applies to new requests only.

A background job runs every 5 minutes, so a request is marked expired within about five minutes of its deadline. An expired request is never executed: the agent sees status TIMEOUT when it polls, and the expiry is written to the audit trail.

Best Practices

Quick Response

Set up multiple approvers to ensure someone is always available to respond promptly.

Clear Context

When configuring policies, consider what information approvers need to make decisions.

Audit Trail

All approval decisions are logged:

  • Who approved/rejected
  • When the decision was made, and from where (Control Room, Slack, or Teams)
  • The request details
  • Refused attempts to decide, with the reason

The request page shows the same history for that one request as its Trail, including what the call wrote and returned once it ran, so you can follow a single request end to end without searching the History page.

Escalation

For time-sensitive operations, consider:

  • Multiple approvers for redundancy
  • Clear documentation of approval criteria
  • Backup approval processes

Common Patterns

Manager Approval

On the Rules page, set the category of expense-related tools to Approval and name your managers as the approvers.

Security Team Approval

Set the Write category of connectors that modify or delete data to Approval, and name the people on your security team as the approvers.

Multiple Approvers for Redundancy

Name several people as the approvers of the same category or tool. Any one of them can approve the request, ensuring coverage when team members are unavailable.