Requests
Ask users for approvals, choices, answers, and permissions
Request types
| Kind | User action | Example |
|---|---|---|
| approval | Tap Approve or Reject | "Deploy to production?" |
| choice | Tap one of the options, or type a custom answer via the built-in "Other" field | "PostgreSQL / SQLite / MongoDB" |
| question | Type a free-text answer | "What should I name the project?" |
| permission | Allow, Always Allow, or Deny | "Allow: Bash(npm install stripe)" |
/api/agent/eventsCreate a request via REST. The request appears as an interactive card in the user's Nod app.
typerequiredtitlerequireddescriptionrequiredkindrequiredoptionsconversation_idtask_run_idPOST /api/agent/events
X-Nod-Agent-Id: agt_abc123
X-Nod-Secret: nod_abc123...
{
"type": "decision",
"title": "Deploy to production?",
"description": "Build #42 passed all tests.",
"kind": "approval"
}{
"type": "decision",
"title": "Database?",
"description": "Which database for this project?",
"kind": "choice",
"options": ["PostgreSQL", "SQLite", "MongoDB"]
// No need to add "Other" — the app automatically includes
// a free-text field so the user can type a custom answer.
}{
"type": "decision",
"title": "Project name?",
"description": "What should I name the project?",
"kind": "question"
}{
"status": "ok",
"decision_id": "dec_xyz"
}WebSocket frameCreate a request via WebSocket. Same fields, plus permission-specific options.
allows_alwaysalways_allow_labelalways_allow_options{
"type": "decision",
"title": "Deploy to production?",
"description": "Build #42 passed all tests.",
"kind": "approval",
"conversation_id": "conv_abc123"
}{
"type": "decision",
"title": "Allow: Bash(npm install stripe)",
"description": "The agent wants to run this command.",
"kind": "permission",
"allows_always": true,
"always_allow_options": [
{ "pattern": "Bash(npm install *)", "label": "All npm installs" },
{ "pattern": "Bash(npm install stripe)", "label": "This command" }
],
"conversation_id": "conv_abc123"
}Receiving responses
When the user acts on a request, your agent receives a single decision_resolved event via WebSocket or webhook. Check the status field to determine what happened:
| Status | Meaning | Read from |
|---|---|---|
| approved | User approved the request | note (optional comment) |
| rejected | User rejected the request | note (optional reason) |
| responded | User answered a question or choice request | note (the answer text) |
| dismissed | User dismissed without action | — |
decision_resolved eventDelivered via WebSocket if online, otherwise POSTed to your agent's webhook_url.
decision_idstatusnotetitledescriptioncreated_attask_run_idalways_allowalways_allow_patternDismissed requests do not notify the agent
decision_resolved event is delivered to the agent. Your agent will not receive any notification — design your timeout handling accordingly.{
"type": "decision_resolved",
"decision_id": "dec_xyz",
"status": "approved",
"note": "Go ahead",
"title": "Deploy to production?",
"description": "Build #42 passed all tests.",
"conversation_id": "conv_abc123"
}{
"type": "decision_resolved",
"decision_id": "dec_xyz",
"status": "responded",
"note": "nod-payments-api",
"title": "Project name?",
"description": "What should I name the new project?",
"conversation_id": "conv_abc123"
}{
"type": "decision_resolved",
"decision_id": "dec_xyz",
"status": "approved",
"always_allow": true,
"always_allow_pattern": "Bash(npm install *)"
}Resolve your own requests
If the user answers in chat instead of tapping the card, resolve the pending request yourself so it doesn't stay open.
/api/agent/decisions/resolveResolve a non-permission request created by your agent.
decision_idrequirednotePOST /api/agent/decisions/resolve
X-Nod-Agent-Id: agt_abc123
X-Nod-Secret: nod_abc123...
{
"decision_id": "dec_xyz",
"note": "User said in chat: use PostgreSQL"
}{
"status": "resolved",
"decision_id": "dec_xyz"
}Task proposals
Propose a scheduled task to the user. If approved, the task is auto-created.
/api/agent/eventsSend a task proposal.
typerequiredtitlerequiredtask_namerequiredtask_promptrequiredtask_schedulerequired{
"type": "task_proposal",
"title": "Schedule: Daily summary",
"task_name": "Daily summary",
"task_prompt": "Summarize git activity",
"task_schedule": "0 9 * * 1-5"
}