# Triggers

> What starts a workflow, by hand with inputs, on a schedule, or from a webhook call.

Source: https://docs.fous.com/guides/workflows/triggers
Index: https://docs.fous.com/llms.txt

Every workflow has one trigger, and any workflow can also be run manually. Schedules and webhooks fire only while `enabled` is `true`, and they require a paid plan: on Free, enabling one returns `403 plan_limit` with `limit.kind: "api"`.

## Inputs

`trigger.inputs` declares what a run takes, at most 20 inputs. Templates read them as `{{trigger.key}}`:

```json
{
  "type": "manual",
  "inputs": [
    {
      "key": "status",
      "label": "Invoice status",
      "type": "string",
      "required": false,
      "default": "open",
      "description": ""
    }
  ]
}
```

`key` uses lowercase letters, digits and `_`. `type` is `string`, `number` or `boolean`. `label` defaults to the key. A run's input is validated against these and defaults are filled in. Webhook body fields that are not declared are passed through unchanged.

## Schedules

```json
{
  "type": "schedule",
  "inputs": [],
  "schedule": {
    "frequency": "weekdays",
    "at": "09:00",
    "timezone": "Europe/Berlin",
    "input": {}
  }
}
```

| `frequency` | Fires | `every` |
| --- | --- | --- |
| `minutes` | Every `every` minutes, on the clock (every 15: :00, :15, :30, :45) | 1 to 1,440 |
| `hourly` | Every `every` hours | 1 to 168 |
| `daily` | At `at`, every `every` days | 1 to 365 |
| `weekdays` | At `at`, Monday to Friday | Not used |
| `weekly` | At `at` on `weekday` (0 is Sunday), every `every` weeks | 1 to 52 |
| `monthly` | At `at` on `day`, every `every` months | 1 to 12 |

`every` is optional. A monthly schedule's `day` is 1 to 31, or `-1` for the last day of the month (default 1). A month without that day runs on its last day, so `31` runs on 30 April and on 28 or 29 February. `at` is `HH:MM` in `timezone`, an IANA name such as `Europe/Berlin` (default UTC). Weekdays and times follow the local clock in `timezone` across daylight saving changes: a time the clock skips runs an hour later, and a time that occurs twice runs the first time. With `every` above 1, the schedule counts from its first run. `input` is the input each scheduled run receives. While the workflow is enabled, `next_run_at` gives the next scheduled time.

## Webhook triggers

A workflow with `"type": "webhook"` gets a `webhook_url` when it is saved. Another service starts a run by POSTing JSON to it; the body is the run's input.

```bash
curl https://api.fous.com/v1/hooks/whk_3q9ZxK0cLm2vT8yR5nB1wJ7dF4hG6sPa \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-1042" \
  -d '{ "order_id": 1042, "customer": { "name": "Ada" } }'
```

Returns `202` with the run's ID:

```json
{ "run_id": "wfr_01m6vhg04gfg9983c4agtcvyse", "workflow_id": "wf_01m6vnc9ewe3za9g5kqvd8yrkp" }
```

The URL takes no API key, so keep it secret. If it leaks, replace it with `POST /v1/workflows/{id}/webhook`; the old URL stops working immediately.

| Rule | Value |
| --- | --- |
| Workflow disabled | `409 conflict`. |
| Body | A JSON object of at most 256 KB, whatever the `Content-Type`. |
| Rate limits | 60 calls a minute per workflow and 120 per sender network. Above that, `429 rate_limited` with `Retry-After`. |
| Queue | At most 100 runs waiting to start. Above that, `429 rate_limited`. |
| `Idempotency-Key` | Your own ID for the call, up to 255 characters. A repeat within 24 hours returns the original run as `{ "run_id": "…", "workflow_id": "…", "repeated": true }` instead of starting another. Without it, the sender's delivery ID is used the same way: `webhook-id` (Standard Webhooks), `svix-id`, `X-GitHub-Delivery` or `X-Shopify-Webhook-Id`, so retries from those senders start one run. |
