Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Events & delivery

Every event Rustle delivers shares one store-agnostic envelope. The store of origin is a field (store), never something your code has to branch on. A review from Apple and a review from Google arrive in exactly the same shape.

The envelope

These fields are present on every event, regardless of type:

FieldTypeNotes
event_idstringIdentity of this delivery to this subscriber. Deterministic (not random). Dedupe on it. Also sent as the x-radar-event-id header.
occurrence_idstringIdentity of the underlying occurrence, shared across every subscriber it fans out to. Lets you recognise “the same review, delivered to me.”
event_typeenumWhich event this is; see the event catalog below. A field to branch on, never a code branch you maintain per store.
storeenumapple or google. A field, not a code branch.
app_idstringStore-native app id (Apple numeric id, Google package name).
subscriber_idstringThe hook this was delivered to (your hook id).
occurred_atRFC 3339When the change happened at the source.
observed_atRFC 3339When Rustle detected it (poll time).
schema_versionintegerBumped only on a breaking payload change; currently 2.
enrichmentobject | nullOptional extra context on a review (sentiment, themes, a short summary); null otherwise. See review.created.

The type-specific fields (review_id, rating, body, … for reviews; current_rating, delta, … for rating drops; feature_slug, count, geo, … for patterns) sit at the top level alongside the envelope. The payload is flattened, not nested. The one exception is the optional enrichment object above, which is nested (or null). See the event catalog below for every type and its reference page.

Event catalog

Rustle emits two kinds of event_type:

  • Subscribable heads: the event types you attach a hook to. A hook’s event_type is always one of these.
  • Emit-only lifecycle riders: pattern events you never subscribe to directly. When you subscribe to a pattern head (feature.demand_surged / issue.surging) you receive its whole lifecycle; the riders arrive to the same hook, branded on event_type.

Subscribable heads

event_typeWhat it is
review.createdA newly-seen review passing your star filter (carries the free enrichment block).
rating.droppedThe aggregate rating fell by at least your configured delta (sharp step).
rating.trendA gradual, smoothed decline in the aggregate rating (the gentle companion to rating.dropped).
feature.demand_surgedRequests for a feature surged past their baseline: head of the demand-surge lifecycle.
issue.surgingA problem theme surged past its baseline: head of the issue-surge lifecycle.

Emit-only lifecycle riders

Delivered to subscribers of the family head above; not separately subscribable.

FamilyRiders
feature.demand_surgedfeature.demand_recurred, feature.demand_intensified, feature.demand_sustained, feature.demand_subsided
issue.surgingissue.recurred, issue.intensified, issue.sustained, issue.subsided, issue.version_regressed

Enrichment and reviews are free; the pattern family is paid (the Rustle Indie tier).

The gate is enforced at delivery: a pattern event bound for a non-entitled (free) hook is silently skipped: never retried, never dropped noisily. review.created (enrichment included) and rating.dropped are never gated.

Delivery

Rustle POSTs the event as a JSON body to your hook’s target_url, with two headers:

HeaderPurpose
x-radar-event-idThe event’s event_id; dedupe on it.
x-radar-signaturesha256=<hex> HMAC of the exact body; verify it.

A 2xx response means you accepted the event. Any other response (or a timeout) is treated as a failure and retried with backoff; events that exhaust their retries land in a dead-letter queue rather than being dropped.

Forward-looking by default

A new hook only receives events that occur at or after it was created. It does not replay the back-catalogue already sitting in a store’s feed. (The same is true for rating drops: the first observation seeds the baseline silently.)