Connections
How events flow between your agent, Nod, and the Nod app
The delivery model
To understand connections, you first need to understand how Nod delivers events. Nod sits in the middle between your agent and the Nod app(where users interact). Both sides push events into Nod, and Nod delivers them to the other side.
Agent → Nod → App
When your agent sends something (a message, a request, an activity log), it goes to Nod via REST API or WebSocket. Nod stores it and pushes it to the Nod app in real time. The app is always connected to Nod — so the user sees new messages, requests, and activity instantly.
App → Nod → Agent
When a user does something in the app (sends a message, approves a request, triggers a task), it goes to Nod. Nod then needs to deliver it to your agent. This is where the delivery channels matter:
This is the key concept
1. WebSocket — if your agent has an active WebSocket connection, the event is pushed instantly.
2. Webhook — if the WebSocket is not connected (or the push fails), and your agent has a
webhook_url configured, the event is POSTed to that URL.If neither channel is available, the event is stored and your agent can retrieve it later by polling (e.g.
GET /api/agent/tasks/triggers/pending).What gets delivered to your agent
These are the events Nod delivers to your agent when a user acts:
| Event | Trigger | Delivered via |
|---|---|---|
| user_message | User sends a chat message in the app | WebSocket push, then webhook fallback |
| decision_resolved | User approves, rejects, or dismisses a request | WebSocket push, then webhook fallback |
| task_due | Scheduled task is due to run | WebSocket push, then webhook fallback |
| task_trigger | External webhook triggers a task | WebSocket push if online, otherwise queued as pending |
On the other side, everything your agent sends (messages, requests, activity) is immediately visible to users in the app — no delivery step needed since the app maintains its own persistent connection to Nod.
Three connection methods
| Method | Direction | Best for |
|---|---|---|
| WebSocket | Bidirectional, real-time | Always-running agents that need instant communication |
| REST API | Agent → Nod (request/response) | Serverless functions, cron jobs, simple integrations |
| Webhooks | Nod → Agent (push) and External → Nod (trigger) | Receiving events when offline, triggering tasks from external services |
WebSocket (persistent connection)
The WebSocket gives you a persistent, bidirectional channel. It's the recommended approach for agents that run continuously — you can both send and receive in real time over a single connection.
wss://api.asknod.ai/ws/agent/{agent_id}What you get with a WebSocket
- Send messages, requests, activity — instantly visible to users in the app
- Receive user messages and decision responses the moment they happen
- Receive task trigger events pushed to you in real time (no polling needed)
- Online status — the app shows your agent as "online" with a live processing indicator
Auth handshake
After connecting, the first message must be an auth message with your credentials:
// Send
{
"type": "auth",
"agent_id": "agt_...",
"secret": "nod_abc123..."
}
// Receive
{
"type": "auth_ok",
"session_id": "sess_abc123",
"agent_name": "My Agent"
}When to use WebSocket
- Your agent runs as a long-lived process (daemon, background service)
- You need to receive user messages and decision responses instantly
- You want the agent to show as "online" in the app
- You want real-time task triggers (no polling)
REST API (stateless)
The REST API lets you send events to Nod with standard HTTP calls. No persistent connection needed. However, you can only push events to Nod — to receive events back, you need either a WebSocket or a webhook URL.
Sending events
The unified POST /api/agent/events endpoint accepts messages, decisions, alerts, and more:
POST https://api.asknod.ai/api/agent/events
X-Nod-Agent-Id: agt_...
X-Nod-Secret: nod_...
{
"type": "message",
"text": "Deployment complete!"
}Everything you send via REST is immediately visible to users in the Nod app, just like WebSocket. The difference is only in how you receive events back.
Receiving events (without WebSocket)
Without a WebSocket, you have two options for receiving events:
- Webhook URL — Set
webhook_urlon your agent. Nod will POST events (user messages, decision resolutions) to your URL automatically. - Polling — Periodically check for due tasks and pending triggers. Less ideal for messages/decisions since there's latency.
// Poll for due tasks GET /api/agent/tasks/due // Poll for queued webhook events GET /api/agent/tasks/triggers/pending
When to use REST only
- Serverless functions (Lambda, Cloud Functions) that can't hold a connection
- Cron jobs that run periodically
- Simple fire-and-forget messages or alerts
- Prototyping — start with REST + webhook, add WebSocket later
Webhooks
Webhooks work in two directions:
Outbound: Nod → Your agent
When your agent doesn't have an active WebSocket, Nod delivers events to the webhook_url you configured on your agent. The same events that would be pushed via WebSocket are instead POSTed to your URL.
Set it when creating or updating the agent:
POST /api/agents
{ "name": "My Agent", "avatar": "robot", "webhook_url": "https://my-server.com/nod-events" }Nod retries failed deliveries with exponential backoff (up to 3 attempts).
Inbound: External → Nod
Event-triggered tasks expose a public URL. External services (GitHub, Stripe, monitoring tools) call this URL to trigger task runs:
POST https://api.asknod.ai/webhook/{trigger_id}
{ "action": "push", "ref": "refs/heads/main", ... }If your agent is online (WebSocket), the trigger is pushed instantly as a task_trigger event. If offline, it's queued and available when the agent polls GET /api/agent/tasks/triggers/pending.
Choosing a connection strategy
| Scenario | Send events | Receive events |
|---|---|---|
| Claude Code / always-on agent | WebSocket | WebSocket (real-time) |
| CrewAI / LangChain server agent | WebSocket or REST | WebSocket + webhook for triggers |
| n8n / workflow automation | REST (HTTP Request node) | Webhook URL (n8n webhook trigger) |
| Serverless function | REST | Webhook URL |
| Simple monitoring script | REST (fire-and-forget) | Not needed |
Combine methods freely