Filters & expressions
Overview
A filter is an ExpressionLanguage expression attached to a destination. When a webhook arrives at the parent endpoint, Splithook evaluates the expression. Only webhooks where the result is true are forwarded to that destination.
Filters are optional. An empty filter means "forward everything".
Variables
| Variable | Type | Description |
|---|---|---|
provider |
string | Auto-detected provider: 'stripe', 'github', 'shopify', 'twilio', 'svix', 'unknown' |
event_type |
string | Auto-detected event type, e.g. 'charge.failed', 'push', 'unknown' |
method |
string | HTTP method, always 'POST' in practice |
headers |
map | All request headers, keys lowercased |
body |
map | Parsed JSON body. Nested access via dot notation. |
body is null-safe: accessing a missing key returns null rather than throwing.
Operators
Comparison
body.amount > 1000
body.status == 'active'
body.livemode != false
body.data.object.amount >= 5000
Boolean logic
provider == 'stripe' and body.livemode
event_type == 'charge.failed' or event_type == 'charge.refunded'
not body.test_mode
Membership
body.status in ['failed', 'errored', 'blocked']
event_type not in ['ping', 'test']
Regex
body.type matches '^charge\.'
event_type matches '^(payment_intent|charge)\.'
headers['x-github-event'] matches 'pull_request'
Null checks
body.metadata != null
body.data.object.dispute == null
String operations
body.email ends with '@acme.com'
body.description starts with 'Invoice'
Practical examples
Only Stripe production events:
provider == 'stripe' and body.livemode == true
Only failed charges over €50:
body.type == 'charge.failed' and body.amount > 5000
GitHub push events to main:
event_type == 'push' and body.ref == 'refs/heads/main'
Shopify paid orders:
event_type == 'orders/paid'
Everything except pings:
event_type != 'ping'
Stripe events for a specific customer:
provider == 'stripe' and body.data.object.customer == 'cus_Nf3XsxxxxxxxxxxxxxxS'
Testing a filter
The destination editor runs your filter expression against the last 100 captured webhooks before you save. Matching events are highlighted green, non-matching are dimmed. This turns filter writing from guesswork into a single click.
Error handling
If the filter expression throws at evaluation time (malformed expression, type mismatch), the event is not forwarded to that destination. The error is recorded in the ReplayLog with the message filter_evaluation_failed.
Fix the filter expression in the destination editor and replay the missed events from the Replay Log.
Performance
Filters are evaluated in the async forwarding worker, not on the capture hot path. A slow or complex filter does not affect how quickly your provider gets a 200 OK back from Splithook.