7.11 Webhooks, schedules, and polling connectors
A pipeline runs on any verb, so an event can start one simply by arriving as a request. RS2 has three common trigger shapes: an inbound webhook, a scheduled mount, or a small connector service that calls a pipeline.
Webhooks are ordinary POSTs
Point a provider at a pipeline path and open only invoke for that unauthenticated
caller:
{ "path": "/hooks", "service": "pipeline", "config": {
"access": { "read": "A", "write": "A", "invoke": "all" }
} }
POST /hooks/stripe runs the stripe spec (or .root). Return a 2xx after the
event is safely handled; most providers retry a non-2xx, giving the delivery an
at-least-once shape.
Opening invoke does not mean trusting the body. Keep the signing key in the
tenant's write-only secrets block, grant that name to the mount, and verify the
signature in the first transform with $hmacVerify over $_rawBody. A failed
verification can call $error, stopping before the event produces effects.
Scheduled mounts
Any mount can carry one schedule in its common config:
{ "path": "/poll", "service": "pipeline", "config": {
"access": { "read": "A", "write": "A", "invoke": "A" },
"schedule": { "every": "60s" }
} }
Or use a five-field UTC cron expression:
"schedule": { "cron": "0 9 * * *" }
Exactly one of every or cron is allowed. Intervals accept ms, s, m,
and h. A bad schedule is rejected when the tenant is built.
On each tick the host sends a trusted internal POST to the mount root with
x-rs2-trigger: schedule and no body. It still counts against tenant admission,
limits, and the circuit breaker, and it appears in logs as an internal call. On
a pipeline mount, .root handles the tick.
The scheduler does not replay missed ticks after a restart. A polling connector
should keep its own cursor with durable state and ask the upstream for changes
since that cursor. The standard scheduler is in-process and single-node; two
independent nodes would both fire. Cluster-wide fire-once requires an operator
to provide a shared ScheduleStore.
This is synchronous triggering: the sender or scheduler waits for the flow. A durable queue that absorbs bursts and retries independently is a separate, future capability, not something the schedule quietly emulates.
When declarative composition is no longer enough, Part 8 covers dropping in your own sandboxed code.
← Previous: 7.10 Wrappers and response shaping · Manual home · Next: Part 8 — 8.1 When to reach for custom code →