# Webhooks

> Start a Nodaro workflow from any system with a Webhook Trigger URL, create schedules through the API, and send results to your server with Webhook Output.

Source: https://nodaro.ai/docs/developers/api/webhooks

**Webhooks** connect Nodaro to your other systems in both directions. A [Webhook Trigger](https://nodaro.ai/docs/nodes/automate/webhook-trigger) node gives a workflow a URL that any system can call to start a run, a [Schedule Trigger](https://nodaro.ai/docs/nodes/automate/schedule-trigger) runs it on a timetable, and a [Webhook Output](https://nodaro.ai/docs/nodes/publish/webhook-output) node sends a run's results to your server. Nodaro does not call you back on its own: to learn that a run ended, poll it, or end the workflow with a Webhook Output node.

Workflow: An outside system calls the Webhook Trigger URL, Generate Image runs, and Webhook Output posts the image URL to your server.

- Webhook Trigger → Generate Image (prompt)
- Generate Image → Webhook Output

## Endpoints

| Method | Path | What it does |
| --- | --- | --- |
| `POST` | `/v1/webhooks/:token` | Start a run. Public: the token in the path is the credential. |
| `GET` | `/v1/workflows/:id/triggers` | A workflow's triggers, with each webhook's URL and token. |
| `PATCH` | `/v1/workflow-triggers/:id` | Pause or resume a trigger with `isActive`, or change a schedule's `config`. |
| `POST` | `/v1/workflow-triggers` | Create a trigger by hand, not tied to any node. |
| `POST` | `/v1/workflows/:id/sync-triggers` | Register a workflow's trigger nodes again from its saved version. |

## Start a workflow from an HTTP call

### Add a Webhook Trigger

Add a [Webhook Trigger](https://nodaro.ai/docs/nodes/automate/webhook-trigger) node to the workflow. Under **Output Parameters**, add one parameter for each value the caller will send. Each parameter has a **Name**, which matches a key in the request's JSON body, and a **Type**: `text`, `imageUrl`, `videoUrl` or `audioUrl`. Wire the parameters into the nodes that should use them.

### Save the workflow

Saving creates the endpoint: Nodaro mints a 32-byte token and registers `POST /v1/webhooks/<token>`. This happens whichever way the workflow is saved: from the editor, the API, the SDK, an import or MCP. The token is minted once and then kept, so the URL you give an outside system stays valid through every later save. Removing the node retires the URL.

### Read the URL

`GET /v1/workflows/<id>/triggers` returns the workflow's triggers, including each webhook's URL and token.

### Call it

Send a `POST` with a JSON body. No `Authorization` header is needed: the token in the URL is the credential.

```bash
curl -s -X POST "https://app.nodaro.ai/v1/webhooks/$WEBHOOK_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"prompt": "a lighthouse in a storm", "imageUrl": "https://example.com/lighthouse.jpg"}'
```

The body becomes the trigger's payload. Each parameter reads the key of the same name, and its type routes the value: an `imageUrl` feeds image inputs, a `videoUrl` feeds video inputs.

Each webhook trigger accepts 10 requests per minute. The limit is separate from your API tokens' limits.

Typical callers are a payment system that starts an onboarding video when a customer signs up, a code repository that asks for a release-notes summary, a content system that publishes a new article, or a no-code automation tool.

### What a triggered run executes

- **A trigger wired to something runs only its branch:** the nodes downstream of the trigger, plus every node those nodes need as input.
- **A trigger wired to nothing runs the whole workflow.**
- **So one workflow can carry several triggers**, each starting its own branch.
- **"Wired" means anything that feeds another node:** a drawn connection, a node inside a Group, or a field mapping.
- **Runs from the editor, the API and published apps are not limited by triggers.** They run what they always run.

A trigger created by hand through the API names no node. Nodaro then uses the only Webhook Trigger on the canvas; with two of them, the whole workflow runs.

### Keep the URL secret

The token is the only credential, so anyone who holds the URL can start runs and spend your credits. For a workflow in an organization's workspace, the runs are paid by the workspace's budget: anyone you share the URL with can spend the class's or the team's credits.

Every automated run, whether from a webhook, a schedule or Telegram, first checks that the trigger's creator may still run the workflow. When they no longer can, because a grant was revoked, a membership was suspended or the workspace was archived, the automation stops. The workflow's run history then shows one failed entry with the code `run_requires_authenticated_member`.

## Manage triggers through the API

Trigger nodes register themselves when the workflow is saved. Four routes manage them directly:

- **`GET /v1/workflows/<id>/triggers`** lists a workflow's triggers.
- **`PATCH /v1/workflow-triggers/<id>`** with `{ "isActive": false }` pauses a trigger, and `true` resumes it. For a trigger that belongs to a node, the next save applies the node's own switch again, so use the node's switch for anything that should stick. A `config` you send is merged into the stored one: send only what changes. The trigger's link to its node and its run count are kept.
- **`POST /v1/workflows/<id>/sync-triggers`** registers the workflow's trigger nodes again from its saved version. The editor calls it after every save, and anyone with edit access may call it. It answers `{ "data": { "synced": …, "created": …, "updated": …, "removed": … } }`.
- **`POST /v1/workflow-triggers`** creates a trigger that belongs to no node, so saving the workflow never changes or removes it. Creating one needs the same permission as running the workflow, because a trigger is a run that nobody attends.

## Schedules

A [Schedule Trigger](https://nodaro.ai/docs/nodes/automate/schedule-trigger) runs a workflow on a timetable. A schedule is a list of **rules**, and the workflow runs whenever any rule matches the current minute.

### Turn a schedule on

A Schedule Trigger node fires only while its data says `"active": true`, the node's switch. A node written through the API, the SDK or MCP without `active` is registered **paused**. The editor's switch and its **Schedule** button set the same field. A template export never carries it, so an imported schedule always starts paused.

### Create a schedule by hand

```json
{
"workflowId": "8c2d7f1e-3a4b-4c5d-9e6f-7a8b9c0d1e2f",
"type": "schedule",
"config": {
"rules": [
{ "kind": "days", "every": 1, "hour": 9, "minute": 0 },
{ "kind": "weeks", "every": 2, "weekdays": [1, 3], "hour": 18, "minute": 30 }
],
"timezone": "Asia/Jerusalem"
}
}
```

Send it with `POST /v1/workflow-triggers`. The same `config` shape is what a Schedule Trigger node stores.

| `config` field | Meaning |
| --- | --- |
| `rules` | One or more rules. The workflow runs when any rule matches. |
| `timezone` | The clock the rules are read in, as a zone name such as `Asia/Jerusalem`. UTC when omitted. |
| `maxExecutions` | Stop after this many runs. The schedule stays registered: raise or clear the number to continue. |

| `kind` | Fields | Runs |
| --- | --- | --- |
| `minutes` | `every` from 1 to 59 | At minute 0, N, 2N and so on, every hour |
| `hours` | `every` from 1 to 23, `minute` | At hour 0, N, 2N and so on, every day, at that minute |
| `days` | `every` from 1 to 31, `hour`, `minute` | Every Nth calendar day at that time |
| `weeks` | `every` from 1 to 52, `weekdays` (0 is Sunday, 6 is Saturday), `hour`, `minute` | On those weekdays, every Nth week |
| `months` | `every` from 1 to 12, `dayOfMonth` from 1 to 31, `hour`, `minute` | On that day, or the month's last day when the month is shorter, every Nth month |
| `cron` | `cron`, a 5-field expression | Whenever the expression matches |

- **Every Nth day, week or month counts from a fixed start**, and weeks start on Monday, so saving again never shifts the days a schedule runs.
- **In a `cron` rule every field must match**, both the day of the month and the day of the week, where some cron tools accept either one. `7` means Sunday, like `0`.
- **Values out of range answer `400`**, and so does a time zone the server cannot read.
- **Older forms still work** for triggers you create by hand: an `interval` such as `5m`, `1h` or `1d`, or a `cron` string. A Schedule Trigger node saved with them is converted to rules.

### How schedules fire

- The server checks the schedules once a minute and runs a workflow when one of its rules matches that minute.
- A minute never fires twice, even across a restart or a clock change. A minute the clock jumps over is skipped that day.
- If the previous run of the workflow is still going, that minute is skipped.
- A node that cannot run is **parked**, for example a `cron` rule with no expression or an unreadable time zone. Nothing is guessed: fix the node and save again.

## Send results to your server

A [Webhook Output](https://nodaro.ai/docs/nodes/publish/webhook-output) node sends the result that reaches it, with the parameters you configure, to your URL as a `POST` request. Its parameters have the same types as the trigger's: `text`, `imageUrl`, `videoUrl` and `audioUrl`. Media values are URLs of files stored by Nodaro, which your server can download.

If your endpoint answers with an error, the node fails, and the error appears in the run's history. Use an `https` URL.

### Send a key with the request

Many endpoints accept a request only with a key in a header. Save the header name and the key once as a **credential** in the web app, under **Integrations › Credentials**, and choose it in the node. The key never enters the workflow, an export or a template.

When you save a key, you choose who can use it:

| Choice | Works on |
| --- | --- |
| **Any address** (a plain credential) | Runs you start yourself: a run from the editor, and a schedule you set up in the editor. |
| **Only one address** (a locked credential) | Every run, but only to that address, or to paths under it when you allow that. |

Runs started with an API token or an OAuth token, by a webhook trigger, by a schedule created through the API, or from a published app are not your own, even though they run as you. **For those runs, lock the credential**: a plain one makes the node fail with a clear message instead of sending. A locked credential is sent only when the node's URL matches the address, a redirect to another address is not followed, and the key is never sent over plain `http`.

With a credential attached, the node does not keep or show your endpoint's response body, only its status code. Credentials are managed only in the web app: the credential routes answer `403 in_app_only` to tokens. Publishing an app or sharing a workflow for others to run answers `409 credential_unbound` until every credential it sends with, including inside sub-workflows, is locked to an address the node sends to.

## No callbacks on API runs

A run you start through the API does not call a URL when it finishes. You have two ways to learn the outcome:

- **Poll it.** Follow the run with `GET /v1/workflow-executions/:id`, or a single node's job with `GET /v1/jobs/:id/status`. See [Executions](https://nodaro.ai/docs/developers/api/executions) and [Jobs](https://nodaro.ai/docs/developers/api/jobs).
- **Let the workflow tell you.** End the workflow with a Webhook Output node that posts the results to your server.

## Frequently asked questions

### How do I start a Nodaro workflow with a webhook?

Add a Webhook Trigger node, define its parameters, and save the workflow. Saving creates a URL of the form POST /v1/webhooks/ followed by a token. Send a JSON body whose keys match the parameter names, with no other authentication.

### Does Nodaro call my server when a run finishes?

Not by itself. Poll the run or its jobs, or end the workflow with a Webhook Output node, which sends the results to your URL when the run reaches it.

### Is a webhook URL safe to share?

Treat it like a password. The token in the URL is the only credential, so anyone who has it can start runs and spend your credits, or the workspace's budget. Each trigger accepts 10 requests per minute.

### How do I schedule a workflow through the API?

Save a Schedule Trigger node with "active" set to true in its data, or create a schedule with POST /v1/workflow-triggers and a config of rules and a timezone. Nodaro checks every schedule once a minute.

### Why does a Schedule Trigger created through the API not run?

A Schedule Trigger runs only while its data says "active" is true. A node written through the API, the SDK or MCP without that field is registered paused. Set the field and save again.
