Filter and delay webhooks
Connect a source to a destination, choose which webhooks it takes with a filter, and hold them for a while before they are sent.
A connection joins a source to a destination. When a webhook arrives, each enabled connection of its source checks its filter, and each one that matches makes a delivery to its destination.
Connect a source to a destination
curl -X POST "$HOOKS_URL/connections" \
-H "Authorization: Bearer $HOOKS_API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"sourceId\": \"$SOURCE_ID\",
\"destinationId\": \"$DESTINATION_ID\",
\"filter\": { \"body\": { \"status\": \"COMPLETED\" } },
\"delaySeconds\": 60
}"A connection without a filter takes every webhook. Set state to paused to stop it making deliveries; webhooks the source receives meanwhile are not sent through it later.
Write a filter
A filter is a JSON object matched against four parts of the webhook as it was received:
| Part | Holds |
|---|---|
body | The body parsed as JSON, or the text when it is not JSON |
headers | The headers. Write their names in lower case |
query | The query string’s values, by name |
path | The part of the address after the source’s address, such as /payments/mpesa |
A plain value matches an equal value, and an object matches field by field, so the fields you leave out can hold anything. This filter takes completed payments only:
{ "body": { "status": "COMPLETED" } }Operators
For other tests, put an object of operators where a value would go. One object holds either operators or field names, not both.
| Operator | Matches |
|---|---|
$eq, $neq | Equal, or not equal |
$in, $nin | One of a list, or none of it |
$gt, $gte, $lt, $lte | Greater or less than a number, or than text in alphabetical order, which suits dates such as 2026-10-01T08:30:00Z |
$exists | Present, with true, or missing, with false |
$startsWith, $endsWith, $contains | Text that starts, ends, or contains the given text |
$and, $or | Every one, or any one, of a list of conditions |
$not | Anything that does not match the condition |
{
"headers": { "x-provider": { "$in": ["mpesa", "airtel-money"] } },
"body": {
"status": "COMPLETED",
"amount": { "$gte": 10000 },
"msisdn": { "$startsWith": "25574" }
}
}A filter is at most 16 KB and 16 levels deep. It is checked when you save the connection, and a filter we cannot read gets 422 with the reason in issues.
Filtered events
An event that no connection takes is kept with the status filtered, so you can see what arrived and why nothing was sent. List them with status=filtered. See Events.
Delay deliveries
delaySeconds holds each delivery for up to 24 hours before its first attempt. Use it when a sender tells you about something before it is ready to read, or to spread the load of a busy sender.
One webhook, many destinations
Give a source a connection for each destination that needs its webhooks. Each connection has its own filter, delay, and transformation, and each delivery is retried on its own, so one failing destination never holds up the others.
Last updated