participant.balance.<symbol>. See CEL Expressions.
Tags
Boolean flags. A tag either exists on an entity or it doesn’t. Useful for one-time gates, status markers, and segmentation labels."VIP" and "vip" are different tags. Pick one casing convention and use it consistently; these docs use lowercase.
Using tags in conditions
Setting tags from rules
TheTAG action adds a tag and UNTAG removes one. Both apply to the event’s participant by default.
This rule grants a one-time welcome bonus and tags the participant to prevent re-triggering:
UNTAG to remove a tag when a condition is no longer met. This rule removes a promotional flag when the promo period ends:
target:
Counters
Numeric accumulators. Stored as high-precision decimals, available as numbers in CEL expressions. Useful for running totals, occurrence counts, and threshold tracking.PUT sets an absolute value and is last-write-wins; increment adds delta atomically, so concurrent writers never lose updates, and negative deltas decrement. See Increment participant counter.
Using counters in conditions
Prefer the dot-access shorthand: a missing counter defaults to0, so no get() is needed:
Updating counters from rules
TheCOUNTER action increments the current value. It does not replace it. This rule tracks purchase count and lifetime spend on every purchase:
purchase_count: 7 and lifetime_spend: 340.00, and a purchase event arrives with event.amount: 49.99, after this rule fires:
purchase_countbecomes8lifetime_spendbecomes389.99
value field accepts static values ("1") or ${{ }} CEL expressions ("${{ event.amount }}").
Auto-resetting counters
Counters can be configured to automatically reset to 0 after a duration elapses. The timer is per-participant, starting from when the counter was last created, explicitly set, or auto-reset. Resets are applied on the next read or write, not at the exact moment the timer expires. Setreset_after via the API:
s, m, and h plus d (days) and w (weeks), combinable as in "1w2d12h"; "30d" and "720h" are equivalent. Note that m means minutes, not months.
Each participant gets their own independent timer. Reading the counter returns the effective value (0 if the window has elapsed), along with reset_after and last_reset_at when auto-reset is configured.
To remove auto-reset from a counter, set reset_after to an empty string. Omitting the field leaves the existing configuration unchanged.
This is for per-participant elapsed-time windows: “reset purchase count 30 days after first purchase” or “daily counter that resets after 24h of inactivity.” For calendar-aligned resets (every Sunday, 1st of month), use a cron automation instead.
Attributes
Key-value strings for arbitrary metadata. Useful for segmentation, preferences, and profile data referenced in rules.Using attributes in conditions
Setting attributes from rules
TheSET_ATTRIBUTE action sets a key-value pair on the event’s participant. Unmarked values are always stored as literal strings: "high" is stored as the text high. For dynamic values, wrap CEL in ${{ ... }}: "value": "${{ event.category }}" stores the evaluated result.
Program and Group State
Programs and groups support the same state types as participants. Access them in CEL viaprogram.* and groups[*].*.
target to the action:
State History
All state changes are logged. Query the history to see what changed, when, and why:state_type, key, operation (set or delete), old_value, new_value, timestamp, and the source of the change. Rule-triggered changes include the event_id. Direct API calls include the API key ID.
State Updates on Inactive Participants
State update behavior depends on participant status:| State Type | ACTIVE | SUSPENDED / CLOSED |
|---|---|---|
| Tags | Allowed | Allowed |
| Attributes | Allowed | Allowed |
| Counters | Allowed | Blocked (409 error) |