Filtering & Transformation
Event Filtering
Use filter on a handler to only create jobs when the payload matches a condition. Events that don’t match are silently skipped – no job is created.
handlers:
paid-only:
source: stripe
events: [invoice.*]
url: http://backend:3000/paid
filter: "$.data.object.status == paid"
Filter Expressions
| Syntax | Example | Description |
|---|---|---|
$.path == value |
$.status == active |
Equality (strings, numbers, booleans) |
$.path != value |
$.env != test |
Inequality |
$.path >= value |
$.amount >= 1000 |
Greater than or equal (numeric) |
$.path > value |
$.retries > 0 |
Greater than (numeric) |
$.path <= value |
$.priority <= 5 |
Less than or equal (numeric) |
$.path < value |
$.age < 18 |
Less than (numeric) |
$.path in [a, b] |
$.type in [created, updated] |
Set membership |
$.path contains value |
$.name contains admin |
Substring match (strings) or array membership |
$.path starts_with value |
$.email starts_with admin |
String prefix match |
$.path ends_with value |
$.file ends_with .json |
String suffix match |
$.path matches <regex> |
$.id matches ^ord_[0-9]+$ |
Regex match |
$.path exists |
$.metadata.tag exists |
Field existence (non-null) |
not <expr> |
not $.status == draft |
Logical negation of any expression |
$.path |
$.data.verified |
Truthy (exists, not null/false/0/””) |
Examples
# Only process paid invoices
filter: "$.data.object.status == paid"
# Exclude test events
filter: "$.environment != test"
# Multiple event types
filter: "$.action in [opened, synchronize, reopened]"
# Check if a field is truthy (exists and not null/false/0)
filter: "$.data.customer.verified"
# Nested paths
filter: "$.data.object.customer.email == user@example.com"
# Substring match
filter: "$.message contains error"
# Array membership (value exists in an array field)
filter: "$.tags contains urgent"
# String prefix/suffix
filter: "$.email starts_with admin"
filter: "$.filename ends_with .csv"
# Regex match
filter: "$.order_id matches ^ORD-[0-9]{6}$"
# Field existence
filter: "$.metadata.trace_id exists"
# Negation (works with any expression)
filter: "not $.status == draft"
filter: "not $.env in [staging, dev]"
Payload Transformation
Use transform to reshape the payload before delivery. The original payload is preserved in the database; transformation is applied at delivery time.
handlers:
slack-notify:
source: stripe
events: [checkout.session.completed]
url: http://slack-bot:3000/notify
transform: |
{"text": "New order from for cents"}
Placeholder Syntax
- `` – replaced with the value at the given JSONPath
- Missing fields resolve to
null - String values are JSON-escaped (safe from injection)
- Supports strings, numbers, booleans, arrays, and nested objects
Examples
Reshape for a downstream API:
transform: |
{"order_id": "", "customer": "", "total": }
Input: {"id": "ord_123", "customer": "alice", "amount": 4999, "currency": "jpy"}
Output: {"order_id": "ord_123", "customer": "alice", "total": 4999}
Slack notification format:
transform: |
{"text": "Order from : "}
Output: {"text": "Order ord_123 from alice: 4999 jpy"}
Combining Filter and Transform
Filter is evaluated first. If it matches, the transform is applied before delivery.
handlers:
audit-paid:
source: stripe
events: [invoice.*]
url: http://audit:3000/log
filter: "$.status == paid"
transform: |
{"invoice_id": "", "amount": , "paid": true}
Only paid invoices are delivered, and they arrive in a compact audit format.
See Also
- filter-transform example – working example with three handler patterns