Skip to content

Your first route

The quickstart left you with one route, “Everything”, that sends every event to one connection. This page adds a second route that matches only some events, counts repeats instead of sending them again, collects events into one message, and is closed by a resolved event.

You need the instance from the Quickstart: a source key, a connection and the “Everything” route. The example uses a Webhook connection, so the messages shown below are the JSON bodies ramzes posts to it.

Each step can be done in the web UI or with the admin API. For the API, create a token under Settings, API tokens, and set three variables in your shell:

Terminal window
KEY='<source key>' # from the quickstart, starts with rz_src_
TOKEN='<API token>' # starts with rz_tok_
CONN='<connection id>' # see below

List the connections to find the id:

Terminal window
curl -s http://localhost:7269/api/connections -H "Authorization: Bearer $TOKEN"

The route should match failed payments in production above a certain amount:

Condition Value Meaning
Topic payments.* * matches any run of characters
Minimum severity error error and critical
Label env equals prod The event must carry this label with this value
Expression payload.amount > 100 The event must also pass this test

Every condition that is set must hold. And it should make less noise than one message per event:

Noise control Value Effect
Dedup 10 minutes An event with the same key as a notification opened in the last 10 minutes is counted, not sent again
Grouping by label service, wait 30 seconds Events with the same service are collected for 30 seconds and sent as one message
  1. Open Routes and press New route.
  2. Name: Failed payments in production.
  3. Under Which events: set Topic to payments.* and Minimum severity to error. Press Add label condition, type env as the label key, keep equals, and type prod as the value. Type payload.amount > 100 into Expression.
  4. Under Send to: choose your connection.
  5. Under Noise control: tick Count repeats of the same event instead of sending them again and set For this long after the first one to 10 minutes. Tick Collect events and send them as one message, type service into Labels to group by and set Wait before sending to 30 seconds.
  6. Tick Skip the routes below when this one matches.
  7. Press Create route.
The route editor, with the tester on the right showing what each route would do with one event.
The route editor, with the tester on the right showing what each route would do with one event.

A new route is added after the existing ones, so “Everything” is still first. Routes are checked from the top, and every route that matches sends. With the new route below “Everything”, a failed payment would be sent twice: at once by “Everything”, and again by the new route.

Put the new route first. Because it stops evaluation when it matches, “Everything” then only gets the events the new route did not match.

On the Routes page, press the up arrow on the new route’s row.

The Try an event panel on the Routes page shows what the routes would do with one event, without storing or sending it. Choose An event I write here and paste:

{
"topic": "payments.failed",
"title": "Payment 7 failed",
"severity": "error",
"labels": {"env": "prod", "service": "checkout"},
"payload": {"amount": 250},
"dedup_key": "payment-7"
}

The new route shows matched with the target outcome “opens a group”, and two steps under it:

  • dedup: “first event with this key in the window”
  • group: “opens a group; it is sent after 30 s”

“Everything” shows as skipped, because an earlier route stopped the evaluation. Change amount to 40 and the new route no longer matches; “Everything” matches instead and would send.

The same test over the API is POST /api/routes/test with the event under "event".

Terminal window
curl -X POST http://localhost:7269/v1/events \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{"topic": "payments.failed", "title": "Payment 7 failed", "severity": "error",
"labels": {"env": "prod", "service": "checkout"},
"payload": {"amount": 250}, "dedup_key": "payment-7"}'

Run it twice within 30 seconds. Both requests answer 202, and nothing arrives at the connection yet:

  • The first event opens a notification that is collecting. On the Notifications page it is under Waiting.
  • The second event has the same dedup_key, so it is counted on that notification as a duplicate.

Thirty seconds after the first event, one message goes out. The Webhook connection receives:

{
"title": "Payment 7 failed (2 times)",
"body": null,
"severity": "error",
"status": "firing",
"topic": "payments.failed",
"labels": {"env": "prod", "service": "checkout"},
"link": null,
"ack_link": null,
"dedup_key": "payment-7",
"event_ids": ["01a136a8-abe9-7601-8ffe-11857f1b6b34", "01a136a8-abfa-76bd-829f-73890d3884a0"],
"sent_at": 1791918416790
}

link and ack_link are null because the instance has no public address yet. Set one under Settings and messages link back to ramzes and carry a link that acknowledges the notification. See Escalation and acknowledgement.

Open either event from the Feed to see its journey: which route it matched, whether it opened the notification or was counted as a duplicate, and the delivery with the status the service answered.

Acknowledging says someone is on it. It stops reminders and escalation for that notification.

Open Notifications, choose Sent, and press Acknowledge on the row.

The notification moves to Acknowledged and records who did it: your email address from the UI, or “API token” from the API.

Send an event with the same dedup_key and "status": "resolved":

Terminal window
curl -X POST http://localhost:7269/v1/events \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{"topic": "payments.failed", "title": "Payment 7 went through", "severity": "error",
"status": "resolved", "labels": {"env": "prod", "service": "checkout"},
"payload": {"amount": 250}, "dedup_key": "payment-7"}'

The route matches, finds the open notification with that key, and closes it. Because a message had been sent for it, the connection is told. The Webhook connection receives the same message again with "status": "resolved":

{
"title": "Payment 7 failed (2 times)",
"severity": "error",
"status": "resolved",
"topic": "payments.failed",
"dedup_key": "payment-7"
}

(The other fields are as before.) The notification is now under Resolved. Later events with the key payment-7 open a new notification.

Three details worth knowing:

  • A resolved event closes a notification only when the keys match. Give the firing and the resolved event the same dedup_key.
  • A resolved event that is less severe than the route’s minimum still closes what the route opened. It does nothing else on that route and does not stop evaluation, so routes below it see the event too. In this example a resolved event sent with severity info would close the notification and also be sent by “Everything”.
  • To close without telling the target, untick Tell the target when it is resolved on the route ("notify_resolved": false in shaping).