# Triggers and unattended runs

Declare events a Block runs on by itself: new media, schedules, webhooks, project completion and provider events, turned on by the project owner, with hosted runs inside an approved budget.

A Block can declare events it runs on by itself. Declaring a trigger runs
nothing: when the Block is placed in a project, the project owner reviews each
trigger and turns it on for that Step, with the same reviews as the automation
panels. Results wait for the owner to review before they are used.

```json
{"triggers": [
  {"event": "media.saved", "input": "video", "kinds": ["video"], "label": "When a new video is saved"},
  {"event": "schedule", "everySeconds": 86400},
  {"event": "webhook", "eventKind": "order.created"}
]}
```

| Event | Fields | Runs when |
| --- | --- | --- |
| `media.saved` | `input` (the primary image, video, audio or asset input), optional `kinds` | New media is saved to the project (checked about every minute). Existing media is not processed. |
| `schedule` | `everySeconds` (60 to 31,536,000) | On the interval, starting a minute after the owner turns it on. Missed runs are skipped. |
| `webhook` | optional `eventKind` | Another service sends `POST /api/workflow-trigger-events/<id>` with the key the owner receives once (`Authorization: Bearer <key>`) and a JSON event `{id, kind, occurredAt, data}` up to 64 KB. Repeated event IDs run once. |
| `project.completed` | none | Another project the owner chooses is marked complete. |
| `provider` | `appId`, `eventKind` | A connected app reports the event; the owner connects the account. |

Up to 4 triggers per Block. A webhook, schedule or provider Block receives the
event through an input with `"semantic": "workflow_event"` and
`"sources": ["project"]`.

Triggers work for recipe, JavaScript and hosted (`runtime: "capability"`)
Blocks. Module Blocks run only in the person's browser, so they cannot declare
triggers or run unattended. Sandboxed code has 25 seconds per run.

### Hosted Blocks run inside an approved budget

A hosted Block (generation, analysis, speech, transcription, web reading) runs
unattended only after the owner approves it for that Step:
the model and payment, credits per run, total credits, number of runs and how
many days the approval lasts. The approval reuses the owner's earlier review of
the Block with that model, so run the Step once yourself first. Each automatic
run:

- claims its credits on the approval before anything is sent, so the total is
  never exceeded, and stops and waits for the owner if the price rises above the
  per-run ceiling or the approval is used up, revoked or expired;
- runs as one job with one workflow budget, and is never paid twice: a resumed
  or retried job polls the same hosted request;
- can take longer than the sandbox's 25 seconds. A long call (for example video
  generation) puts the job in a timed wait and StillMade polls it until it
  finishes. Cancelling the job cancels the hosted call.

Timeline and workspace proposals never run unattended; they always wait for a
person.

`autoCaptions` and `orderNote` in `@stillmade/block-sdk` are complete examples:
transcription of each new video into timed captions (`media.saved`), and a
JavaScript Block that turns a shop's webhook into a production note. The SDK
helpers `BLOCK_TRIGGER_EVENTS`, `BLOCK_TRIGGER_LIMITS`, `UNATTENDED_RUNTIMES`,
`triggerProblems`, `blockTriggers`, `describeTrigger` and `triggerReview`
(what the owner reviews for each trigger) check and describe declarations.
