Skip to content

Approvals ​

Bots read freely, but anything that sends, creates, changes or deletes outside Lex waits for a person to approve it. Each tool has a risk class:

RiskExamplesDefault
readFetch emails, list channelsRuns on its own
writeSend an email, create an issueAsks first
high_impactDelete a repositoryAlways asks, even if a policy allows auto-run

Workspace admins can change the defaults per connector with policies: block tools, always ask, or let specific write tools run on their own.

In a chat ​

When a run needs approval, the stream sends approval.required and then run.waiting:

json
{ "approvalId": "apr_1", "callId": "call_9", "toolSlug": "GMAIL_SEND_EMAIL",
  "risk": "write", "summary": "Send email to bob@example.com", "expiresAt": "2026-10-22T10:15:00.000Z" }

Show the summary to the user and send their decision:

http
POST /approvals/apr_1/decision
x-lex-client: my-app
Content-Type: application/json

{ "decision": "approve" }

decision is approve or reject. The run resumes on its own: a rejected tool reports tool.completed with status: "rejected" and the bot carries on without it.

GET /approvals/pending lists everything waiting on the signed-in user, across all bots.

Guarantees ​

  • Only the requester decides. Other users get 404 NOT_FOUND.
  • Bound to the exact action. An approval covers one tool call with one set of arguments. If the arguments change, it no longer applies.
  • Single use. Once used, an approval can't run the action again.
  • Expires. Undecided approvals expire at expiresAt; the tool then completes with status: "expired".

Calling tools directly ​

POST /integrations/tools/{toolSlug}/execute runs a tool outside a chat. A write tool answers 409 APPROVAL_REQUIRED with details.approvalId; approve it as above, then repeat the same request with that approvalId:

json
{ "arguments": { "to": "bob@example.com", "body": "Hello" }, "approvalId": "apr_1" }

Lex by Gavalytics AI