> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs.rightbrain.ai/v-1/docs/concepts/triggers-and-runs/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.rightbrain.ai/_mcp/server. # Triggers & runs > Triggers start Rightbrain runs through API calls, webhooks, schedules, Gmail, and Slack; every run is observable, streamable, and metered. A **trigger** is what starts a run. A **run** is a single execution of a [Task](/docs/concepts/tasks) or an [agent](/docs/concepts/agents). Triggers are the front door; runs are the record of what happened. Together they're how Rightbrain moves from "a thing I built" to "a thing that operates." ## Triggers Anything that can fire an event can start a run. A trigger targets **a Task or an agent**. | Trigger | How it fires | | --------------- | ------------------------------------------ | | **API call** | A direct `POST .../run` request. | | **Webhook** | An inbound HTTP call to a public endpoint. | | **Schedule** | A cron expression runs it on a timer. | | **Gmail inbox** | A new email in a connected inbox. | | **Slack** | A message in a connected workspace. | ### Webhook triggers A webhook trigger has a public invoke endpoint: ``` POST /api/v1/public/webhook/{project_id}/{endpoint_id} ``` Authentication is either **`hmac_sha256`** (the caller signs the payload with a shared secret, sent in the configured signature header) or **`bearer_token`** (a bearer token). The auth method is fixed at creation — to switch methods, create a new trigger. Webhook triggers support optional payload mapping and idempotency, and you can rotate the secret or regenerate the endpoint. HMAC authentication supports `prefix`, `timestamp_kv`, `plain`, and `standard_webhooks` signature formats. Standard Webhooks v1 uses a Base64-encoded HMAC over the message ID, timestamp, and raw body. Its default headers are `webhook-signature`, `webhook-timestamp`, and `webhook-id`, with a default timestamp tolerance of 300 seconds. The message ID also becomes the idempotency key when no payload path supplies one. Configure `idempotency_key_path` when the sender may retry deliveries. Rightbrain remembers the extracted key for `idempotency_ttl_seconds`, preventing the same event from starting duplicate work during that window. Keep the same event ID when retrying. For a task target, a duplicate returns `409` with `error.code: "DUPLICATE_REQUEST"` and `error.original_task_run_id`. For an agent target, a duplicate returns `202` with `is_duplicate: true` and the original `event_id`. These responses do not start another run. A bad signature returns `401` with `error.code: "AUTH_FAILED"`. > **Note** > > Response behavior depends on the target. A **task**-targeted webhook runs synchronously and returns `200` with the run result in the body. An **agent**-targeted webhook returns `202` with the trigger event ID and processes the run in the background. Either way the invocation is recorded as a trigger event you can list and inspect. ### Schedule and inbox triggers * **Schedule** — a cron trigger that fires on a recurring timer. * **Gmail inbox** — fires an agent (or Task) when mail arrives in a connected Gmail inbox, passing the message through as input. Each trigger type records its own **events**, so you can see every firing and its outcome. ## Runs A run captures one execution end to end: inputs, tool calls, output, token counts, timing, and credits. ### Statuses Agent runs move through `running` → `waiting_for_human` (paused for an [approval](/docs/production/approvals)) → `completed` or `failed`. Task runs are request/response — they return the `TaskRun` directly. ### Streaming (agents) Agent runs stream **Server-Sent Events** so you can render progress live — incremental text, each tool call and its result, approval pauses, and a terminal `done` event. See [Run agents via API](/docs/api/run-agents) for the full event reference and how to handle the stream. ### Files in and out Runs handle files through a **runtime file registry**. Agents accept uploaded input files (multipart or base64), pass them between tools within a single run, and track generated files with provenance (whether a file was an input or was generated, and by which Task). A paused run resumes with its file manager intact. Files are retrievable per run: ``` GET .../task-agent/{agent_id}/run/{run_id}/file/{file_name} ``` ### Observability and usage Every run is recorded for [observability](/docs/production/observability). Run and event endpoints expose the execution source, failure metadata, and per-model telemetry. Runs are metered in **credits**, and token, credit, timing, and usage reports are available per Task, per agent, and project-wide. Sensitive audit events are recorded in the tamper-evident [audit log](/docs/production/observability). ## Signed webhook example This creates an agent webhook, maps the incoming `message`, and sends one event. Set `RB_API_KEY`, `ORG_ID`, `PROJECT_ID`, and `AGENT_ID` in your environment. The management API uses your API key; the public invoke endpoint uses the separate webhook secret returned at creation. #### Create the webhook Run `node webhook.mjs` with Node.js 22+. The script creates an agent-targeted webhook, then signs and sends one event. The management request uses your API key; the response provides the webhook's own secret and invoke URL. `payload_mapping` takes `message` from the incoming JSON. `idempotency_key_path` identifies retries of the same event. Store the returned `auth_secret` securely for future deliveries; do not log it. **`webhook.mjs (lines 3-25)`** ```javascript webhook.mjs (lines 3-25) const base = "https://app.rightbrain.ai/api/v1"; const projectPath = `/org/${process.env.ORG_ID}/project/${process.env.PROJECT_ID}`; const authorization = `Bearer ${process.env.RB_API_KEY}`; const created = await fetch(`${base}${projectPath}/trigger/webhook`, { method: "POST", headers: { Authorization: authorization, "Content-Type": "application/json" }, body: JSON.stringify({ name: "Signed agent webhook", target_type: "task_agent", target_id: process.env.AGENT_ID, auth_method: "hmac_sha256", auth_config: { signature_header: "X-Signature", signature_format: "plain", encoding: "hex", }, payload_mapping: { message: "$.message" }, idempotency_key_path: "$.event_id", }), }); if (!created.ok) throw new Error(`Create webhook: HTTP ${created.status}`); const trigger = await created.json(); ``` #### Sign the exact request bytes Serialize the payload once, then compute its HMAC-SHA256 using the webhook secret. The configured `plain` format expects lowercase hex with no prefix. Re-serializing the JSON, or adding whitespace or a newline after signing, changes the signature. For retries, preserve the event ID and body. Running this whole script again creates a new trigger and event. **`webhook.mjs (lines 28-34)`** ```javascript webhook.mjs (lines 28-34) const body = JSON.stringify({ event_id: randomUUID(), // Reuse this ID when retrying this event. message: "Create a product listing for headphones.", }); const signature = createHmac("sha256", trigger.auth_secret) .update(body, "utf8") .digest("hex"); ``` #### Send the event Send the signed body to `endpoint_url` with the signature in `X-Signature`. An agent webhook returns `202` with an event ID: this acknowledges receipt, not completed execution. The script prints the trigger and event IDs for inspection. A task-targeted webhook behaves differently: it returns the run result synchronously. **`webhook.mjs (lines 36-43)`** ```javascript webhook.mjs (lines 36-43) const invoked = await fetch(trigger.endpoint_url, { method: "POST", headers: { "Content-Type": "application/json", "X-Signature": signature }, body, // Send exactly the bytes that were signed. }); if (!invoked.ok) throw new Error(`Invoke webhook: HTTP ${invoked.status}`); const accepted = await invoked.json(); console.log({ triggerId: trigger.id, eventId: accepted.event_id, status: accepted.status }); ``` #### Inspect the execution Set `TRIGGER_ID` and `EVENT_ID` to the printed IDs, then poll the event. Inspect `status`, `error_code` and `error_message`. A completed agent event includes `task_agent_run_id` for the [agent run API](/docs/api/run-agents). `request_data.mapped_input` lets you check the mapping. Store request data according to your application's privacy requirements. When testing is finished, disable the temporary trigger with `POST …/trigger/webhook/{trigger_id}` and `{ "status": "disabled" }`. **`inspect-event.sh (lines 1-3)`** ```bash inspect-event.sh (lines 1-3) curl --fail-with-body \ "https://app.rightbrain.ai/api/v1/org/$ORG_ID/project/$PROJECT_ID/trigger/webhook/$TRIGGER_ID/events/$EVENT_ID" \ -H "Authorization: Bearer $RB_API_KEY" ``` #### Complete files **`webhook.mjs`** ```javascript title="webhook.mjs" import { createHmac, randomUUID } from "node:crypto"; const base = "https://app.rightbrain.ai/api/v1"; const projectPath = `/org/${process.env.ORG_ID}/project/${process.env.PROJECT_ID}`; const authorization = `Bearer ${process.env.RB_API_KEY}`; const created = await fetch(`${base}${projectPath}/trigger/webhook`, { method: "POST", headers: { Authorization: authorization, "Content-Type": "application/json" }, body: JSON.stringify({ name: "Signed agent webhook", target_type: "task_agent", target_id: process.env.AGENT_ID, auth_method: "hmac_sha256", auth_config: { signature_header: "X-Signature", signature_format: "plain", encoding: "hex", }, payload_mapping: { message: "$.message" }, idempotency_key_path: "$.event_id", }), }); if (!created.ok) throw new Error(`Create webhook: HTTP ${created.status}`); const trigger = await created.json(); // Store auth_secret in your secret manager for later deliveries; do not log it. const body = JSON.stringify({ event_id: randomUUID(), // Reuse this ID when retrying this event. message: "Create a product listing for headphones.", }); const signature = createHmac("sha256", trigger.auth_secret) .update(body, "utf8") .digest("hex"); const invoked = await fetch(trigger.endpoint_url, { method: "POST", headers: { "Content-Type": "application/json", "X-Signature": signature }, body, // Send exactly the bytes that were signed. }); if (!invoked.ok) throw new Error(`Invoke webhook: HTTP ${invoked.status}`); const accepted = await invoked.json(); console.log({ triggerId: trigger.id, eventId: accepted.event_id, status: accepted.status }); ``` **`inspect-event.sh`** ```bash title="inspect-event.sh" curl --fail-with-body \ "https://app.rightbrain.ai/api/v1/org/$ORG_ID/project/$PROJECT_ID/trigger/webhook/$TRIGGER_ID/events/$EVENT_ID" \ -H "Authorization: Bearer $RB_API_KEY" ``` With `signature_format: "prefix"`, configure the matching `signature_prefix` (for example `sha256=`) and include it in the signature header. This example explicitly selects `plain` so the signing and verification rules match. ## Related #### [Webhooks & forwarders](/docs/api/task-forwarders) Webhook and email forwarding for run results. #### [Observability & audit](/docs/production/observability) Run telemetry, failure reasons, reports, and the audit log. #### [Run agents via API](/docs/api/run-agents) Consume the SSE event stream. #### [Memory & context](/docs/concepts/memory-and-context) Control the session history carried across runs. #### [API Reference — Triggers](/api-reference/api-reference/triggers) Webhook, schedule, and Gmail trigger endpoints. > Build reliable AI agents that run inside your existing tools and workflows. Rightbrain developer documentation.