Impri documentation
Add a human approval step to any AI agent. An agent proposes an action, a person approves or rejects it in the inbox, and only then does it run.
What is Impri
Impri is a human-in-the-loop gate for AI agents and automations. It does not act on its own — it holds an agent's proposed action until a human says yes. Two moving parts:
- Approval inbox — a web app where you review and approve/reject the actions your agents propose (and can edit them first).
- Watchers — scheduled checks (a subreddit, an RSS feed, a web page) that drop matching items into the inbox automatically, no code required.
Agents integrate over a small REST API or the MCP server. It is open-core (MIT) and self-hostable.
Two ways to use it
Self-host
docker compose up and you have the full core running locally in a few
minutes. This is the complete, production-ready path today. Start below.
Hosted cloud (beta)
A hosted instance runs at app.impri.dev / api.impri.dev.
Self-serve signup isn't open yet — reach out on GitLab
for early access. Everything below applies; just swap the base URL.
Quickstart (self-host)
From zero to your first approved action in under five minutes. You need Docker and
curl.
1. Start Impri
git clone https://gitlab.com/sekera.radim/impri.git
cd impri
# set a strong secret for signed webhooks
export WEBHOOK_SECRET=$(openssl rand -hex 32)
docker compose up -d
The API runs on http://localhost:8484 and the web inbox on
http://localhost:8080. On first start the server prints a one-time
bootstrap admin key to its log:
docker compose logs server | grep "Admin API Key"
# Admin API Key: im_... (shown once, then hashed — store it now)
export ADMIN_KEY="im_..."
Paste that key into the web inbox login to sign in.
2. Create a key for your agent
The bootstrap key has admin scope. Mint a narrower actions key
for the agent so you can rotate it independently:
curl -s -X POST http://localhost:8484/v1/keys \
-H "Authorization: Bearer $ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"my-agent","scopes":["actions"]}'
# → { "key": "im_...", ... } store as $AGENT_KEY
3. Propose an action
This is the single call your agent makes before doing anything consequential:
curl -s -X POST http://localhost:8484/v1/actions \
-H "Authorization: Bearer $AGENT_KEY" \
-H "Content-Type: application/json" \
-d '{
"kind": "email.send",
"title": "Send welcome email to jane@acme.com",
"preview": { "format": "markdown", "body": "To: jane@acme.com\n\nWelcome aboard!" },
"expires_in": 3600,
"editable": ["preview.body"]
}'
# → { "id": "act_...", "status": "pending", ... }
4. Approve it
Open the inbox at http://localhost:8080. The pending action shows up as a
card with its preview. Click Approve or Reject. If you
set editable, you can edit the content first — the agent receives the final,
human-edited version.
5. Act only if approved, then report back
# poll until the decision arrives
curl -s http://localhost:8484/v1/actions/act_... \
-H "Authorization: Bearer $AGENT_KEY"
# → { "status": "approved", ... } (or rejected / expired)
# your agent performs the action, then closes the loop:
curl -s -X POST http://localhost:8484/v1/actions/act_.../result \
-H "Authorization: Bearer $AGENT_KEY" \
-H "Content-Type: application/json" \
-d '{"status":"executed","detail":"email sent"}'
pending → approved → executed. If the human
rejects, the agent does nothing — that's the whole point.Wire up an agent
A complete, dependency-free example agent (Node 18+) that runs the whole loop lives in
the repo at examples/approval-gated-agent.mjs:
IMPRI_API_KEY=im_your_key \
IMPRI_BASE_URL=http://localhost:8484 \
node examples/approval-gated-agent.mjs
It proposes an action, waits for you to approve it in the inbox, then runs and reports
the result. Edit the task and replace performAction() with the
real thing you want gated (send an email, deploy, issue a refund, spend money…).
MCP (Claude & other agents)
If your agent is an LLM, you usually don't write the loop by hand — give it the Impri MCP
server and it can request approval as a tool call. Published on npm as
@impri/mcp:
{
"mcpServers": {
"impri": {
"command": "npx",
"args": ["-y", "@impri/mcp"],
"env": { "IMPRI_API_KEY": "im_...", "IMPRI_BASE_URL": "http://localhost:8484" }
}
}
}
It exposes tools to push an action, await the decision, report the result, and manage watchers — the same API, agent-native.
Actions
An action is one approval request. Fields:
| Field | Notes |
|---|---|
kind * | Free-form label, e.g. email.send, deploy. |
title * | One-line summary shown in the inbox. |
preview * | { format: "markdown" | "plain" | "diff", body } — what the human reviews. |
payload | Any JSON your agent needs back with the decision. |
target_url | Optional link to the thing being acted on. |
expires_in | Seconds until it auto-expires (default 3 days). |
editable | Paths the human may edit before approving, e.g. ["preview.body"]. |
States: pending → approved | rejected | expired, then
executed | execute_failed once the agent reports back.
Watchers (no code)
A watcher checks a source on a schedule and drops matches into the inbox — the no-code
way to feed Impri. Create them in the web UI (Watchers → Create) or via
POST /v1/watchers. Three kinds:
| Kind | Watches |
|---|---|
reddit_search | A subreddit for posts matching a query. |
rss | An RSS/Atom feed for new entries. |
url_diff | A web page for content changes. |
Optional keywords score/filter results before they reach you; a schedule sets how often it runs. Each surfaced item becomes a pending action you review.
Keys & scopes
API keys start with im_ and are hashed at rest. Scopes: admin
(full control, billing, keys, watchers) and actions (create actions + report
results — give this to agents). Manage keys via /v1/keys.
API reference
Base URL <host>/v1. Auth header Authorization: Bearer im_....
Full spec at /v1/openapi.json.
| Method | Path | Description |
|---|---|---|
| POST | /actions | Propose an action for approval |
| GET | /actions | List actions (?status=pending) |
| GET | /actions/:id | Get one action + its decision |
| POST | /actions/:id/decision | Approve or reject |
| POST | /actions/:id/result | Report execution result |
| GET / POST | /watchers | List / create watchers |
| PATCH / DELETE | /watchers/:id | Update / delete a watcher |
| GET / POST / DELETE | /keys | List / mint / revoke API keys |
| GET | /project/export | GDPR export of project data |
| DELETE | /project/data | Erase project data |
Self-hosting
docker compose up runs the server + inbox with a persistent SQLite volume.
Key environment variables:
| Var | Purpose |
|---|---|
WEBHOOK_SECRET | Signs outbound webhooks (set a strong random value). |
BASE_URL | Public URL of the API (used in links). |
APP_URL | Public URL of the web inbox (checkout/return links). |
SMTP_* / NTFY_* | Optional email / ntfy notifications on new approvals. |
VAPID_* | Optional web-push notifications. |
REDIS_URL | Optional — Redis-backed rate limiting for multi-instance. |
STRIPE_* | Optional — only if you run the paid tiers yourself. |
Full guide: self-hosting.md (env, backups, reverse proxy).
More docs
- Quickstart — the full step-by-step
- How to add human approval to an AI agent
- Webhooks — HMAC verification, retries, polling fallback
- Self-hosting — Docker, env, backups
- Source on GitLab · @impri/mcp on npm