Monitoring rules
A report is a snapshot you pull on demand. Monitoring is the opposite: Walker Street Data watches a customer's enriched data as it arrives and sends you a webhook only when something you care about happens - turnover dropping, an account slipping overdrawn, or new borrowing appearing.
Getting set up
Monitoring takes two one-off steps, then runs on its own:
- Agree your rulesets with us. Walker Street Data works through with you what to watch and at what thresholds, then configures the rulesets on your account. This happens offline, not through the API (contact us to start).
- Register a webhook. Subscribe to the
monitoring.rule.triggeredevent so firings reach your system (see Subscribing). - Keep data flowing. Each time you submit transactions for a customer, the rulesets are checked once enrichment finishes, and any that are true send you a webhook (see When rules run).
Rules and rulesets
A rule is a single true/false condition: one metric compared against a threshold.
days_overdrawn_30d > 5
A ruleset is a named group of rules combined with OR - it is true when any rule is true. A ruleset with one rule is still a ruleset. Rulesets are what you get alerted on: when one becomes true it fires and sends one webhook. Rulesets fire independently.
A set of rulesets for a lender might look like this - each block is a ruleset, the indented lines are its rules:
revenue-drop (ruleset)
revenue_trend_90d < -0.25
OR revenue_vs_prior_year < -0.30
OR declining_months_streak >= 3
overdrawn-account (ruleset)
days_overdrawn_30d > 5
new-borrowing (ruleset)
new_loan_inflows_30d > 0
OR bnpl_repayments_30d > 0
So revenue-drop fires when turnover falls sharply on any of three measures,
overdrawn-account when the account sits overdrawn for more than five days in a month, and
new-borrowing when new loan drawdowns or BNPL repayments appear. The metrics here are
illustrative; your rulesets are configured with Walker Street Data
(contact us to set one up) and are not self-service.
When rules run
Rulesets run automatically after enrichment - there is no separate call:
- Submit transactions for a customer.
- Once the job enriches them, every active ruleset for that customer is evaluated.
- Each metric reads back over its own window (
days_overdrawn_30dthe last 30 days,revenue_trend_90dthe last 90, and so on) across the customer's full history, not just the latest submission. - Any ruleset that is true fires a
monitoring.rule.triggeredwebhook; ones that aren't true send nothing.
Submitting more transactions later re-evaluates every ruleset over the updated history, so keeping data current keeps monitoring current.
What you receive
One firing sends one webhook, so three rulesets firing on the same evaluation means three deliveries. A ruleset that stays true re-fires on each evaluation.
The payload is the common webhook envelope (eventType, eventId, clientId, customerId,
timestamp) plus a ruleset object. It does not carry the job fields (jobId, abn,
jobType).
| Field | Type | Description |
|---|---|---|
ruleset.id | uuid | Identifier of the ruleset |
ruleset.slug | string | Stable machine-readable ruleset slug |
ruleset.name | string | Human-readable name of the ruleset |
{
"eventType": "monitoring.rule.triggered",
"eventId": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
"clientId": "a0ced7e1-da3a-40ea-a18f-4c829f816c6a",
"customerId": "524ba9bc-06e7-417e-bd54-b99785f5194a",
"timestamp": "2026-07-13T02:15:00Z",
"ruleset": {
"id": "184ba9bc-06e7-417e-bd54-b99785f5199a",
"slug": "REVENUE_DROP",
"name": "Revenue drop detected"
}
}
The delivery tells you which ruleset fired, not which rule within it. Route on ruleset.slug
(stable) rather than ruleset.name (display text that may change); pull a
report to see the underlying data.
Subscribing
Notifications use the standard webhook mechanism. Subscribe to the
monitoring.rule.triggered event type:
- cURL
- Node.js
- Python
- C#
curl -X POST "https://api.walkerstdata.com.au/v1/webhooks/subscriptions" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"eventType": "monitoring.rule.triggered",
"webhookUrl": "https://your-app.example.com/webhooks/wsd",
"customerIds": []
}'
const resp = await fetch(
'https://api.walkerstdata.com.au/v1/webhooks/subscriptions',
{
method: 'POST',
headers: {
'x-api-key': process.env.WSD_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
eventType: 'monitoring.rule.triggered',
webhookUrl: 'https://your-app.example.com/webhooks/wsd',
customerIds: [],
}),
}
);
if (!resp.ok) throw new Error(`Request failed: ${resp.status}`);
const { data } = await resp.json();
import os
import requests
resp = requests.post(
"https://api.walkerstdata.com.au/v1/webhooks/subscriptions",
headers={"x-api-key": os.environ["WSD_API_KEY"]},
json={
"eventType": "monitoring.rule.triggered",
"webhookUrl": "https://your-app.example.com/webhooks/wsd",
"customerIds": [],
},
)
resp.raise_for_status()
data = resp.json()["data"]
using System.Net.Http.Json;
using System.Text.Json.Nodes;
using var http = new HttpClient();
http.DefaultRequestHeaders.Add("x-api-key", Environment.GetEnvironmentVariable("WSD_API_KEY"));
var resp = await http.PostAsJsonAsync("https://api.walkerstdata.com.au/v1/webhooks/subscriptions", new
{
eventType = "monitoring.rule.triggered",
webhookUrl = "https://your-app.example.com/webhooks/wsd",
customerIds = Array.Empty<string>(),
});
resp.EnsureSuccessStatusCode();
var data = (await resp.Content.ReadFromJsonAsync<JsonNode>())!["data"];
One subscription receives firings for all rulesets on your account; pass customerIds to
scope it, or leave it empty for a catch-all. See
Webhooks for scoping, signature verification, and
delivery behaviour.
Next steps
- Webhooks - Subscribe, verify signatures, and handle deliveries
- Reports - Pull insight metrics for a customer on demand
- Upload banking data - Feed the data that monitoring runs on