Triggers
Triggers automatically create workflow instances in response to external events. Four trigger types are supported: HTTP webhooks, NATS message queues, file-system watch events, and in-process event bus. All triggers are persisted to the database and managed via REST API.
HTTP webhook trigger
Register a webhook trigger with a secret, then send public delivery to POST /webhooks/{slug}. The raw JSON body becomes context.data. Public delivery is always signed; the authenticated /triggers/{slug}/fireroute is for trusted API clients and internal event invocation.
POST /triggers
{
"slug": "stripe_payment_failed",
"sequence_name": "payment_dunning",
"version": 1,
"tenant_id": "acme",
"enabled": true,
"secret": "whsec_your_signing_secret"
}
// Disable without deleting
PATCH /triggers/stripe_payment_failed
{ "enabled": false }POST /webhooks/stripe_payment_failed
x-trigger-timestamp: 1787443200
x-trigger-nonce: 7f6a2d85b1e94c31
x-orch8-signature: v1=<base64url-hmac>
signed_message = timestamp + "." + nonce + "." + raw_request_body
signature = "v1=" + base64url(HMAC-SHA256(secret, signed_message))Timestamps may be at most 300 seconds old or 60 seconds in the future. Nonces are single-use, 16–128 printable ASCII characters, and the body limit is 1 MiB. Sign the exact bytes sent—do not parse and re-serialize JSON after signing.
Transactional event-batch intake (current main)
PostgreSQL outbox producers can deliver up to 100 events per request toPOST /api/v1/events/batch. This endpoint is on current main after v0.7.1, not in the stable 0.7.1 release.
{
"events": [{
"tenant_id": "acme",
"event_name": "order.completed",
"producer_event_id": "outbox-018f5d2f",
"correlation_key": "ORD-123",
"payload": { "order_id": "ORD-123" }
}]
}Retries with the same tenant, event name, andproducer_event_id are deduplicated. Keep the producer outbox row until the batch response confirms acceptance.
NATS message queue trigger
Subscribe to a NATS subject. When a message arrives, the engine creates a workflow instance. The message payload becomes context.data. Configure in orch8.toml.
# orch8.toml — NATS trigger configuration
[[triggers.nats]]
subject = "events.payment.failed"
sequence_name = "payment_dunning"
tenant_id = "acme"
url = "nats://nats-server:4222"
# Multiple NATS triggers from different subjects
[[triggers.nats]]
subject = "events.user.signup"
sequence_name = "welcome_onboarding"
tenant_id = "acme"
url = "nats://nats-server:4222"The trigger processor loop syncs trigger definitions from the database at startup and dynamically starts/stops listeners when triggers are created or disabled via API.
File watch trigger
Watch a directory (or file path) for create and modify events. When the OS notifies of a change, the engine creates a workflow instance with the file path and event type in context.data. Uses the notify crate for cross-platform fs-event support.
# orch8.toml — file watch trigger
[[triggers.file_watch]]
path = "/data/incoming"
recursive = true
sequence_name = "process_incoming_file"
tenant_id = "acme"
# context.data for each trigger:
# { "path": "/data/incoming/report.csv", "event": "create" }
# Combine with a processing sequence
{
"type": "step", "id": "process_file",
"handler": "csv_importer",
"params": { "path": "{{context.data.path}}", "event": "{{context.data.event}}" }
}Event trigger (in-process event bus)
Event triggers use an in-process event bus for trusted server-to-server or in-cluster integration. Unlike webhooks, event triggers carry no HMAC validation. They can be fired via POST /triggers/{slug}/fire or internally by workflows using the emit_event built-in handler.
POST /triggers
{
"slug": "order_completed",
"sequence_name": "post_order_processing",
"tenant_id": "acme",
"trigger_type": "event",
"enabled": true
}
// Fire directly via API
POST /triggers/order_completed/fire
{ "order_id": "ORD-123", "total": 99.99 }// Or fire from another workflow step
{ "type": "step", "id": "emit_order_event",
"handler": "emit_event",
"params": { "slug": "order_completed", "payload": { "order_id": "{{context.data.order_id}}" } } }Trigger management API
# List all triggers
GET /triggers
# Get a trigger by slug
GET /triggers/{slug}
# Update trigger
PATCH /triggers/{slug}
{ "enabled": false }
# Delete a trigger
DELETE /triggers/{slug}