Documentation
Four steps: create an account, connect Slack, call the API before a risky action, and let a human decide. No infrastructure to run — the queue, the Slack bot, and the audit log are already live.
Go to the sign-up page and create an organization — just a name, email is optional. You'll immediately get back an API key that looks like ag_xxxxxxxxxxxxxxxxxxxxxxxx.
This key identifies your organization, not an individual agent. Every request your agents send — one agent or twenty — uses this same key, and every approval request created with it belongs to your org and only your org.
Log in, go to Settings → Slack Integration, and click Add to Slack. You'll be sent to Slack to pick the workspace you want approvals posted to, then redirected back — connected.
chat:write, so AgentGate can post approval cards — and click Allow.There's no bot token to create or paste, and nothing to edit in a config file. Approval requests default to posting in #agent-approvals — create that channel in your workspace, or override it per-request (see below).
Prefer Microsoft Teams? In the same Settings page, add an Incoming Webhook URL from your Teams channel's connector settings instead — no OAuth needed for Teams.
Wherever your agent is about to do something that's expensive to get wrong — send an email, delete a record, deploy, move money — send a POST /api/v1/approvals request first, then wait for a decision before continuing.
pip install useagentgate
The install command is useagentgate — the import stays agentgate. Requires Python 3.10+, no other setup; the SDK already points at the live AgentGate API.
from agentgate import AgentGate
gate = AgentGate(api_key="ag_your_key_here")
result = await gate.request_approval(
action="send_email",
description="Send Q4 pricing proposal to client@acme.com",
context={"deal_value": "$50,000", "recipient": "client@acme.com"},
risk_tier="high",
timeout_minutes=30,
)
if result.approved:
send_the_email()
elif result.rejected:
log_skipped(result.reason)
else:
log_skipped("timed_out")Not in an async context? Use from agentgate import AgentGateSync instead — same method, no await.
BaseTool with ApprovalRequiredTool instead of calling request_approval directly, zero extra boilerplate.No Python, or want to see exactly what the SDK does under the hood? Same two calls, by hand:
curl -X POST https://agentgate-w5qx.onrender.com/api/v1/approvals \
-H "X-AgentGate-Key: ag_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"action": "send_email",
"description": "Send Q4 pricing proposal to client@acme.com",
"context": { "deal_value": "$50,000", "recipient": "client@acme.com" },
"risk_tier": "high",
"timeout_minutes": 30
}'
# then poll until status isn't "pending":
curl https://agentgate-w5qx.onrender.com/api/v1/approvals/{id} \
-H "X-AgentGate-Key: ag_your_key_here"Set risk_tier to low / medium / high / critical — this controls the default timeout (critical gets the shortest) and how the request is flagged in Slack. Leave it out and it defaults to medium.
As soon as the request is created, a message posts to your connected Slack channel with the action, description, risk tier, and any context you sent — plus two buttons.
status: "approved".timed_out — silence is never treated as approval.Every request, decision, and reason is recorded in your Audit Log(Dashboard → Audit Log), exportable as CSV.
langchain-agentgate wraps any existing BaseTool so it requires approval before it runs — no rewriting the tool, no restructuring your agent. It's a thin layer around what you already built.
pip install langchain-agentgate
from agentgate import AgentGate
from langchain_agentgate import ApprovalRequiredTool
gate = AgentGate(api_key="ag_your_key_here")
# send_email_tool is any BaseTool you already have — unchanged
gated_send_email = ApprovalRequiredTool(
wrapped_tool=send_email_tool,
gate=gate,
risk_tier="high",
timeout_minutes=15,
)
# use gated_send_email anywhere send_email_tool would have gone —
# same name, same input schema, same output type
agent_executor = create_agent_executor(tools=[gated_send_email, ...])
result = await agent_executor.ainvoke({
"input": "email the Q4 proposal to john@acme.com"
})That's the whole integration. gated_send_email has the same name and args schema as the tool it wraps, so nothing else in your agent needs to know it's gated. When the agent calls it, execution pauses, a request posts to Slack/Teams exactly like the REST flow above, and the call only resumes once a human responds — or the timeout hits.
| Parameter | What it does |
|---|---|
| wrapped_tool | The existing BaseTool to gate. Required. |
| gate | An AgentGate (async) or AgentGateSync instance. Required. |
| risk_tier | low / medium / high / critical. Defaults to medium. |
| timeout_minutes | Auto-rejects if nobody responds in time. Defaults to 30. |
| approver | Optional Slack handle to @mention directly, e.g. "@sarah". |
| slack_channel | Optional override of the default connected channel. |
Officially listed in LangChain's own integrations docs and published on PyPI.
crewai-agentgate is the same wrapper pattern as the LangChain integration, built for CrewAI's BaseTool. Gate any tool you give an Agent — no restructuring the crew.
pip install crewai-agentgate
from agentgate import AgentGate
from crewai_agentgate import ApprovalRequiredTool
gate = AgentGate(api_key="ag_your_key_here")
# publish_content_tool is any BaseTool you already have — unchanged
gated_publish = ApprovalRequiredTool(
wrapped_tool=publish_content_tool,
gate=gate,
risk_tier="high",
timeout_minutes=15,
)
# give gated_publish to an Agent anywhere publish_content_tool would have gone
publisher = Agent(
role="Content Publisher",
goal="Publish approved content to the appropriate platforms",
tools=[gated_publish],
)Same behavior as the LangChain wrapper: gated_publish keeps the same name and args schema as the tool it wraps, execution pauses when the agent calls it, a request posts to Slack/Teams, and the call only resumes once a human responds — or the timeout hits. Parameters (risk_tier, timeout_minutes, approver, slack_channel) are identical to the LangChain version above.
Published on PyPI.
Frequently asked
It doesn't connect to a specific agent — it connects to your organization. Here's the full path a single approval request takes:
POST /api/v1/approvals using your org's X-AgentGate-Key.GET /api/v1/approvals/{id} — sees the new status and continues or stops.So the Slack connection is a one-time, per-organization setup step — you do it once in Settings, and every agent, script, or process that uses your API key automatically posts into that same workspace. You never connect Slack per-agent, and you never touch a bot token.
Reference
All requests need X-AgentGate-Key: ag_your_key_here. Full interactive reference: https://agentgate-w5qx.onrender.com/docs.
| Endpoint | What it does |
|---|---|
| POST /api/v1/approvals | Create an approval request. Posts to Slack/Teams if connected. |
| GET /api/v1/approvals/{id} | Check a request's status. Poll this until it's not pending. |
| GET /api/v1/approvals | List requests, filterable by status and risk_tier. |
| POST /api/v1/actions/log | Log a completed action to the audit trail without requiring approval. |
| GET /api/v1/audit-log | Retrieve or export (?export_csv=true) the audit trail. |