Zapnoty — Agents

API Documentation

REST API for notifications via Telegram and Max. Subscribers, OTP, broadcasts, forms, helpdesk.

Agents

An agent is a named identity with rights: an AI agent, a cron script or a CI pipeline. The agent asks a human questions, requests approvals and accepts tasks; the human answers with buttons in Telegram/Max, the app or the dashboard. An agent is created together with an API key (project settings → “Agents”) or automatically when an MCP client connects.

Ask a human

The question is delivered to the agent’s participants as a card with buttons. The answer is an option or free text (if allowed). 1 credit per delivery.

POST /v1/agent/ask
Authorization: Bearer zn_live_...
{
"question": "Ship v2.4.1 to production?",
"options": ["Yes", "No"],
"comment": "All tests green",
"ttl_minutes": 60
}
→ 202 {
"request_id": "agrq_3xK...",
"status": "pending",
"deliveries": 1
}

Fetching the answer — long-poll

We hold the connection up to 45 seconds (wait, default 25) — no public address needed: works from cron, CI and a laptop. status=pending — call again.

GET /v1/agent/requests/agrq_3xK...?wait=25
→ no answer yet: { "status": "pending", ... }
→ the human pressed a button: {
"status": "answered",
"answer": "Yes",
"reason_code": "answered",
"answered_by": "Peter",
"answered_via": "telegram"
}

Approving an external action

For actions outside Zapnoty (payment, deploy, deletion). The human sees [Approve]/[Decline]. Params are recorded in the audit — pass them honestly.

POST /v1/agent/approve
{
"action_type": "pay_invoice",
"description": "Pay invoice #1042 for 45 000 ₽",
"params": { "invoice": 1042, "amount": 45000 }
}
→ 202 { "request_id": "agrq_...", "status": "pending" }
# reason_code in the long-poll answer:
# approved_full → perform the action
# rejected_by_human → do NOT perform, do not re-ask
# expired → no answer within TTL

Who receives the question

By default the question goes to every recipient of the agent — whoever answers first wins, the rest see “Answered by Peter”. To ask one specific person, pass principal: a recipient id from the dashboard or a sub_… subscriber id. Recipients are assigned by the owner in the “Agents” tab — an agent cannot add them itself.

Rights and grants

Agent rights are configured across 18 resources: none · read · write · ask. “Ask” — the call returns 202 grant_required, the human approves once or for a period, and the retried call passes on the grant. 403 scope_forbidden — ask the owner to widen rights; 429 budget_exceeded — daily cap, stop.

# A resource with the “ask” level
POST /v1/broadcast → 202 {
"request_id": "agrq_...",
"reason": "grant_required",
"hint": "Poll the request; retry the call after approval"
}
# The human taps “Allow for a day” → a grant. The retry passes:
POST /v1/broadcast → 200 { "job_id": ... }

A successful call made on a grant returns the X-Agent-Grant-Expires header — the moment the grant expires (or never). It tells you how long you can keep working without asking the human again.

Commands and tasks (wake)

The agent publishes commands — the human sees buttons in chat and the app, can type free text (if allowed) and schedule runs (recurring). The agent.task.created push webhook is available from the Basic plan.

# Publish commands (buttons for the human)
PUT /v1/agent/commands
{ "commands": [
{ "key": "deploy", "label": "🚀 Deploy" },
{ "key": "status", "label": "📊 Status" }
] }
# Pull tasks (long-poll; the human tapped a button or typed)
GET /v1/agent/tasks?wait=25
→ { "task": { "task_id": "agtk_...", "command": "deploy", "text": "" } }
# Result — back to the human, signed by the agent
POST /v1/agent/tasks/agtk_.../complete
{ "result": "Shipped v2.4.1, no errors" }

Sandbox

With the test key, questions are not delivered and no credits are charged — run the whole scenario, including decline and expiry.

# Test key zn_test_: the question is not delivered, the outcome is simulated
POST /v1/agent/ask
{
"question": "...",
"_test_directives": { "decision": "answered", "answer": "Yes", "delay_ms": 2000 }
}

MCP

Claude Code and Cursor connect to mcp.zapnoty.com via OAuth with a rights picker (“Safe” — sending requires confirmation). Tools: zapnoty_ask_user (blocking — waits for the human), zapnoty_request_approval, zapnoty_check_answer, zapnoty_get_tasks and zapnoty_complete_task (tasks from the human), zapnoty_set_commands (chat buttons), zapnoty_send_to_thread (message without a question), zapnoty_request_key and zapnoty_verify_mandate.

Related sections