Create Saved View
create_viewCreates a View: a saved predicate that records a Match when an event enters it and sends it by email or to a destination, with an optional Digest. Try the predicate with screen_events first; use update_view to change a View that exists.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | ||
| tags | No | Free-text organization labels for this View (max 5, deduplicated). Purely for grouping/filtering in the app; tags never change what the View matches or where alerts deliver. | |
| color | No | Accent color the app shows on this View's pill/dot. One of: red, orange, amber, green, teal, blue, violet, pink. Cosmetic only. | |
| digest | No | The View's Digest: each Issue is the View's events with Movers, New and Gone against the previous Issue. Only the fields you pass change. Turning it on past the plan's Digest count is refused with the plan that carries more. | |
| enabled | No | ||
| channels | Yes | Delivery channels, at least one. "email" mails the Matches to the account's address. The other value routes them to the destinations attached to this View instead, which is how a Slack or Discord channel receives them: add one in the Ticker web app under Settings, then attach it with set_view_target. A View may carry both. | |
| predicate | No | {} = always-true, combined with max_firings_per_eval to get a "top-N of the universe" alert. Predicate DSL (recursive JSON): a leaf is {col, op, val}; composites are {all:[...]} (AND) or {any:[...]} (OR). Columns are prefixed: "ea." = event_analytics, "e." = events, "pa." = performer_analytics, "p." = performers (p.name, the act the row is about), "v." = venues (v.venue_name, the venue's name; v.city, v.state, v.country_code, v.capacity). Ops: =, !=, >, >=, <, <=, between (val=[lo,hi]), in (val=[...]), contains (case-insensitive substring on a TEXT column; val is a plain string), not_contains (removes the rows whose TEXT column holds val as a case-insensitive substring; a row with no value stays; % and _ in val match themselves, while contains reads them as wildcards). Example: {"all":[{"col":"ea.price_self_z_7d_xs_z_subcat_tte","op":">=","val":2},{"col":"ea.days_to_event","op":"between","val":[7,60]}]}. NAMED ACTS / TEAMS / PERFORMERS, use p.name. When the user names the act the events are BY (a musician like 'Taylor Swift', a team like 'Lakers', a comedian, a touring show), filter the performer column: {col:'p.name', op:'contains', val:'Taylor Swift'}. p.name is the act the row is KEYED on. e.event_name is the TITLE, which reads 'A at B' for a sports event and so also returns the opponent's home games, and for a concert also returns parking and support billings. A performer or team ask NEVER goes to e.event_name. Keep writing 'contains' for an act name. When what was typed IS a whole act name in the catalog, the server rewrites that leaf to op '=' and says so; anything else stays a substring. REMOVING ROWS BY A WORD. 'NOT Little', 'not the Lakers', 'without Taylor', 'excluding Hamilton' remove every row whose title contains the word: {col:'e.event_name', op:'not_contains', val:'Little'}. Never write '!=' for a word: '!=' compares the WHOLE value, so e.event_name != 'Manilow' removes nothing. A MISSPELLED superlative is still a superlative. 'htotest', 'hotest', 'bigest movers', 'chepest', 'lowset price' read as the word they intend and take the ordering that word takes. A ranking word is NEVER a name: never put it in a 'contains' leaf on e.event_name or p.name, and never answer with sort null because the spelling was odd. ECONOMIC FLOOR. The server already ANDs ea.listings_current >= 25 AND ea.median_price_current >= 40 into every screen. Do NOT add a listings-depth floor of your own. A column whose name ends in d1 or 1d is a ONE-DAY CHANGE, not yesterday's value. 'Inventory dropping' or 'listings falling' is a SEVEN-DAY change or an absorption column, never a one-day ratio. A stale row, or an event that is not active, is NEVER a move: its numbers describe the last day it was priced. Gate a movement ask on ea.last_price_snapshot_date with a relative date. The economic floor CAN be turned off at the call site (apply_floor=false, or apply_economic_floor=false on a rule), only when you explicitly want the raw universe. A freshness gate is NOT applied by default, so supply it yourself: {"col":"ea.last_price_snapshot_date","op":">=","val":{"days_ago":1}} means "priced within the last day" and compiles to CURRENT_DATE - 1, re-evaluated every tick, where a literal date string silently rots. The {"days_ago": N} value form is valid on any date/timestamp column. A weekend is {"col":"e.local_date","op":"between","val":{"weekend":"this","tz":"America/New_York"}} ("next" for the one after): the coming Friday to Sunday in tz, from today on a Friday to Sunday, resolved on every run. e.event_id, e.venue_id and e.performer_id take the ids rows carry (ev..., vn..., pf...). Authoritative validation runs in SQL; an invalid predicate returns a clear error. | |
| notification_mode | No | Per-alert EMAIL delivery mode: 'instant' (email each match), 'batched' (the Matches wait and go out together in one email, at the pace notification_cadence sets: `hourly` or `daily`), or 'muted' (Matches recorded, never emailed). 'instant' and 'muted' override notification_cadence. 'digest' is the old name of 'batched', accepted until 2026-11-30 and stored as 'batched'. Alert destinations are unaffected: they always deliver instantly. | |
| delivery_target_id | No | Optionally attach an alert destination (an id from list_destinations; new destinations are added in the Ticker web app under Settings) so this alert's Matches are delivered there the instant they fire, in addition to email. Omit for email-only. | |
| apply_economic_floor | No | Whether the rule's predicate is AND-ed with the economic floor (listings_current >= 25 AND median_price_current >= 40). Default true. | |
| max_firings_per_eval | No | Cap on events this rule can match per evaluation tick (top-N by event_id (deterministic cap, not magnitude-prioritized)). Bounds alert volume since percentile predicates can't self-limit. Default 25. | |
| notification_cadence | No | How often this alert's Matches may leave as EMAIL: `immediate` (each match), `hourly`, `daily` (batched), or `off` (Matches recorded but never emailed). Only paces EMAIL; an attached alert destination always delivers the instant a Match fires, regardless of this. |