Noddocs

Requests & Decisions

Structured ways for agents to get human input: approvals, choices, questions, and permissions

Overview

Requests are structured interactions where the agent asks for human input and waits for a response. Unlike chat messages, requests have defined response types — users respond by tapping a button, selecting an option, or typing an answer.

In the Nod app, requests appear as interactive cards. Users can respond from the chat view or the dedicated Requests page.

Four request types

KindUser actionResponseExample
approvalTap Approve or Rejectstatus: approved/rejected + optional note"Deploy to production?"
choiceTap an option or type a custom answer via "Other"status: responded + selected option in note"PostgreSQL / SQLite / MongoDB"
questionType a free-text answerstatus: responded + answer in note"What should I name the project?"
permissionAllow, Always Allow, or Denystatus: approved/rejected + optional pattern"Allow: Bash(npm install stripe)"

Approval requests

The simplest request type. The agent asks a yes/no question. The user taps Approve or Reject.

Create an approval request
{
  "type": "decision",
  "title": "Deploy to production?",
  "description": "Build #42 passed all tests. Ready to deploy to the production cluster.",
  "kind": "approval"
}
User response (via WebSocket or webhook)
{
  "type": "decision_resolved",
  "decision_id": "dec_xyz",
  "status": "approved",        // or "rejected"
  "note": "Go ahead",          // optional note from user
  "conversation_id": "conv_abc123"
}

Choice requests

Present a set of options for the user to pick from. Options render as tappable buttons in the Nod app.

{
  "type": "decision",
  "title": "Database?",
  "description": "Which database should we use for this project?",
  "kind": "choice",
  "options": ["PostgreSQL", "SQLite", "MongoDB"]
}

The Nod app renders each option as a tappable button. An "Other..." button is automatically included below the options — tapping it opens a free-text field where the user can type a custom response instead of picking a predefined option. You don't need to add "Other" to your options array; the app handles it for you. Either way, the user's selection (or typed text) appears in the note field of the resolution.

Question requests

Ask for free-text input. The user sees a text field and can type any response.

{
  "type": "decision",
  "title": "Project name?",
  "description": "What should I name the new project?",
  "kind": "question"
}

When the user submits their answer, your agent receives a decision_resolved event with status: "responded" and the typed text in the note field.

Permission requests

Permission requests are typically used by hook systems (like our CLI's PreToolUse hook) to gate specific agent actions. They include "Always Allow" options so users can persist permission patterns.

{
  "type": "decision",
  "title": "Allow: Bash(npm install stripe)",
  "description": "The agent wants to run: npm install stripe",
  "kind": "permission",
  "allows_always": true,
  "always_allow_label": "Always allow npm install",
  "always_allow_options": [
    { "pattern": "Bash(npm install *)", "label": "All npm installs" },
    { "pattern": "Bash(npm install stripe)", "label": "This exact command" }
  ]
}

When the user taps "Always Allow" and selects a pattern, it's returned in the resolution so your system can persist the rule.

Request lifecycle

StatusMeaning
pendingWaiting for user response
approvedUser approved (approval/permission kind)
rejectedUser rejected (approval/permission kind)
respondedUser responded with text or selection (question/choice kind)
dismissedUser dismissed without responding

Your agent receives the resolution via WebSocket (decision_resolved event) or webhook delivery. The resolution includes the status, optional note, and any "always allow" pattern the user selected.

Requests without a conversation

Requests sent during task runs or from approval-only agents may not have a conversation context. Set conversation_id to null to create a request that appears only in the Requests page, not in any chat thread:

{
  "type": "decision",
  "title": "Approve refund #4821?",
  "description": "$730 refund to customer@example.com",
  "kind": "approval",
  "conversation_id": null
}
See Requests API for the full endpoint reference.