Skip to content

Derived rules

Define custom "entered / exited a segment" events that fire automatically from your existing event stream, without changing your integration.

A derived rule watches a subject (an identified user or an account/tenant) for a condition on its subscribed anchor events, and emits a brand-new event of your own naming when that condition is met — a high_value_order event, say, fired the moment an order’s own amount property crosses a threshold, with no client-side code change required.

The condition is evaluated against the anchor event that just arrived: its name, its timestamp, its own properties, and a few profile facts. A rule cannot sum or count across a subject’s past events, so a threshold has to be one the triggering event carries by itself — see Worked example and Guardrails.

  • The anchor event(s) the rule subscribes to already flowing through Sending events — a rule can only watch events that exist.

Every endpoint on this page is a Management API call — host https://retidal.com, authenticated with the trackly_session cookie from a logged-in console user and your project role. There is no API-key path here; see Authentication for the full session-vs-key model.

GET https://retidal.com/api/projects/{projectId}/derived-rules

Returns every derived rule configured for the project. Console → Projects → Derived Rules shows the same list, with rule type, subject, and enabled/disabled state.

POST https://retidal.com/api/projects/{projectId}/derived-rules
ruleTypebodystringrequired

event_condition (fires when a subscribed event’s condition matches) or absence (fires when a subject has produced none of the subscribed events for longer than absenceThresholdSeconds).

subjectTypebodystringrequired

identified_user or account.

subscribedEventsbodyarrayrequired

The anchor event names this rule watches. A derived event itself cannot be subscribed to — Retidal rejects a rule that would create a cycle.

outputEventNamebodystringrequired

The name of the new event this rule emits. Must not collide with an existing non-derived event name in the project.

POST /api/projects/{projectId}/derived-rules returns 409 if the project’s rule-count cap is reached, and 422 if the body fails validation, creates a subscription cycle, or the output event name conflicts with an existing one.

GET https://retidal.com/api/projects/{projectId}/derived-rules/{id}
PATCH https://retidal.com/api/projects/{projectId}/derived-rules/{id}

GET returns one rule’s full detail. PATCH updates mutable fields only — ruleType, subjectType, and outputEventName are immutable after creation; create a new rule instead of trying to change them.

POST https://retidal.com/api/projects/{projectId}/derived-rules/{id}/enable

Starts or stops a rule. A disabled rule stops evaluating incoming events entirely — it does not queue or backfill events that arrived while disabled.

A derived rule turns a pattern in your existing event stream into a first-class event name you can subscribe Event mappings or an automation to, without instrumenting a new client-side call for it.

  1. Confirm the rule is enabled

    Console → Projects → Derived Rules shows the rule with its enabled/disabled state. Equivalently, from a browser session already logged into the console (so the trackly_session cookie is sent automatically):

    bash
    curl -s https://retidal.com/api/projects/{projectId}/derived-rules/{id} \
    -H "Cookie: trackly_session=$SESSION_COOKIE"
    # expect: 200 with "enabled": true
  2. Send an event that satisfies the rule's condition

    Send one of the rule’s subscribedEvents via Sending events, with a property value that makes the condition true (for the worked example below, a chat.completed event with tokens at least 2000) — the condition is evaluated only against that event’s own properties, not a running total.

  3. Confirm the output event appears

    Check Event catalog (or GET /api/projects/{projectId}/project-events) for the rule’s outputEventName appearing with recent volume.

If the rule never fires — the derived event itself never arrives — work through Events not arriving; the rule not firing is the same “expected event never showed up” symptom that page diagnoses.

A rule that emits user.heavy_session whenever an identified user sends a chat.completed event whose own tokens property is at least 2000 — the rule engine only ever sees the anchor event’s own name, timestamp, and properties (plus a few profile facts), not a cumulative count across past events, so the condition must be evaluated against a fact the triggering event actually carries:

POST /api/projects/{projectId}/derived-rules
{
"name": "Heavy sessions",
"ruleType": "event_condition",
"subjectType": "identified_user",
"subscribedEvents": ["chat.completed"],
"condition": {
"all": [
{ "fact": "event.tokens", "op": "gte", "value": 2000 }
]
},
"outputEventName": "user.heavy_session",
"outputEventCategory": "Engagement",
"enabled": true
}

outputEventName is checked against every existing non-derived event name in the project at creation time, but not re-checked if a matching event name is introduced later — naming a derived event too generically (completed, active) risks a silent future naming collision once that name is claimed elsewhere. Prefer a namespaced output name (user.power_user, not power_user). Separately, subscribedEvents cannot include another derived event — POST /api/projects/{projectId}/derived-rules rejects that at creation with 422, preventing an infinite derivation loop where rule A’s output feeds rule B whose output feeds rule A.