mcp-server
Was dieses MCP kann
Provides SQL-based market scans, historical price and indicator data, news and event timelines, portfolio-related signals, and webhook alerts across stocks and cryptocurrencies.
Tools
Eingabeschema
{'type': 'object', 'required': ['name', 'expr'], 'properties': {'expr': {'type': 'string', 'description': 'Boolean SQL predicate. May reference built-in signals and other custom signals you own. Must evaluate to true/false. Max 4000 chars. Stricter grammar than scan `q`: comparisons, `AND`/`OR`/`NOT`, `IN`, `BETWEEN`, `IS [NOT] NULL`, arithmetic, and the functions `abs`/`coalesce`/`round`/`least`/`greatest` only — no `LIKE`/`ILIKE`, no `CASE`, no `::` casts, no other functions. An expression that scans fine can still be rejected here with `compile_failed`. What you send is what you read back: responses echo your expression as stored, not its expansion. A signal referencing another custom of yours returns the reference as you typed it — the inlined SQL exists only internally, and is what a subscribe endpoint freezes into a webhook. The one rewrite: a column named under its pre-2026-09-07 spelling (`bollinger_pct_b`) is stored under its current name (`bollinger_b`) and reported in `_meta.deprecated_columns`.'}, 'name': {'type': 'string', 'description': "Slug — `^[a-z][a-z0-9_]{0,63}$`. Must not collide with any built-in signal name, and 15 names are reserved outright: `columns`, plus the `/v2/series` OHLCV aliases `open`/`high`/`low`/`close`/`volume`/`vwap`/`trades` and `o`/`h`/`l`/`c`/`v`/`vw`/`n` (those resolve to bars before custom lookup). This is the signal's API handle: it's what you reference in `q` and in the CRUD path."}, 'description': {'type': 'string', 'description': 'Free-form notes. Max 500 chars. Absent or empty comes back as `""` rather than null.'}}}
Ausgabeschema
{'type': 'object', 'required': ['as_of', 'signal'], 'properties': {'_meta': {'type': 'object', 'description': 'Only when `expr` named a column under its pre-2026-09-07 spelling: `deprecated_columns` lists each one (`requested`, `use`, `note`). The stored `expr` carries the current name.'}, 'as_of': {'type': 'string', 'description': 'Server time this response was assembled (ISO 8601).'}, 'signal': {'type': 'object', 'description': 'The stored signal: `name`, `kind` (`custom`), `description`, `expr` (your predicate as stored), `created_at`, `updated_at`.'}}, 'additionalProperties': False}
Eingabeschema
{'type': 'object', 'required': ['name', 'tickers'], 'properties': {'id': {'type': 'string', 'description': "Optional slug — becomes the universe's permanent handle everywhere (`?universe=`, subscribe `universe`, CRUD path). Pattern `^[a-z][a-z0-9_]{0,62}$` — starts with a lowercase letter, then lowercase letters/digits/underscore, 63 chars max; the value is trimmed and lowercased before validation. `top_10` and `top_100` are reserved for system universes and rejected with 400. Must be unique within your account. Generated (`u_…`) if omitted."}, 'name': {'type': 'string', 'description': 'Human-readable label, up to 80 characters. Display-only — never used to reference the universe.'}, 'tickers': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Ticker symbols, up to 10,000. Validated against the active universe. `[]` is accepted — a shell universe you can fill later via PATCH.'}, 'description': {'type': 'string', 'description': 'Free-form notes, up to 500 characters. Stored as `""` when omitted.'}}}
Ausgabeschema
{'type': 'object', 'required': ['as_of', 'id', 'name', 'description', 'tickers', 'size', 'system', 'created_at', 'updated_at'], 'properties': {'id': {'type': 'string', 'description': "The slug — the universe's handle in `?universe=`."}, 'name': {'type': 'string', 'description': 'Display label.'}, 'size': {'type': 'number', 'description': 'Member count.'}, 'as_of': {'type': 'string', 'description': 'Server time this response was assembled (ISO 8601).'}, 'system': {'type': 'boolean', 'description': '`false` — this is your universe.'}, 'tickers': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Members, after this call.'}, 'created_at': {'type': 'number', 'description': 'Creation timestamp.'}, 'updated_at': {'type': 'number', 'description': 'Last modification timestamp.'}, 'description': {'type': 'string', 'description': 'Free-form notes; `""` when unset.'}, 'effective_at': {'type': 'number', 'description': 'System universes only; absent on yours.'}, 'rebalance_method': {'type': 'string', 'description': 'System universes only; absent on yours.'}, 'next_rebalance_at': {'type': 'number', 'description': 'System universes only; absent on yours.'}}, 'additionalProperties': False}
Eingabeschema
{'type': 'object', 'required': ['trigger'], 'properties': {'dir': {'enum': ['asc', 'desc'], 'type': 'string', 'default': 'desc', 'description': 'Sort direction for `order`. Not accepted on `event` triggers (400).'}, 'name': {'type': 'string', 'description': 'Display name, max 80 characters. Defaults to an auto-generated one from the trigger.'}, 'order': {'type': 'string', 'default': 'market_cap', 'description': "Signal the fired payload's match lists are sorted by before the 100-row cap is applied — so a truncated list is the deterministic top 100, not an arbitrary sample. Same contract as `POST /v2/scan`. Not accepted on `event` triggers (they deliver one event at a time)."}, 'cadence': {'enum': ['realtime', 'hourly', 'nyse_open'], 'type': 'string', 'default': 'realtime', 'description': 'Evaluation cadence — a user preference — never gated. Event triggers deliver on ingest — only `realtime` is accepted on them (400 otherwise).'}, 'channel': {'enum': ['webhook', 'discord', 'in_app', 'mobile_push'], 'type': 'string', 'description': 'Delivery channel. See Delivery channels.'}, 'columns': {'type': 'string', 'description': "Extra columns echoed in fired payloads' match rows (`fields` accepted as an alias). Not accepted on `event` triggers (400) — event deliveries carry the event payload, not state rows."}, 'trigger': {'type': 'object', 'required': ['type'], 'properties': {'q': {'type': 'string', 'description': "scan: required — the SQL WHERE any ticker must match to fire. ticker: required — WHERE fragment evaluated for that ticker (auto-scoped; don't add `ticker = …` yourself; `trigger.condition` accepted as an alias). event: optional row-STATE filter on the event's ticker at fire time (`market_cap > 1e10`)."}, 'type': {'enum': ['scan', 'ticker', 'signal', 'event'], 'type': 'string', 'description': 'Which trigger shape the rest of the object uses.'}, 'kinds': {'type': 'string', 'description': 'event: required — event kinds to fire on, array or comma list (e.g. `split,analyst`).'}, 'signal': {'type': 'string', 'description': 'signal: required — a built-in signal name (e.g. `rsi_14`) or one of your custom signals (custom SQL is expanded and frozen at creation).'}, 'ticker': {'type': 'string', 'description': 'ticker: required — the symbol to watch (e.g. `NVDA`). signal: optional — restrict the signal to one symbol (omit to watch the whole universe).'}, 'event_q': {'type': 'string', 'description': "event: optional event-CONTENT filter in the `/v2/events` grammar over `(ticker, ts, kind, payload)` — e.g. `payload->>'firm' = 'Goldman Sachs'`. Composes with `trigger.q`."}, 'tickers': {'type': 'string', 'description': 'event: optional symbol list, max 50 (e.g. `AAPL,NVDA`). Mutually exclusive with `trigger.universe`.'}, 'universe': {'type': 'string', 'description': 'scan / signal / event: optional universe slug (`top_10`, `top_100`, or one of yours) scoping which tickers can fire. Mutually exclusive with `trigger.tickers` on event.'}, 'condition': {'type': 'string', 'description': 'signal: required for every non-boolean signal — a single bound typed like the signal: `>70` (numeric), `<YYYY-MM-DDTHH:MM:SSZ` (timestamp), `>=YYYY-MM-DD` (date), `=ETF` (string); sending one with a boolean or custom signal returns 400 (it does not apply). ticker: accepted as the original alias of `trigger.q`.'}}, 'description': 'What fires the webhook. A discriminated object — `trigger.type` picks the shape, and the fields below belong inside it. Each shape is also available as a flat-params shortcut: `POST /v2/scan/subscribe`, `/v2/tickers/{t}/subscribe`, `/v2/signals/{s}/subscribe`, `/v2/events/subscribe`.'}, 'device_id': {'type': 'string', 'description': 'Registered device id (channel `mobile_push`, see /v2/devices).'}, 'target_url': {'type': 'string', 'description': 'HTTPS delivery URL (the `webhook` channel), max 1024 characters. Omit for in-app delivery, or use `channel` + `discord_url`/`device_id` for other channels.'}, 'discord_url': {'type': 'string', 'description': 'Discord webhook URL (channel `discord`).'}}}
Ausgabeschema
{'type': 'object', 'required': ['as_of', 'id', 'name', 'q', 'rule_id', 'fields', 'order', 'dir', 'universe_id', 'cadence', 'channel', 'target_url', 'delivery', 'status', 'source', 'subscription_origin', 'last_predicate_value', 'created_at', 'updated_at', 'last_fired', 'last_match_set', 'next_eval_at', 'last_evaluated_at', 'channel_config', 'signing_secret'], 'properties': {'q': {'type': 'string', 'description': 'The stored predicate. Custom signals appear expanded: the SQL is frozen at creation.'}, 'id': {'type': 'string', 'description': 'The webhook id — `wh_…`, the handle for every other call on this record.'}, 'dir': {'type': 'string', 'description': 'Sort direction for that list; `null` means the default (`desc`).'}, 'name': {'type': 'string', 'description': 'Your label for the subscription.'}, '_meta': {'type': 'object', 'description': 'Returned on create only, and only when the rule or `columns` named a column under its pre-2026-09-07 spelling: `deprecated_columns` lists each one (`requested`, `use`, `note`). The stored rule carries the current name.'}, 'as_of': {'type': 'string', 'description': 'Server time this response was assembled (ISO 8601).'}, 'order': {'type': 'string', 'description': 'Sort signal for the payload row list; `null` means the evaluator default (`market_cap`).'}, 'fields': {'type': 'string', 'description': 'Extra signals carried on each fired match row; `null` means the standard set.'}, 'source': {'type': 'string', 'description': 'Which API version created the record; `v2` for anything you create today.'}, 'status': {'type': 'string', 'description': '`active` or `disabled`. Auto-disable follows repeated delivery failure.'}, 'cadence': {'type': 'string', 'description': 'How often the trigger is evaluated — `realtime`, `hourly`, or `nyse_open`.'}, 'channel': {'type': 'string', 'description': 'Where deliveries go: `webhook`, `discord`, `in_app`, or `mobile_push`.'}, 'event_q': {'type': 'string', 'description': 'Event-trigger webhooks only: the payload filter, or `null`.'}, 'rule_id': {'type': 'string', 'description': 'Legacy link to a v1 alert rule; `null` on everything created through v2.'}, 'delivery': {'type': 'string', 'description': 'Legacy alias of `channel`, kept aligned for older readers.'}, 'test_url': {'type': 'string', 'description': 'Returned on create only: the `POST /v2/webhooks/{id}/test` URL for this record.'}, 'created_at': {'type': 'number', 'description': 'Creation timestamp.'}, 'last_error': {'type': 'string', 'description': 'The last evaluation error; `null` on a healthy hook. The answer to "why is my webhook not firing?".'}, 'last_fired': {'type': 'number', 'description': 'When a delivery last went out; `null` if it never has.'}, 'target_url': {'type': 'string', 'description': 'Your HTTPS endpoint; `null` on every channel except `webhook`.'}, 'updated_at': {'type': 'number', 'description': 'Last modification timestamp.'}, 'event_kinds': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Event-trigger webhooks only: the kinds subscribed (`split`, `dividend`, `insider`, `analyst`, `earnings`).'}, 'universe_id': {'type': 'string', 'description': 'Universe the trigger is scoped to, or `null` for the whole market.'}, 'next_eval_at': {'type': 'number', 'description': 'When the evaluator will next consider this subscription.'}, 'trigger_kind': {'type': 'string', 'description': 'Event-trigger webhooks only: `event`.'}, 'event_tickers': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Event-trigger webhooks only: the symbols the trigger is scoped to, or `null` for the universe / whole market.'}, 'channel_config': {'type': 'object', 'description': 'Returned on create only: the channel-specific delivery settings as stored (e.g. the Discord URL, the device id).'}, 'last_match_set': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Tickers matching at the last evaluation — the set the next run is diffed against, which is what makes firing edge-triggered.'}, 'signing_secret': {'type': 'string', 'description': 'Returned on create only — shown once, never again. HMAC key for verifying the `X-Tickerbot-Signature` header on deliveries.'}, 'last_evaluated_at': {'type': 'number', 'description': 'When it was last evaluated; `null` until the first run.'}, 'last_eval_error_at': {'type': 'number', 'description': 'When the last evaluation error happened; `null` on a healthy hook.'}, 'subscription_origin': {'type': 'object', 'description': 'Which door created it — `type` (`ticker`/`signal`/`scan`/`event`), its `ref`, and the `condition` in display form.'}, 'last_predicate_value': {'type': 'string', 'description': "The trigger's value at the last evaluation; `null` until it has run."}}, 'additionalProperties': False}
Eingabeschema
{'type': 'object', 'required': ['signal'], 'properties': {'force': {'type': 'boolean', 'default': False, 'description': 'When `true`, skip the reference check and delete. References will break on next recompile.'}, 'signal': {'type': 'string', 'description': 'Custom signal slug (the signal name). A built-in name answers 404 — built-ins are read-only.'}}}
Eingabeschema
{'type': 'object', 'required': ['id'], 'properties': {'id': {'type': 'string', 'description': 'Universe slug.'}, 'force': {'type': 'boolean', 'default': False, 'description': 'A universe still referenced by live webhooks refuses to delete with `409 universe_referenced`. Pass `force=true` to delete anyway — those webhooks will match nothing until re-pointed or deleted.'}}}
Eingabeschema
{'type': 'object', 'required': ['id'], 'properties': {'id': {'type': 'string', 'description': 'Webhook id.'}}}
Eingabeschema
{'type': 'object', 'required': ['id'], 'properties': {'id': {'type': 'string', 'description': 'Webhook id.'}}}
Ausgabeschema
{'type': 'object', 'required': ['as_of', 'id', 'name', 'q', 'rule_id', 'fields', 'order', 'dir', 'universe_id', 'cadence', 'channel', 'target_url', 'delivery', 'status', 'source', 'subscription_origin', 'last_predicate_value', 'created_at', 'updated_at', 'last_fired', 'last_match_set', 'next_eval_at', 'last_evaluated_at'], 'properties': {'q': {'type': 'string', 'description': 'The stored predicate. Custom signals appear expanded: the SQL is frozen at creation.'}, 'id': {'type': 'string', 'description': 'The webhook id — `wh_…`, the handle for every other call on this record.'}, 'dir': {'type': 'string', 'description': 'Sort direction for that list; `null` means the default (`desc`).'}, 'name': {'type': 'string', 'description': 'Your label for the subscription.'}, 'as_of': {'type': 'string', 'description': 'Server time this response was assembled (ISO 8601).'}, 'order': {'type': 'string', 'description': 'Sort signal for the payload row list; `null` means the evaluator default (`market_cap`).'}, 'fields': {'type': 'string', 'description': 'Extra signals carried on each fired match row; `null` means the standard set.'}, 'source': {'type': 'string', 'description': 'Which API version created the record; `v2` for anything you create today.'}, 'status': {'type': 'string', 'description': '`active` or `disabled`. Auto-disable follows repeated delivery failure.'}, 'cadence': {'type': 'string', 'description': 'How often the trigger is evaluated — `realtime`, `hourly`, or `nyse_open`.'}, 'channel': {'type': 'string', 'description': 'Where deliveries go: `webhook`, `discord`, `in_app`, or `mobile_push`.'}, 'event_q': {'type': 'string', 'description': 'Event-trigger webhooks only: the payload filter, or `null`.'}, 'rule_id': {'type': 'string', 'description': 'Legacy link to a v1 alert rule; `null` on everything created through v2.'}, 'delivery': {'type': 'string', 'description': 'Legacy alias of `channel`, kept aligned for older readers.'}, 'created_at': {'type': 'number', 'description': 'Creation timestamp.'}, 'last_error': {'type': 'string', 'description': 'The last evaluation error; `null` on a healthy hook. The answer to "why is my webhook not firing?".'}, 'last_fired': {'type': 'number', 'description': 'When a delivery last went out; `null` if it never has.'}, 'target_url': {'type': 'string', 'description': 'Your HTTPS endpoint; `null` on every channel except `webhook`.'}, 'updated_at': {'type': 'number', 'description': 'Last modification timestamp.'}, 'event_kinds': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Event-trigger webhooks only: the kinds subscribed (`split`, `dividend`, `insider`, `analyst`, `earnings`).'}, 'universe_id': {'type': 'string', 'description': 'Universe the trigger is scoped to, or `null` for the whole market.'}, 'next_eval_at': {'type': 'number', 'description': 'When the evaluator will next consider this subscription.'}, 'trigger_kind': {'type': 'string', 'description': 'Event-trigger webhooks only: `event`.'}, 'event_tickers': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Event-trigger webhooks only: the symbols the trigger is scoped to, or `null` for the universe / whole market.'}, 'last_match_set': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Tickers matching at the last evaluation — the set the next run is diffed against, which is what makes firing edge-triggered.'}, 'last_evaluated_at': {'type': 'number', 'description': 'When it was last evaluated; `null` until the first run.'}, 'last_eval_error_at': {'type': 'number', 'description': 'When the last evaluation error happened; `null` on a healthy hook.'}, 'subscription_origin': {'type': 'object', 'description': 'Which door created it — `type` (`ticker`/`signal`/`scan`/`event`), its `ref`, and the `condition` in display form.'}, 'last_predicate_value': {'type': 'string', 'description': "The trigger's value at the last evaluation; `null` until it has run."}}, 'additionalProperties': False}
Eingabeschema
{'type': 'object', 'required': ['ticker', 'interval'], 'properties': {'to': {'type': 'string', 'description': 'Window end (inclusive): a bare `YYYY-MM-DD` means through the end of that day, same as series. Mutually exclusive with `asof` and `before` (400).'}, 'asof': {'type': 'string', 'description': "Point-in-time: the most recent bar whose period had closed at or before that moment. A bare `YYYY-MM-DD` means that day's close. A full timestamp means the last FINISHED bar — at 10:00 ET on a Wednesday the day's close has not happened, so `1d` returns Tuesday's bar. Returns one bar unless you also pass `limit`, which gives the last `limit` closed bars. Mutually exclusive with `before`/`cursor` (400). Unlimited depth."}, 'from': {'type': 'string', 'description': 'Window start (inclusive): `YYYY-MM-DD`, ISO timestamp, or epoch-ms. Combines with `to` for an explicit window; page within it using `cursor`. Mutually exclusive with `asof` and `before` (400).'}, 'limit': {'type': 'integer', 'default': 100, 'description': 'Most-recent N bars. Max 1000 — an over-cap value is clamped, not an error.'}, 'before': {'type': 'string', 'description': 'Return the N bars ending strictly before this date/timestamp — back-paging. Mutually exclusive with `cursor` (they are the same control — a 400 when both are sent).'}, 'cursor': {'type': 'string', 'description': "Continuation token from a prior response's `next_cursor`; sugar for `before` (sending both is a 400; a blank `cursor=` counts as absent), and the way to page inside a `from`/`to` window."}, 'ticker': {'type': 'string', 'description': 'Ticker symbol, or a comma-separated list (up to 50) for a bulk response keyed by symbol.'}, 'session': {'enum': ['all', 'regular'], 'type': 'string', 'default': 'all', 'description': 'Sub-hour intervals only. `all` (default) includes pre- and post-market bars. `regular` keeps bars whose start is in 09:30–16:00 ET (DST-aware). Why you might want it: the vendor buckets trades by SIP report time, and late-reported off-exchange (Form T) prints on thin names can land 20 min to hours late in a pre-market minute — a `$1.70` print at 08:13 ET on a `$3.85` stock. Daily high/low are untouched by those. `limit` counts after the filter; paging still works.'}, 'adjusted': {'type': 'boolean', 'description': 'Default `true`: prices are split-adjusted — restated after each later split, as the tape is, so a series is continuous across a split. `false` returns the price as it printed that day (a name that later did a 1:10 reverse split reads `21.4` adjusted and `2.14` on the tape), which is what a broker fill or a chart from that time shows. Volume scales the other way. Un-adjusted on read from the splits table; the store is untouched.'}, 'interval': {'enum': ['1s', '1m', '5m', '15m', '30m', '1h', '2h', '4h', '1d', '1w', '1mo'], 'type': 'string', 'description': "Bar interval. `2h`/`4h` roll up hourly bars; `1w`/`1mo` roll up daily bars into calendar weeks (Monday start) and months — the bar's `t` is the bucket start (UTC), and with `asof` the last bucket is the week/month to date."}}}
Ausgabeschema
{'type': 'object', 'required': ['as_of', 'interval', 'adjusted', 'session', 'count', 'coverage', 'bars'], 'properties': {'bars': {'type': 'array', 'items': {'type': 'string'}, 'description': 'OHLCV bars, chronological, in the compact array shape. Bulk requests key this by symbol instead.'}, 'note': {'type': 'string', 'description': 'Present only when there is something to disclose about how the page was served: the first request for a symbol at a sub-hour interval loads and stores its bars, so that one call is slower than later ones, and the note says so. Bulk responses carry `notes[symbol]` instead.'}, 'as_of': {'type': 'string', 'description': 'Server time this response was assembled (ISO 8601).'}, 'count': {'type': 'number', 'description': 'Bars returned in single-symbol mode; the number of SYMBOLS in bulk mode.'}, 'notes': {'type': 'object', 'description': 'Bulk (comma-list) requests only: the per-symbol disclosures, keyed by symbol, in place of `note`.'}, 'ticker': {'type': 'string', 'description': 'The symbol you asked for.'}, 'session': {'type': 'string', 'description': 'The session filter applied: `all` (default) or `regular` (09:30–16:00 ET, sub-hour intervals only).'}, 'adjusted': {'type': 'boolean', 'description': 'Whether the bars are split-adjusted — `true` unless you passed `adjusted=false`.'}, 'coverage': {'type': 'string', 'description': '`covered` when bars were found, `no_data` when nothing exists for the symbol in the window (before its first session, a market holiday, a thin name with no prints). A page that could not be completed is never a 200: it is a `503 unavailable` with `Retry-After`.'}, 'interval': {'type': 'string', 'description': 'The bar size served.'}, 'next_cursor': {'type': 'string', 'description': 'Opaque token for the next page; `null` on the last page. Absent on bulk (comma-list) requests, which are unpaged. Absent on bulk requests — page bulk symbol-by-symbol.'}}, 'additionalProperties': False}
Eingabeschema
{'type': 'object', 'required': ['ticker'], 'properties': {'limit': {'type': 'integer', 'default': 500, 'description': "Max holdings returned. Max 5000. When the cap cuts the list, the response sets `truncated: true` and `total` (the ETF's full holding count) — raise `limit` to at least `total` to get the full set, possible whenever `total` is within the 5000 cap (an over-cap `limit` is clamped to 5000, not an error). No `truncated` in the response means the list is complete."}, 'ticker': {'type': 'string', 'description': 'ETF symbol. Case-insensitive.'}}}
Ausgabeschema
{'type': 'object', 'required': ['as_of', 'ticker', 'is_etf', 'count', 'holdings'], 'properties': {'as_of': {'type': 'string', 'description': 'Server time this response was assembled (ISO 8601).'}, 'count': {'type': 'number', 'description': 'Holdings in this page.'}, 'total': {'type': 'number', 'description': 'Total constituents held, before `limit`.'}, 'is_etf': {'type': 'boolean', 'description': 'Whether the symbol is an ETF, from the instrument type on its ticker record.'}, 'ticker': {'type': 'string', 'description': 'The ETF you asked for.'}, 'holdings': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Constituents, heaviest first, each with its weight.'}, 'truncated': {'type': 'boolean', 'description': '`true` when `limit` cut the list short.'}}, 'additionalProperties': False}
Eingabeschema
{'type': 'object', 'required': ['ticker'], 'properties': {'ticker': {'type': 'string', 'description': 'ETF symbol. Case-insensitive.'}}}
Ausgabeschema
{'type': 'object', 'required': ['as_of', 'ticker', 'is_etf', 'count', 'sectors'], 'properties': {'as_of': {'type': 'string', 'description': 'Server time this response was assembled (ISO 8601).'}, 'count': {'type': 'number', 'description': 'Sectors returned.'}, 'is_etf': {'type': 'boolean', 'description': 'Whether the symbol is an ETF, from the instrument type on its ticker record.'}, 'ticker': {'type': 'string', 'description': 'The ETF you asked for.'}, 'sectors': {'type': 'array', 'items': {'type': 'string'}, 'description': "Sector weights, heaviest first, in the vendor's ETF-profile vocabulary."}}, 'additionalProperties': False}
Eingabeschema
{'type': 'object', 'properties': {'to': {'type': 'string', 'description': 'Latest timestamp (inclusive), `YYYY-MM-DD` or ISO.'}, 'asof': {'type': 'string', 'description': "Point-in-time read: ONE row per ticker — the state at that instant — rather than a range. `YYYY-MM-DD` or a full ISO timestamp, the same meaning `asof` carries on `/v2/tickers`, `/v2/scan` and `/v2/signals`. Cannot be combined with `from`/`to` or `cursor` (400) — a point and a window are contradictory, and `limit` has no meaning under it. It also resolves WHICH COMPANY held the symbol at that instant: a ticker that changed hands returns the row of whoever traded it then, so `tickers=SHLD&asof=2010-06-30` returns Sears Holdings' price and `asof=2026-01-01` returns the Global X defence ETF. Returns the most recent row at or before the instant, so a date inside a trading gap gives the last row before it. At `interval=1q` the anchor is the date the quarter was REPORTED (earnings release / filing), not fiscal period end — you get the latest quarter that was public knowledge at the instant, with restatements after it excluded."}, 'from': {'type': 'string', 'description': 'Earliest timestamp (inclusive), `YYYY-MM-DD` or ISO. Intraday requests default to a recent window (`1m`: 7 days, `1h`: 60 days) — the cursor keeps walking further back window-by-window, or pass `from` to widen it up front.'}, 'limit': {'type': 'integer', 'default': 252, 'description': 'Grid steps per page (shared across tickers). Max 1000 — an over-cap `limit` is clamped to 1000 (house convention, `limit=10000` means "max"). Separately, tickers × limit may not exceed 25,000 rows per page — over THAT cap is an explicit 400.'}, 'cursor': {'type': 'string', 'description': 'Opaque cursor from the previous response — every ticker pages backward in lockstep on the shared grid, no per-ticker gaps or duplicates.'}, 'ticker': {'type': 'string', 'description': 'Single-symbol form — `/v2/series?ticker=AAPL` is ticker history in its canonical spelling. Exactly one of `ticker` or `tickers` is required.'}, 'columns': {'type': 'string', 'description': 'Up to 25 columns (POST accepts an array): OHLCV names, signals, and your custom signals, freely mixed. Omitted → the ticker-history default set (price, change_1d_pct, relative_volume, market_cap), intersected with what the interval carries. At `1q`, `columns` is required and quarterly-only. `fields` accepted as an alias.'}, 'tickers': {'type': 'string', 'description': 'Comma-separated symbols, up to 50 (POST accepts a JSON array). Exactly one of `tickers` or `ticker` is required; when both are passed, `ticker` wins — so sending both silently narrows the request to one symbol.'}, 'interval': {'enum': ['1m', '1h', '1d', '1w', '1q'], 'type': 'string', 'default': '1d', 'description': 'Grid granularity. `1w` resamples the daily tier weekly (Monday-keyed); `1q` is the fiscal-quarter grid.'}, 'transitions_only': {'type': 'boolean', 'description': 'Only rows where a boolean signal changed state. Accepted spellings: `true`/`1`/`yes` and `false`/`0`/`no` (case-insensitive) — anything else is a 400, never silently off. Requires at least one boolean signal (built-in boolean or custom signal); each returned row carries `transitions: {column: "enter"|"exit"}`, and `_meta` lists the driving columns. Strict truth: only literal `true` is "on", so `null → true` is an enter and `true → null` an exit (a backfill boundary reads as an edge). Edges need a prior observation — on the oldest page of a walk the first row has no predecessor and yields no edge. A flip is dated by the state table and does not move with the column list: one recorded on a non-trading carry row keeps that date, with any bar columns `null` on that row (no bar exists there).'}}}
Ausgabeschema
{'type': 'object', 'required': ['as_of', 'interval', 'tickers', 'columns', 'count', 'next_cursor', '_meta', 'series'], 'properties': {'_meta': {'type': 'object', 'description': 'Per-column `sources` (`bars`, `state`, or `custom` for your own signals; `earnings`/`statements` at 1q) and per-ticker `coverage`, plus `non_trading_days_dropped` / `transitions_only` / `from_defaulted` when they apply. `deprecated_columns` lists any column you named under its pre-2026-09-07 spelling that was served under its current name (`requested`, `use`, `note`).'}, 'as_of': {'type': 'string', 'description': 'Server time this response was assembled (ISO 8601).'}, 'count': {'type': 'number', 'description': 'Rows per ticker in this page.'}, 'series': {'type': 'object', 'description': 'Keyed by ticker: an array of flat rows, chronological, each keyed `t` plus the columns you asked for.'}, 'columns': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Columns in the response, echoed.'}, 'tickers': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Symbols in the response, echoed.'}, 'interval': {'type': 'string', 'description': 'The grid granularity served.'}, 'next_cursor': {'type': 'string', 'description': 'Opaque token for the next page; `null` on the last page. Pass it back as `cursor`.'}}, 'additionalProperties': False}
Eingabeschema
{'type': 'object', 'required': ['signal'], 'properties': {'asof': {'type': 'string', 'description': "Optional. Target moment as `YYYY-MM-DD` (that day's close) or an ISO timestamp (that intraday moment) — the same read as it stood then, unlimited depth. Full contract under As of a past date."}, 'limit': {'type': 'integer', 'default': 50, 'description': 'Page size. Max 200.'}, 'cursor': {'type': 'string', 'description': 'Opaque cursor from the previous response.'}, 'signal': {'type': 'string', 'description': 'A signal name. Booleans (e.g. `golden_cross`, `above_sma_50`) are detected automatically; every other type (numeric `rsi_14`, timestamp `price_asof`, date `earnings_date`, string `asset_class`) requires a `condition`.'}, 'sort_by': {'enum': ['default', 'market_cap'], 'type': 'string', 'default': 'default', 'description': "Row order: `default` (alphabetic for booleans, highest-value-first for numerics) or `market_cap` (desc NULLS LAST; adds `market_cap` to each row). Live only — with `asof` it is a 400 (the snapshot's order is fixed)."}, 'interval': {'enum': ['1m', '1h', '1d', 'auto'], 'type': 'string', 'default': 'auto', 'description': 'Grain the past state is reconstructed at: `1m`, `1h`, `1d`, or `auto` (default). Only valid alongside `asof` — a live read with `interval` is a 400. Details under As of a past date.'}, 'universe': {'type': 'string', 'description': 'Optional. Scope to a system or caller-owned universe slug.'}, 'condition': {'type': 'string', 'description': 'Required for every non-boolean signal; the shape follows the signal\'s `type` in the catalog. Single bound, `<op><value>`. numeric: `>70`, `<=200`, `!=0` (operators `>`, `>=`, `=`, `!=`, `<`, `<=`). timestamp: an ISO instant, `<YYYY-MM-DDTHH:MM:SSZ` or `>=YYYY-MM-DD` (a bare date is midnight UTC). date: `>=YYYY-MM-DD` or `=YYYY-MM-DD`. string: `=ETF` or `!=ETF` (`=` and `!=` only; quotes optional). A relative window ("older than 15 minutes") is a `/v2/scan` query: `price_asof < now() - interval \'15 minutes\'`. Sending a condition with a boolean or custom signal returns 400 (it does not apply).'}, 'include_active_since': {'type': 'boolean', 'default': False, 'description': 'Built-in booleans only: adds `active_since` and `days_live` per row — the first day of the current true streak, from daily state (the day after the last false day; if the boolean has never been false since it first computed, the first true day). Looks back five years, so a boolean true for longer reports the window edge as a lower bound. Live only — a 400 with `asof`.'}}}
Ausgabeschema
{'type': 'object', 'required': ['as_of', 'signal', 'condition', 'universe', 'count', 'next_cursor', 'results'], 'properties': {'_meta': {'type': 'object', 'description': 'With `asof`: how the read was resolved — interval served and requested, blending, sources, frozen fields (see the as-of read below). On any read, `deprecated_columns` when you named the signal under its pre-2026-09-07 spelling and it was served under its current name.'}, 'as_of': {'type': 'string', 'description': 'Server time this response was assembled (ISO 8601).'}, 'count': {'type': 'number', 'description': 'Rows in this page.'}, 'signal': {'type': 'string', 'description': 'The signal you asked for.'}, 'results': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Matching tickers with the signal value.'}, 'universe': {'type': 'string', 'description': 'The universe you scoped to, echoed; `null` when unscoped.'}, 'condition': {'type': 'string', 'description': 'The bound you passed, echoed; `null` for boolean and custom signals.'}, 'next_cursor': {'type': 'string', 'description': 'Opaque token for the next page; `null` on the last page. Pass it back as `cursor`.'}}, 'additionalProperties': False}
Eingabeschema
{'type': 'object', 'required': ['ticker'], 'properties': {'asof': {'type': 'string', 'description': "Optional. Target moment as `YYYY-MM-DD` (that day's close) or an ISO timestamp (that intraday moment) — the same read as it stood then, unlimited depth. Full contract under As of a past date."}, 'ticker': {'type': 'string', 'description': 'One symbol, or a comma-separated list of up to 50 for a batch response keyed by symbol. Case-insensitive. Equities are bare symbols (`AAPL`); every other class carries a prefix — rates (`R:SOFR`), crypto (`X:BTCUSD`), fx (`X:EURUSD`). Bare `BTC`/`ETH` are US-listed ETFs, not spot crypto. See Tickers.'}, 'interval': {'enum': ['1m', '1h', '1d', 'auto'], 'type': 'string', 'default': 'auto', 'description': 'Grain the past state is reconstructed at: `1m`, `1h`, `1d`, or `auto` (default). Only valid alongside `asof` — a live read with `interval` is a 400. Details under As of a past date.'}}}
Ausgabeschema
{'type': 'object', 'required': ['as_of', 'data'], 'properties': {'data': {'type': 'object', 'description': 'The full ticker row — every signal on the schema page. On the list form, an object keyed by symbol, one full row each.'}, '_meta': {'type': 'object', 'description': 'With `asof` only: how the read was resolved — the interval served and requested, whether rows blend intervals, sources and frozen fields. See the as-of read below.'}, 'as_of': {'type': 'string', 'description': 'Server time this response was assembled (ISO 8601).'}, 'count': {'type': 'number', 'description': 'List form only — how many of `requested` were found.'}, 'ticker': {'type': 'string', 'description': 'The symbol you asked for, normalised. Single form only.'}, 'not_found': {'type': 'string', 'description': 'List form only — the requested symbols we do not track, in request order. An empty array when every symbol was found.'}, 'requested': {'type': 'string', 'description': 'List form only — the canonical symbols asked for, de-duplicated, in request order.'}}, 'additionalProperties': False}
Eingabeschema
{'type': 'object', 'required': ['ticker'], 'properties': {'ticker': {'type': 'string', 'description': 'Case-insensitive. Equities are bare symbols (`AAPL`); every other class carries a prefix — rates (`R:SOFR`), crypto (`X:BTCUSD`), fx (`X:EURUSD`). Bare `BTC`/`ETH` are US-listed ETFs, not spot crypto. See Tickers.'}}}
Ausgabeschema
{'type': 'object', 'required': ['as_of', 'ticker', 'name', 'minute_tier', 'spans', 'measured_fields'], 'properties': {'name': {'type': 'string', 'description': 'Company or instrument name.'}, 'as_of': {'type': 'string', 'description': 'Server time this response was assembled (ISO 8601).'}, 'spans': {'type': 'object', 'description': 'Per resolution — `oldest`, `newest`, `rows`.'}, 'ticker': {'type': 'string', 'description': 'The symbol you asked for.'}, 'minute_tier': {'type': 'object', 'description': 'Deprecated (see the changelog): an internal precompute roster that has no bearing on what bars you can read — sub-hour bars are available for every active symbol. Do not branch on it.'}, 'measured_fields': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Per-field measured depth where the backfill engine has probed — `field`, the grain it was measured at (`daily`, `hourly`, `minute`), `first_date`, `last_date`, `pct_complete`. Capped at 1500 rows.'}}, 'additionalProperties': False}
Eingabeschema
{'type': 'object', 'required': ['id'], 'properties': {'id': {'type': 'string', 'description': 'Universe slug.'}}}
Ausgabeschema
{'type': 'object', 'required': ['as_of', 'id', 'name', 'description', 'tickers', 'size', 'system', 'created_at', 'updated_at'], 'properties': {'id': {'type': 'string', 'description': "The slug — the universe's handle in `?universe=`."}, 'name': {'type': 'string', 'description': 'Display label.'}, 'size': {'type': 'number', 'description': 'Member count.'}, 'as_of': {'type': 'string', 'description': 'Server time this response was assembled (ISO 8601).'}, 'system': {'type': 'boolean', 'description': '`true` for a built-in universe, `false` for one you created.'}, 'tickers': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Members.'}, 'created_at': {'type': 'number', 'description': 'Creation timestamp.'}, 'updated_at': {'type': 'number', 'description': 'Last modification timestamp.'}, 'description': {'type': 'string', 'description': 'Free-form notes; `""` when unset.'}, 'effective_at': {'type': 'number', 'description': 'System universes only: when this membership took effect.'}, 'rebalance_method': {'type': 'string', 'description': 'System universes only: how membership is chosen.'}, 'next_rebalance_at': {'type': 'number', 'description': 'System universes only: when membership is next recomputed.'}}, 'additionalProperties': False}
Eingabeschema
{'type': 'object', 'required': ['id'], 'properties': {'id': {'type': 'string', 'description': 'Webhook id returned by a subscribe endpoint (`POST /v2/tickers/{T}/subscribe`, etc.).'}}}
Ausgabeschema
{'type': 'object', 'required': ['as_of', 'id', 'name', 'q', 'rule_id', 'fields', 'order', 'dir', 'universe_id', 'cadence', 'channel', 'target_url', 'delivery', 'status', 'source', 'subscription_origin', 'last_predicate_value', 'created_at', 'updated_at', 'last_fired', 'last_match_set', 'next_eval_at', 'last_evaluated_at'], 'properties': {'q': {'type': 'string', 'description': 'The stored predicate. Custom signals appear expanded: the SQL is frozen at creation.'}, 'id': {'type': 'string', 'description': 'The webhook id — `wh_…`, the handle for every other call on this record.'}, 'dir': {'type': 'string', 'description': 'Sort direction for that list; `null` means the default (`desc`).'}, 'name': {'type': 'string', 'description': 'Your label for the subscription.'}, 'as_of': {'type': 'string', 'description': 'Server time this response was assembled (ISO 8601).'}, 'order': {'type': 'string', 'description': 'Sort signal for the payload row list; `null` means the evaluator default (`market_cap`).'}, 'fields': {'type': 'string', 'description': 'Extra signals carried on each fired match row; `null` means the standard set.'}, 'source': {'type': 'string', 'description': 'Which API version created the record; `v2` for anything you create today.'}, 'status': {'type': 'string', 'description': '`active` or `disabled`. Auto-disable follows repeated delivery failure.'}, 'cadence': {'type': 'string', 'description': 'How often the trigger is evaluated — `realtime`, `hourly`, or `nyse_open`.'}, 'channel': {'type': 'string', 'description': 'Where deliveries go: `webhook`, `discord`, `in_app`, or `mobile_push`.'}, 'event_q': {'type': 'string', 'description': 'Event-trigger webhooks only: the payload filter, or `null`.'}, 'rule_id': {'type': 'string', 'description': 'Legacy link to a v1 alert rule; `null` on everything created through v2.'}, 'delivery': {'type': 'string', 'description': 'Legacy alias of `channel`, kept aligned for older readers.'}, 'created_at': {'type': 'number', 'description': 'Creation timestamp.'}, 'last_error': {'type': 'string', 'description': 'The last evaluation error; `null` on a healthy hook. The answer to "why is my webhook not firing?".'}, 'last_fired': {'type': 'number', 'description': 'When a delivery last went out; `null` if it never has.'}, 'target_url': {'type': 'string', 'description': 'Your HTTPS endpoint; `null` on every channel except `webhook`.'}, 'updated_at': {'type': 'number', 'description': 'Last modification timestamp.'}, 'event_kinds': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Event-trigger webhooks only: the kinds subscribed (`split`, `dividend`, `insider`, `analyst`, `earnings`).'}, 'universe_id': {'type': 'string', 'description': 'Universe the trigger is scoped to, or `null` for the whole market.'}, 'next_eval_at': {'type': 'number', 'description': 'When the evaluator will next consider this subscription.'}, 'trigger_kind': {'type': 'string', 'description': 'Event-trigger webhooks only: `event`.'}, 'event_tickers': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Event-trigger webhooks only: the symbols the trigger is scoped to, or `null` for the universe / whole market.'}, 'last_match_set': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Tickers matching at the last evaluation — the set the next run is diffed against, which is what makes firing edge-triggered.'}, 'last_evaluated_at': {'type': 'number', 'description': 'When it was last evaluated; `null` until the first run.'}, 'last_eval_error_at': {'type': 'number', 'description': 'When the last evaluation error happened; `null` on a healthy hook.'}, 'subscription_origin': {'type': 'object', 'description': 'Which door created it — `type` (`ticker`/`signal`/`scan`/`event`), its `ref`, and the `condition` in display form.'}, 'last_predicate_value': {'type': 'string', 'description': "The trigger's value at the last evaluation; `null` until it has run."}}, 'additionalProperties': False}
Eingabeschema
{'type': 'object', 'properties': {'q': {'type': 'string', 'description': "SQL WHERE over the projection — `ticker`, `ts`, `kind`, `payload` (plus ticker-state signals when `join=state`). When exactly ONE `kind` is named, that kind's payload fields are additionally first-class typed columns (`amount > 1`, `firm = 'Goldman Sachs'` — see each kind page for its list); multi-kind requests use `payload->>'…'`. Max 4000 chars. ANDs with the filter params."}, 'to': {'type': 'string', 'description': 'Window end — same strict ISO subset. A bare `YYYY-MM-DD` means through the end of that day, matching bars/series/spans; a timestamp is exclusive (events strictly before it). (`until` accepted as an alias.)'}, 'dir': {'enum': ['asc', 'desc'], 'type': 'string', 'default': 'desc', 'description': 'Aggregate-mode sort direction.'}, 'firm': {'type': 'string', 'description': 'Analyst-only structured filter — requires `kind=analyst` alone (`400` otherwise). Exact firm-name match on the ratings feed.'}, 'from': {'type': 'string', 'description': 'Events at/after this instant — strict ISO: `YYYY-MM-DD` or `YYYY-MM-DDTHH:MM[:SS]Z`. A bare `YYYY-MM-DD` means from the start of that day. (`since` accepted as an alias.)'}, 'join': {'enum': ['state'], 'type': 'string', 'description': "Set to `state` to allow ticker-state signals in `q`/`select`/`group_by`/`having`, evaluated as of each event's timestamp (daily resolution)."}, 'kind': {'enum': ['dividend', 'split', 'insider', 'analyst', 'earnings', 'signal', 'news', 'estimate_revision'], 'type': 'string', 'description': 'Comma list of kinds. Omitted → the five corporate kinds; `signal`, `news` and `estimate_revision` join only when named here.'}, 'limit': {'type': 'integer', 'default': 50, 'description': 'Page size (row modes) / max rollup rows (aggregate mode). Max 1000.'}, 'order': {'type': 'string', 'description': "Aggregate-mode sort — a bare column name or an output name only (put expressions in `select` and sort by their alias). A group key's name works too, whether you aliased it or it was named for you: `group_by=payload->>'firm' AS firm&order=firm`. Default: `events`. (Row mode is always newest-first.)"}, 'action': {'enum': ['upgrades', 'downgrades', 'initiates_coverage_on', 'maintains', 'reiterates', 'assumes', 'reinstates', 'suspends', 'terminates_coverage_on'], 'type': 'string', 'description': 'Analyst-only structured filter — requires `kind=analyst` alone. Same `action` vocabulary as Analyst actions.'}, 'cursor': {'type': 'string', 'description': 'Opaque cursor from the previous response — carries the original filters (and `q` when short), so pass it alone. Not valid with `group_by`.'}, 'having': {'type': 'string', 'description': 'Post-aggregation filter. Requires `group_by`.'}, 'select': {'type': 'string', 'description': 'Aggregate-mode output columns (requires `group_by`). Default: group keys + `COUNT(*) AS events`. Same naming rule as `group_by` — alias with `AS`, or take the name derived for you.'}, 'signal': {'type': 'string', 'description': 'Signal-only filter — requires `kind=signal` alone (`400` otherwise). One built-in boolean signal; REQUIRED with `q` or `join=state` on that kind. See Signal firings.'}, 'ticker': {'type': 'string', 'description': 'Single-ticker filter. When both `ticker` and `tickers` are passed, `ticker` wins.'}, 'tickers': {'type': 'string', 'description': 'Comma list of tickers (max 50). Mutually exclusive with `universe`.'}, 'group_by': {'type': 'string', 'description': "Comma list of rollup keys — switches the response to aggregate rows. Columns (`kind`, `ticker`), payload fields (`firm`, or the explicit `payload->>'firm'`), and expressions over them all roll up. Name a key with `AS` to choose its JSON key: `payload->>'firm' AS firm`. Un-named keys are named for you — a payload read takes its key (`payload->>'firm'` → `firm`), a function keeps the function's name (`lower(ticker)` → `lower`), and anything else falls back to `group_1`, `group_2`."}, 'interval': {'enum': ['1m', '1h', '1d', 'auto'], 'type': 'string', 'default': 'auto', 'description': "Grain the per-event state is reconstructed at, when `join=state`: `1m`, `1h`, `1d`, or `auto` (default). `auto` resolves to `1d` — the event set's tickers are not known before the query runs, and `1d` is the only tier covering the whole universe, so it is the only grain guaranteed to satisfy every event. An explicit `1m`/`1h` trades coverage for precision: events on tickers absent from that tier join to `null`. A referenced column the grain does not store is a `400`. Reported back as `_meta.state_interval`."}, 'universe': {'type': 'string', 'description': 'Universe slug (`top_10`, `top_100`, or one of yours) to scope the stream. Mutually exclusive with `tickers`.'}, 'transition': {'enum': ['enter', 'exit'], 'type': 'string', 'description': 'Signal-only filter — requires `kind=signal` alone. `enter` (false→true) or `exit` (true→false).'}}}
Ausgabeschema
{'type': 'object', 'required': ['as_of', 'query', 'count', 'results'], 'properties': {'_meta': {'type': 'object', 'description': 'With `join=state` only: `state_interval`, the grain the joined state was read at, and `deprecated_columns` when a state column was named under its pre-2026-09-07 spelling and served under its current name (`requested`, `use`, `note`).'}, 'as_of': {'type': 'string', 'description': 'Server time this response was assembled (ISO 8601).'}, 'count': {'type': 'number', 'description': 'Rows in this page.'}, 'query': {'type': 'object', 'description': 'Your filters, echoed exactly as you sent them — `q`, `select`, `group_by` and `having` come back in your spelling, not the SQL they compile to — including `join` and its grain when you passed `join=state`.'}, 'results': {'type': 'array', 'items': {'type': 'string'}, 'description': 'One row per event (`ticker`, `ts`, `kind`, `payload`), or rollup rows plus `truncated: true` when an aggregate exceeds `limit`.'}, 'truncated': {'type': 'boolean', 'description': 'Aggregate mode only (`group_by`): `true` when the rollup stopped at its row cap. Aggregate responses are unpaged, so `next_cursor` is absent there.'}, 'next_cursor': {'type': 'string', 'description': 'Opaque token for the next page; `null` on the last page. Carries `q_truncated: true` alongside it when an oversized `q` could not ride the token — resend `q` on later pages.'}}, 'additionalProperties': False}
Eingabeschema
{'type': 'object', 'properties': {'kind': {'enum': ['builtin', 'custom'], 'type': 'string', 'description': 'Filter by kind (`expression` accepted as a legacy alias for `custom`). Omit to return both.'}, 'limit': {'type': 'integer', 'default': 50, 'description': 'Page size for the custom-signal slice. Max 200.'}, 'cursor': {'type': 'string', 'description': 'Opaque cursor from a prior response.'}}}
Ausgabeschema
{'type': 'object', 'required': ['as_of', 'count', 'count_builtin', 'count_custom', 'next_cursor', 'signals'], 'properties': {'as_of': {'type': 'string', 'description': 'Server time this response was assembled (ISO 8601).'}, 'count': {'type': 'number', 'description': 'Rows in this page — the canonical count, equal to `count_builtin` + `count_custom`.'}, 'signals': {'type': 'array', 'items': {'type': 'string'}, 'description': 'The catalog, your custom signals first, then built-ins. Built-ins carry `kind: builtin` plus their taxonomy membership — `category`/`category_label`/`group`/`group_label` (slugs are stable, switch on those; labels are display strings) — yours carry `kind: custom` with the `expr`.'}, 'taxonomy': {'type': 'object', 'description': 'Absent when the page holds no built-ins (`kind=custom`). The signal taxonomy tree, once per response: `groups[]` in derivation-ladder order (record → behavior → indicator → company side), each with `slug`, `label`, `derivation`, `description`, and its `categories[]` (`slug`, `label`, `description`). Definitions live here and only here — rows carry pointers, never the descriptions. Omitted on `kind=custom`.'}, 'next_cursor': {'type': 'string', 'description': 'Opaque token for the next page; `null` on the last page. Pass it back as `cursor`.'}, 'count_custom': {'type': 'number', 'description': 'Your custom signals.'}, 'count_builtin': {'type': 'number', 'description': 'Built-in signals in the catalog.'}}, 'additionalProperties': False}
Eingabeschema
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'default': 50, 'description': 'Page size. Max 1000.'}, 'cursor': {'type': 'string', 'description': "Opaque cursor from the previous response's `next_cursor` field. Continues the walk from after that page. A cursor minted under `search` only resumes the same search."}, 'search': {'type': 'string', 'description': 'Case-insensitive match on `ticker` or `name`, max 64 characters (longer is a 400). Results are ranked: an exact ticker match first, then symbols that start with the term, then name matches — alphabetical within each rank. The cursor carries the rank, so paging a search never repeats or skips.'}, 'exchange': {'type': 'string', 'description': 'Filter by exchange name — the value rows carry in their `exchange` field. MIC codes (`XNAS`, `XNYS`, `BATS`) are also accepted and match `exchange_mic`. A malformed value (non-letters, over 16 chars) is a 400.'}, 'asset_type': {'enum': ['CS', 'ETF', 'ADRC', 'PFD', 'FUND', 'UNIT', 'SP', 'ETS', 'WARRANT', 'RIGHT', 'ETN', 'ETV', 'equity'], 'type': 'string', 'description': 'Filter by instrument type WITHIN equities — the stored `asset_type` value (`CS`, `ETF`, `ADRC`, `PFD`, `FUND`, `UNIT`, `SP`, `ETS`, `WARRANT`, `RIGHT`, `ETN`, `ETV`), matched case-insensitively. `equity` is a convenience value expanding to the equity-like set. This is NOT an asset class: `asset_type=crypto` is rejected — use `asset_class=crypto`.'}, 'asset_class': {'type': 'string', 'description': "Filter by asset class — `stocks`, `rates`, `crypto`, `fx`, or a comma-separated list (the live classes today; validated for shape, not against a fixed list, so a well-formed class we don't track simply matches nothing — same contract as scan). Omit for every class. This is the class of INSTRUMENT, distinct from `asset_type` below (the instrument type within equities). Every row carries its `asset_class`, so a non-equity row identifies itself."}}}
Ausgabeschema
{'type': 'object', 'required': ['as_of', 'count', 'next_cursor', 'results'], 'properties': {'_meta': {'type': 'object', 'description': 'With `asset_class` only: `scope.asset_class` lists the classes the page was filtered to.'}, 'as_of': {'type': 'string', 'description': 'Server time this response was assembled (ISO 8601).'}, 'count': {'type': 'number', 'description': 'Rows in this page.'}, 'results': {'type': 'array', 'items': {'type': 'string'}, 'description': 'One identity row per symbol — the thirteen signals named above, nothing else. `active: false` rows carry `delisted_utc`; they are still addressable on the state route with `asof`.'}, 'next_cursor': {'type': 'string', 'description': 'Opaque token for the next page; `null` on the last page.'}}, 'additionalProperties': False}
Eingabeschema
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'default': 50, 'description': 'Page size (applies to your own). Max 100.'}, 'owner': {'enum': ['me', 'system', 'all'], 'type': 'string', 'default': 'me', 'description': 'Which universes to list: `me` (your own), `system` (built-ins), or `all` (both).'}, 'cursor': {'type': 'string', 'description': 'Opaque cursor from the previous response.'}}}
Ausgabeschema
{'type': 'object', 'required': ['as_of', 'count', 'next_cursor', 'universes'], 'properties': {'as_of': {'type': 'string', 'description': 'Server time this response was assembled (ISO 8601).'}, 'count': {'type': 'number', 'description': 'Rows in this page.'}, 'universes': {'type': 'array', 'items': {'type': 'string'}, 'description': 'The universes in scope. Every row carries `system: true|false`.'}, 'next_cursor': {'type': 'string', 'description': 'Opaque token for the next page; `null` on the last page. Pass it back as `cursor`.'}}, 'additionalProperties': False}
Eingabeschema
{'type': 'object', 'required': ['id'], 'properties': {'id': {'type': 'string', 'description': 'Webhook id.'}, 'to': {'type': 'string', 'description': 'Only deliveries created at/before this moment — same value grammar as `from`. A date-only value means through the end of that UTC day. `from` after `to` is a 400.'}, 'from': {'type': 'string', 'description': 'Only deliveries created at/after this moment — epoch seconds, epoch milliseconds (13+ digits), or an ISO datetime (`since` is accepted as an alias). Delivery history is retained for 90 days; deleting a webhook deletes its delivery history with it.'}, 'limit': {'type': 'integer', 'default': 50, 'description': 'Page size. Max 100.'}, 'cursor': {'type': 'string', 'description': 'Opaque cursor.'}, 'status': {'enum': ['pending', 'delivered', 'permanent_failure'], 'type': 'string', 'description': 'Filter by delivery status.'}}}
Ausgabeschema
{'type': 'object', 'required': ['as_of', 'count', 'next_cursor', 'deliveries'], 'properties': {'as_of': {'type': 'string', 'description': 'Server time this response was assembled (ISO 8601).'}, 'count': {'type': 'number', 'description': 'Rows in this page.'}, 'deliveries': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Attempts, newest first: status, attempt, response code, error, and `body_string` — the exact JSON POSTed.'}, 'next_cursor': {'type': 'string', 'description': 'Opaque token for the next page; `null` on the last page. Pass it back as `cursor`.'}}, 'additionalProperties': False}
Eingabeschema
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'default': 50, 'description': 'Page size. Max 100.'}, 'cursor': {'type': 'string', 'description': 'Opaque cursor from the previous response.'}, 'status': {'enum': ['active', 'disabled'], 'type': 'string', 'description': 'Filter by status: `active` or `disabled` — the only two states a webhook has (`disabled` covers both a user pause and the automatic disable after repeated delivery failures; `consecutive_failures`/`last_error` on each record say which). Omit for all.'}}}
Ausgabeschema
{'type': 'object', 'required': ['as_of', 'count', 'next_cursor', 'webhooks'], 'properties': {'as_of': {'type': 'string', 'description': 'Server time this response was assembled (ISO 8601).'}, 'count': {'type': 'number', 'description': 'Rows in this page.'}, 'webhooks': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Your subscriptions, newest first, each with its `subscription_origin` and health fields. `signing_secret` is stripped — it is shown only on create.'}, 'next_cursor': {'type': 'string', 'description': 'Opaque token for the next page; `null` on the last page. Pass it back as `cursor`.'}}, 'additionalProperties': False}
Eingabeschema
{'type': 'object', 'required': ['q'], 'properties': {'q': {'type': 'string', 'description': 'SQL WHERE expression. Max 4000 chars; semicolons, comments and write keywords are rejected. Your custom signals are valid here — each expands to its SQL at run time.'}, 'dir': {'enum': ['asc', 'desc'], 'type': 'string', 'default': 'desc', 'description': 'Sort direction.'}, 'asof': {'type': 'string', 'description': "Optional. Target moment as `YYYY-MM-DD` (that day's close) or an ISO timestamp (that intraday moment) — the same read as it stood then, unlimited depth. Full contract under As of a past date."}, 'full': {'type': 'boolean', 'default': False, 'description': 'Return every signal instead of the default set. Mutually exclusive with `columns` — passing both is a 400.'}, 'limit': {'type': 'integer', 'default': 50, 'description': 'Page size. Max 100. Aggregate mode does not paginate — it sets `truncated: true` when groups were cut, so sort with `order` to keep the ones you want.'}, 'order': {'type': 'string', 'default': 'change_1d_pct', 'description': "Signal to sort by. In aggregate mode the default is the count alias `tickers` — or, with a custom `select`, the last item's alias — sorted NULLS LAST with the group keys as tiebreak."}, 'cursor': {'type': 'string', 'description': "Opaque cursor from the previous response's `next_cursor`. Row mode only."}, 'having': {'type': 'string', 'description': 'Filter the aggregate rows (requires `group_by`). Custom signals are valid here too.'}, 'select': {'type': 'string', 'description': 'Aggregate output items (requires `group_by`). Default: the group keys + `COUNT(*) AS tickers`. Supports count/avg/sum/min/max/stddev/string_agg/bool_and/bool_or plus `FILTER (WHERE …)`, and your custom signals inside expressions. Alias with `AS`; a last item without one is a 400.'}, 'columns': {'type': 'string', 'description': 'Extra signals per row, ADDITIVE — the defaults are always present (ticker, name, asset_class, asset_type, price, change_1d_pct, gap_pct, relative_volume, market_cap). `fields` accepted as an alias.'}, 'group_by': {'type': 'string', 'description': 'AGGREGATE MODE: 1–6 group keys (signals, expressions, or one of your custom signals as a boolean key). Results become rollup rows. Name a key with `AS` to choose its JSON key (`market_cap > 1e11 AS mega`); an un-named expression is named for you rather than returned as `?column?`. Incompatible with `columns`/`full`/`cursor`; works with `asof`.'}, 'interval': {'enum': ['1m', '1h', '1d', 'auto'], 'type': 'string', 'default': 'auto', 'description': 'Grain the past state is reconstructed at: `1m`, `1h`, `1d`, or `auto` (default). Only valid alongside `asof` — a live read with `interval` is a 400. Details under As of a past date.'}, 'universe': {'type': 'string', 'description': 'Slug of a system universe (`top_10`, `top_100`) or one of your own. Omitted, the scan runs across all ~21,963 tracked tickers.'}, 'asset_class': {'type': 'string', 'description': "One or more asset classes — slug or comma-separated list (`stocks`, `rates`, `crypto`, `fx`). Validated for shape, not against a fixed list, so a well-formed class we don't track simply matches nothing. Echoed in `query`."}}}
Ausgabeschema
{'type': 'object', 'required': ['as_of', 'query', 'count', 'results'], 'properties': {'_meta': {'type': 'object', 'description': '`null_coverage` reports, per signal in the predicate, how many in-scope rows are NULL and therefore never evaluated — absence from `results` means "no value", not "did not match". `scope` additionally describes an explicit `universe`. `deprecated_columns` lists any column you named under its pre-2026-09-07 spelling that was served under its current name (`requested`, `use`, `note`).'}, 'as_of': {'type': 'string', 'description': 'Server time this response was assembled (ISO 8601).'}, 'count': {'type': 'number', 'description': 'Rows in this page.'}, 'query': {'type': 'object', 'description': 'Your query, echoed — `q`, `order`, `dir`, `limit`, and any scope.'}, 'results': {'type': 'array', 'items': {'type': 'string'}, 'description': 'One row per match — every signal on the schema page, plus any you named.'}, 'truncated': {'type': 'boolean', 'description': 'Aggregate mode only (`group_by`): `true` when the rollup stopped at its row cap. Aggregate responses are unpaged, so `next_cursor` is absent there.'}, 'next_cursor': {'type': 'string', 'description': 'Opaque token for the next page; `null` on the last page. Pass it back as `cursor`.'}}, 'additionalProperties': False}
Eingabeschema
{'type': 'object', 'properties': {'q': {'type': 'string', 'description': 'WHERE clause over the news_article table. Max 4000 chars. Required UNLESS `search` or a scoping param (`ticker`/`tickers`/`universe`/`from`/`to`) is present — the simplest call needs no SQL. Queryable columns: `time_published`, `title`, `summary`, `source`, `source_domain`, `category`, `authors`, `topics`, `overall_sentiment_score`, `overall_sentiment_label`, `tickers`, `ticker_data`, `banner_image`, `url`, `id`, `created_at` — plus `tk`, the per-ticker UNNEST alias. Signal/state columns are not joinable here.'}, 'to': {'type': 'string', 'description': 'Articles strictly before this instant — same strict ISO subset, matching `/v2/events`. (`until` accepted as an alias.)'}, 'dir': {'enum': ['asc', 'desc'], 'type': 'string', 'default': 'desc', 'description': 'Sort direction.'}, 'from': {'type': 'string', 'description': 'Earliest `time_published` (inclusive) — strict ISO: `YYYY-MM-DD` or `YYYY-MM-DDTHH:MM[:SS]Z`. (`since` accepted as an alias.)'}, 'limit': {'type': 'integer', 'default': 50, 'description': 'Page size. Max 1000.'}, 'order': {'type': 'string', 'description': 'Sort — a bare column name or SELECT alias only (put expressions in `select` and order by their alias). Defaults to `time_published` (article rows) or `volume` (aggregate rows).'}, 'cursor': {'type': 'string', 'description': "Opaque pagination cursor from a prior response's `next_cursor`."}, 'having': {'type': 'string', 'description': 'HAVING clause on the aggregate (max 1000 chars). Requires `group_by`.'}, 'search': {'type': 'string', 'description': 'Full-text search over `title` + `summary` — websearch grammar: `apple earnings` (all words), `"price target"` (phrase), `chips OR semiconductors`, `-crypto` (negation). Max 200 chars. ANDs with `q` and the scoping params. Language-stemmed English.'}, 'select': {'type': 'string', 'description': 'Columns/expressions to return (max 2000 chars). Defaults to article columns (no `group_by`) or `<group_by cols>, COUNT(*) AS volume` (with `group_by`).'}, 'ticker': {'type': 'string', 'description': 'Articles mentioning this symbol (ANDed with `q`).'}, 'tickers': {'type': 'string', 'description': 'Comma list, up to 50 — articles mentioning ANY of them. Not combinable with `ticker` or `universe`.'}, 'group_by': {'type': 'string', 'description': 'AGGREGATE MODE: comma-separated group keys, 1-6 (max 1000 chars). Switches the response to rollup rows. Use `tk` to roll up per ticker without writing the UNNEST. Name a key with `AS` to choose its JSON key; an un-named expression is named for you rather than returned as `?column?`.'}, 'universe': {'type': 'string', 'description': 'Universe slug — articles mentioning any member. Not combinable with `ticker`/`tickers`.'}}}
Ausgabeschema
{'type': 'object', 'required': ['as_of', 'query', 'count', 'next_cursor', 'results'], 'properties': {'as_of': {'type': 'string', 'description': 'Server time this response was assembled (ISO 8601).'}, 'count': {'type': 'number', 'description': 'Rows in this page.'}, 'query': {'type': 'object', 'description': 'Your filters, echoed.'}, 'results': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Article rows, or rollup rows when you passed `group_by`. Aggregate responses add `truncated: true` when `limit` cut the group list.'}, 'truncated': {'type': 'boolean', 'description': 'Aggregate mode only (`group_by`): `true` when the rollup stopped at its row cap.'}, 'next_cursor': {'type': 'string', 'description': 'Opaque token for the next page; `null` on the last page. Pass it back as `cursor`.'}}, 'additionalProperties': False}
Eingabeschema
{'type': 'object', 'required': ['kinds'], 'properties': {'q': {'type': 'string', 'description': "Optional row-STATE filter evaluated against the event's ticker at fire time. Same grammar as scan `q`; custom signals are expanded and frozen at creation."}, 'name': {'type': 'string', 'description': 'Display name. Defaults to `events: <kinds> · <scope>`.'}, 'kinds': {'enum': ['dividend', 'split', 'insider', 'analyst', 'earnings'], 'type': 'string', 'description': 'Event kinds to fire on — array or comma list.'}, 'ticker': {'type': 'string', 'description': 'Single-symbol shorthand for `tickers`.'}, 'channel': {'enum': ['webhook', 'discord', 'in_app', 'mobile_push'], 'type': 'string', 'description': 'Delivery channel. `slack` is reserved and returns `501`.'}, 'event_q': {'type': 'string', 'description': 'Optional event-CONTENT filter in the `/v2/events` grammar — only `ticker`, `ts`, `kind`, `payload` may appear. Composes with `q`.'}, 'tickers': {'type': 'string', 'description': 'Scope to specific tickers (max 50). Mutually exclusive with `universe` — and with the singular alias `ticker` (sending both is a 400). Omit both for all tickers.'}, 'universe': {'type': 'string', 'description': 'Scope to a universe slug (`top_10`, `top_100`, or one of yours). `universe_id` accepted as an alias.'}, 'device_id': {'type': 'string', 'description': 'Device to notify, from `POST /v2/devices/register`. Required when `channel` is `mobile_push`; unknown ids are a 404 `device_not_found`.'}, 'target_url': {'type': 'string', 'description': 'HTTPS delivery URL; or use `channel` + `discord_url`/`device_id`. Omit for in-app.'}, 'discord_url': {'type': 'string', 'description': 'Discord incoming-webhook URL. Required when `channel` is `discord`. Stored as a posting credential: the create response echoes it back under `channel_config`, but every later read (list, get, deliveries) strips it and sets `channel_config_present: true` instead.'}}}
Ausgabeschema
{'type': 'object', 'required': ['as_of', 'id', 'name', 'q', 'rule_id', 'fields', 'order', 'dir', 'universe_id', 'cadence', 'channel', 'target_url', 'delivery', 'status', 'source', 'subscription_origin', 'last_predicate_value', 'created_at', 'updated_at', 'last_fired', 'last_match_set', 'next_eval_at', 'last_evaluated_at', 'channel_config', 'signing_secret'], 'properties': {'q': {'type': 'string', 'description': 'The stored predicate. Custom signals appear expanded: the SQL is frozen at creation.'}, 'id': {'type': 'string', 'description': 'The webhook id — `wh_…`, the handle for every other call on this record.'}, 'dir': {'type': 'string', 'description': 'Sort direction for that list; `null` means the default (`desc`).'}, 'name': {'type': 'string', 'description': 'Your label for the subscription.'}, '_meta': {'type': 'object', 'description': 'Returned on create only, and only when the rule or `columns` named a column under its pre-2026-09-07 spelling: `deprecated_columns` lists each one (`requested`, `use`, `note`). The stored rule carries the current name.'}, 'as_of': {'type': 'string', 'description': 'Server time this response was assembled (ISO 8601).'}, 'order': {'type': 'string', 'description': 'Sort signal for the payload row list; `null` means the evaluator default (`market_cap`).'}, 'fields': {'type': 'string', 'description': 'Extra signals carried on each fired match row; `null` means the standard set.'}, 'source': {'type': 'string', 'description': 'Which API version created the record; `v2` for anything you create today.'}, 'status': {'type': 'string', 'description': '`active` or `disabled`. Auto-disable follows repeated delivery failure.'}, 'cadence': {'type': 'string', 'description': 'How often the trigger is evaluated — `realtime`, `hourly`, or `nyse_open`.'}, 'channel': {'type': 'string', 'description': 'Where deliveries go: `webhook`, `discord`, `in_app`, or `mobile_push`.'}, 'event_q': {'type': 'string', 'description': 'Event-trigger webhooks only: the payload filter, or `null`.'}, 'rule_id': {'type': 'string', 'description': 'Legacy link to a v1 alert rule; `null` on everything created through v2.'}, 'delivery': {'type': 'string', 'description': 'Legacy alias of `channel`, kept aligned for older readers.'}, 'test_url': {'type': 'string', 'description': 'Returned on create only: the `POST /v2/webhooks/{id}/test` URL for this record.'}, 'created_at': {'type': 'number', 'description': 'Creation timestamp.'}, 'last_error': {'type': 'string', 'description': 'The last evaluation error; `null` on a healthy hook. The answer to "why is my webhook not firing?".'}, 'last_fired': {'type': 'number', 'description': 'When a delivery last went out; `null` if it never has.'}, 'target_url': {'type': 'string', 'description': 'Your HTTPS endpoint; `null` on every channel except `webhook`.'}, 'updated_at': {'type': 'number', 'description': 'Last modification timestamp.'}, 'event_kinds': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Event-trigger webhooks only: the kinds subscribed (`split`, `dividend`, `insider`, `analyst`, `earnings`).'}, 'universe_id': {'type': 'string', 'description': 'Universe the trigger is scoped to, or `null` for the whole market.'}, 'next_eval_at': {'type': 'number', 'description': 'When the evaluator will next consider this subscription.'}, 'trigger_kind': {'type': 'string', 'description': 'Event-trigger webhooks only: `event`.'}, 'event_tickers': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Event-trigger webhooks only: the symbols the trigger is scoped to, or `null` for the universe / whole market.'}, 'channel_config': {'type': 'object', 'description': 'Returned on create only: the channel-specific delivery settings as stored (e.g. the Discord URL, the device id).'}, 'last_match_set': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Tickers matching at the last evaluation — the set the next run is diffed against, which is what makes firing edge-triggered.'}, 'signing_secret': {'type': 'string', 'description': 'Returned on create only — shown once, never again. HMAC key for verifying the `X-Tickerbot-Signature` header on deliveries.'}, 'last_evaluated_at': {'type': 'number', 'description': 'When it was last evaluated; `null` until the first run.'}, 'last_eval_error_at': {'type': 'number', 'description': 'When the last evaluation error happened; `null` on a healthy hook.'}, 'subscription_origin': {'type': 'object', 'description': 'Which door created it — `type` (`ticker`/`signal`/`scan`/`event`), its `ref`, and the `condition` in display form.'}, 'last_predicate_value': {'type': 'string', 'description': "The trigger's value at the last evaluation; `null` until it has run."}}, 'additionalProperties': False}
Eingabeschema
{'type': 'object', 'required': ['q'], 'properties': {'q': {'type': 'string', 'description': 'WHERE-clause expression using signal names — the same grammar and the same 4000-char cap as `POST /v2/scan`, so anything scannable is subscribable. Custom signals are expanded and frozen in at creation.'}, 'dir': {'enum': ['asc', 'desc'], 'type': 'string', 'default': 'desc', 'description': 'Sort direction for `order`.'}, 'name': {'type': 'string', 'description': 'Human-readable label (up to 80 chars). Defaults to `scan: <q>`.'}, 'order': {'type': 'string', 'default': 'market_cap', 'description': "Signal the payload's match lists are sorted by before the 100-row cap applies, so a truncated list is the deterministic top 100 rather than an arbitrary sample. Must be a real signal (validated at creation)."}, 'cadence': {'enum': ['realtime', 'hourly', 'nyse_open'], 'type': 'string', 'description': '`realtime` (the default) is evaluated on every data refresh (~1×/min); `hourly` and `nyse_open` throttle to a batch schedule. `1m` is a deprecated alias for `realtime`.'}, 'channel': {'enum': ['webhook', 'discord', 'in_app', 'mobile_push'], 'type': 'string', 'description': 'Delivery channel. `webhook` (POST to `target_url`), `discord` (embed to `discord_url`), `in_app` (dashboard only), or `mobile_push` (requires a `device_id` from `POST /v2/devices/register`). Inferred when omitted: `webhook` if `target_url` is set, `discord` if `discord_url` is set, else `in_app`. `slack` is reserved and returns `501`.'}, 'columns': {'type': 'string', 'description': 'Extra signals per fired payload match row, beyond the standard set (`ticker`, `name`, `asset_type`, `price`, `change_1d_pct`, `market_cap`). Each must be a real signal; unknown ones are rejected at creation. `fields` accepted as an alias — and the RESPONSE reports them under `fields`, as an array.'}, 'universe': {'type': 'string', 'description': 'System or user-owned universe to scope the scan. `universe_id` accepted as an alias. Unknown universes are a 404 `universe_not_found`.'}, 'device_id': {'type': 'string', 'description': 'Device to notify, from `POST /v2/devices/register`. Required when `channel` is `mobile_push`; unknown ids are a 404 `device_not_found`.'}, 'target_url': {'type': 'string', 'description': 'https:// URL to POST when the match set changes. Omit for in-app delivery.'}, 'discord_url': {'type': 'string', 'description': 'Discord incoming-webhook URL. Required when `channel` is `discord`. Stored as a posting credential: the create response echoes it back under `channel_config`, but every later read (list, get, deliveries) strips it and sets `channel_config_present: true` instead.'}}}
Ausgabeschema
{'type': 'object', 'required': ['as_of', 'id', 'name', 'q', 'rule_id', 'fields', 'order', 'dir', 'universe_id', 'cadence', 'channel', 'target_url', 'delivery', 'status', 'source', 'subscription_origin', 'last_predicate_value', 'created_at', 'updated_at', 'last_fired', 'last_match_set', 'next_eval_at', 'last_evaluated_at', 'channel_config', 'signing_secret'], 'properties': {'q': {'type': 'string', 'description': 'The stored predicate. Custom signals appear expanded: the SQL is frozen at creation.'}, 'id': {'type': 'string', 'description': 'The webhook id — `wh_…`, the handle for every other call on this record.'}, 'dir': {'type': 'string', 'description': 'Sort direction for that list; `null` means the default (`desc`).'}, 'name': {'type': 'string', 'description': 'Your label for the subscription.'}, '_meta': {'type': 'object', 'description': 'Returned on create only, and only when the rule or `columns` named a column under its pre-2026-09-07 spelling: `deprecated_columns` lists each one (`requested`, `use`, `note`). The stored rule carries the current name.'}, 'as_of': {'type': 'string', 'description': 'Server time this response was assembled (ISO 8601).'}, 'order': {'type': 'string', 'description': 'Sort signal for the payload row list; `null` means the evaluator default (`market_cap`).'}, 'fields': {'type': 'string', 'description': 'Extra signals carried on each fired match row; `null` means the standard set.'}, 'source': {'type': 'string', 'description': 'Which API version created the record; `v2` for anything you create today.'}, 'status': {'type': 'string', 'description': '`active` or `disabled`. Auto-disable follows repeated delivery failure.'}, 'cadence': {'type': 'string', 'description': 'How often the trigger is evaluated — `realtime`, `hourly`, or `nyse_open`.'}, 'channel': {'type': 'string', 'description': 'Where deliveries go: `webhook`, `discord`, `in_app`, or `mobile_push`.'}, 'event_q': {'type': 'string', 'description': 'Event-trigger webhooks only: the payload filter, or `null`.'}, 'rule_id': {'type': 'string', 'description': 'Legacy link to a v1 alert rule; `null` on everything created through v2.'}, 'delivery': {'type': 'string', 'description': 'Legacy alias of `channel`, kept aligned for older readers.'}, 'test_url': {'type': 'string', 'description': 'Returned on create only: the `POST /v2/webhooks/{id}/test` URL for this record.'}, 'created_at': {'type': 'number', 'description': 'Creation timestamp.'}, 'last_error': {'type': 'string', 'description': 'The last evaluation error; `null` on a healthy hook. The answer to "why is my webhook not firing?".'}, 'last_fired': {'type': 'number', 'description': 'When a delivery last went out; `null` if it never has.'}, 'target_url': {'type': 'string', 'description': 'Your HTTPS endpoint; `null` on every channel except `webhook`.'}, 'updated_at': {'type': 'number', 'description': 'Last modification timestamp.'}, 'event_kinds': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Event-trigger webhooks only: the kinds subscribed (`split`, `dividend`, `insider`, `analyst`, `earnings`).'}, 'universe_id': {'type': 'string', 'description': 'Universe the trigger is scoped to, or `null` for the whole market.'}, 'next_eval_at': {'type': 'number', 'description': 'When the evaluator will next consider this subscription.'}, 'trigger_kind': {'type': 'string', 'description': 'Event-trigger webhooks only: `event`.'}, 'event_tickers': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Event-trigger webhooks only: the symbols the trigger is scoped to, or `null` for the universe / whole market.'}, 'channel_config': {'type': 'object', 'description': 'Returned on create only: the channel-specific delivery settings as stored (e.g. the Discord URL, the device id).'}, 'last_match_set': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Tickers matching at the last evaluation — the set the next run is diffed against, which is what makes firing edge-triggered.'}, 'signing_secret': {'type': 'string', 'description': 'Returned on create only — shown once, never again. HMAC key for verifying the `X-Tickerbot-Signature` header on deliveries.'}, 'last_evaluated_at': {'type': 'number', 'description': 'When it was last evaluated; `null` until the first run.'}, 'last_eval_error_at': {'type': 'number', 'description': 'When the last evaluation error happened; `null` on a healthy hook.'}, 'subscription_origin': {'type': 'object', 'description': 'Which door created it — `type` (`ticker`/`signal`/`scan`/`event`), its `ref`, and the `condition` in display form.'}, 'last_predicate_value': {'type': 'string', 'description': "The trigger's value at the last evaluation; `null` until it has run."}}, 'additionalProperties': False}
Eingabeschema
{'type': 'object', 'required': ['signal'], 'properties': {'dir': {'enum': ['asc', 'desc'], 'type': 'string', 'default': 'desc', 'description': 'Sort direction for `order`.'}, 'name': {'type': 'string', 'description': 'Human-readable label (up to 80 chars). Defaults to the predicate — `at_52w_high` for a boolean, `rsi_14 > 70` for a numeric, prefixed with `<TICKER>: ` when `ticker` scopes it.'}, 'order': {'type': 'string', 'default': 'market_cap', 'description': "Signal the fired payload's match lists are sorted by before the 100-row cap is applied, so a truncated list is the deterministic top 100 rather than an arbitrary sample. Must be a real signal (validated at creation)."}, 'signal': {'type': 'string', 'description': 'Signal name from the schema (case-insensitive).'}, 'ticker': {'type': 'string', 'description': 'Restrict to a single ticker. Default: any ticker.'}, 'cadence': {'enum': ['realtime', 'hourly', 'nyse_open'], 'type': 'string', 'description': '`realtime` (the default) is evaluated on every data refresh (~1×/min); `hourly` and `nyse_open` throttle to a batch schedule. `1m` is a deprecated alias for `realtime`.'}, 'channel': {'enum': ['webhook', 'discord', 'in_app', 'mobile_push'], 'type': 'string', 'description': 'Delivery channel. `webhook` (POST to `target_url`), `discord` (post an embed to `discord_url`), `in_app` (dashboard only), or `mobile_push` (notify a phone signed in to the Tickerbot mobile app; requires a `device_id` from `POST /v2/devices/register`). Inferred when omitted: `webhook` if `target_url` is set, `discord` if `discord_url` is set, else `in_app`. `slack` is reserved and returns `501`. See the Delivery channels guide.'}, 'columns': {'type': 'string', 'description': 'Comma-separated extra signals to include in each fired payload match row, beyond the standard set (`ticker`, `name`, `asset_type`, `price`, `change_1d_pct`, `market_cap`). Each must be a real signal; an unknown signal is rejected at creation. `fields` accepted as an alias — and note the RESPONSE reports them under `fields`, as an array.'}, 'universe': {'type': 'string', 'description': 'Restrict to a system or user-owned universe (e.g. `top_100`). `universe_id` accepted as an alias. Unknown universes are a 404 `universe_not_found`.'}, 'condition': {'type': 'string', 'description': 'Required for every non-boolean signal; the shape follows the signal\'s `type`. Numeric: `">70"`, `"<30"`, `">=100"`. Timestamp: `"<YYYY-MM-DDTHH:MM:SSZ"` (or a bare date). Date: `">=YYYY-MM-DD"`. String: `"=ETF"` or `"!=ETF"`. Sending one with a boolean or custom signal returns 400 (it does not apply).'}, 'device_id': {'type': 'string', 'description': 'Device to notify, from `POST /v2/devices/register`. Required when `channel` is `mobile_push`; unknown ids are a 404 `device_not_found`.'}, 'target_url': {'type': 'string', 'description': 'https:// URL to POST when fired. Omit for in-app delivery.'}, 'discord_url': {'type': 'string', 'description': 'Discord incoming-webhook URL (`https://discord.com/api/webhooks/…`). Required when `channel` is `discord`. Stored as a posting credential: the create response echoes it back under `channel_config`, but every later read (list, get, deliveries) strips it and sets `channel_config_present: true` instead.'}}}
Ausgabeschema
{'type': 'object', 'required': ['as_of', 'id', 'name', 'q', 'rule_id', 'fields', 'order', 'dir', 'universe_id', 'cadence', 'channel', 'target_url', 'delivery', 'status', 'source', 'subscription_origin', 'last_predicate_value', 'created_at', 'updated_at', 'last_fired', 'last_match_set', 'next_eval_at', 'last_evaluated_at', 'channel_config', 'signing_secret'], 'properties': {'q': {'type': 'string', 'description': 'The stored predicate. Custom signals appear expanded: the SQL is frozen at creation.'}, 'id': {'type': 'string', 'description': 'The webhook id — `wh_…`, the handle for every other call on this record.'}, 'dir': {'type': 'string', 'description': 'Sort direction for that list; `null` means the default (`desc`).'}, 'name': {'type': 'string', 'description': 'Your label for the subscription.'}, '_meta': {'type': 'object', 'description': 'Returned on create only, and only when the rule or `columns` named a column under its pre-2026-09-07 spelling: `deprecated_columns` lists each one (`requested`, `use`, `note`). The stored rule carries the current name.'}, 'as_of': {'type': 'string', 'description': 'Server time this response was assembled (ISO 8601).'}, 'order': {'type': 'string', 'description': 'Sort signal for the payload row list; `null` means the evaluator default (`market_cap`).'}, 'fields': {'type': 'string', 'description': 'Extra signals carried on each fired match row; `null` means the standard set.'}, 'source': {'type': 'string', 'description': 'Which API version created the record; `v2` for anything you create today.'}, 'status': {'type': 'string', 'description': '`active` or `disabled`. Auto-disable follows repeated delivery failure.'}, 'cadence': {'type': 'string', 'description': 'How often the trigger is evaluated — `realtime`, `hourly`, or `nyse_open`.'}, 'channel': {'type': 'string', 'description': 'Where deliveries go: `webhook`, `discord`, `in_app`, or `mobile_push`.'}, 'event_q': {'type': 'string', 'description': 'Event-trigger webhooks only: the payload filter, or `null`.'}, 'rule_id': {'type': 'string', 'description': 'Legacy link to a v1 alert rule; `null` on everything created through v2.'}, 'delivery': {'type': 'string', 'description': 'Legacy alias of `channel`, kept aligned for older readers.'}, 'test_url': {'type': 'string', 'description': 'Returned on create only: the `POST /v2/webhooks/{id}/test` URL for this record.'}, 'created_at': {'type': 'number', 'description': 'Creation timestamp.'}, 'last_error': {'type': 'string', 'description': 'The last evaluation error; `null` on a healthy hook. The answer to "why is my webhook not firing?".'}, 'last_fired': {'type': 'number', 'description': 'When a delivery last went out; `null` if it never has.'}, 'target_url': {'type': 'string', 'description': 'Your HTTPS endpoint; `null` on every channel except `webhook`.'}, 'updated_at': {'type': 'number', 'description': 'Last modification timestamp.'}, 'event_kinds': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Event-trigger webhooks only: the kinds subscribed (`split`, `dividend`, `insider`, `analyst`, `earnings`).'}, 'universe_id': {'type': 'string', 'description': 'Universe the trigger is scoped to, or `null` for the whole market.'}, 'next_eval_at': {'type': 'number', 'description': 'When the evaluator will next consider this subscription.'}, 'trigger_kind': {'type': 'string', 'description': 'Event-trigger webhooks only: `event`.'}, 'event_tickers': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Event-trigger webhooks only: the symbols the trigger is scoped to, or `null` for the universe / whole market.'}, 'channel_config': {'type': 'object', 'description': 'Returned on create only: the channel-specific delivery settings as stored (e.g. the Discord URL, the device id).'}, 'last_match_set': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Tickers matching at the last evaluation — the set the next run is diffed against, which is what makes firing edge-triggered.'}, 'signing_secret': {'type': 'string', 'description': 'Returned on create only — shown once, never again. HMAC key for verifying the `X-Tickerbot-Signature` header on deliveries.'}, 'last_evaluated_at': {'type': 'number', 'description': 'When it was last evaluated; `null` until the first run.'}, 'last_eval_error_at': {'type': 'number', 'description': 'When the last evaluation error happened; `null` on a healthy hook.'}, 'subscription_origin': {'type': 'object', 'description': 'Which door created it — `type` (`ticker`/`signal`/`scan`/`event`), its `ref`, and the `condition` in display form.'}, 'last_predicate_value': {'type': 'string', 'description': "The trigger's value at the last evaluation; `null` until it has run."}}, 'additionalProperties': False}
Eingabeschema
{'type': 'object', 'required': ['ticker', 'q'], 'properties': {'q': {'type': 'string', 'description': 'WHERE-clause fragment using signal names from the schema — the same grammar as /v2/scan. (`condition` accepted as an alias.)'}, 'dir': {'enum': ['asc', 'desc'], 'type': 'string', 'default': 'desc', 'description': 'Sort direction for `order`.'}, 'name': {'type': 'string', 'description': 'Human-readable label (up to 80 chars). Defaults to `<TICKER>: <query>`.'}, 'order': {'type': 'string', 'default': 'market_cap', 'description': "Signal the fired payload's match lists are sorted by before the 100-row cap is applied, so a truncated list is the deterministic top 100 rather than an arbitrary sample. Must be a real signal (validated at creation)."}, 'ticker': {'type': 'string', 'description': 'Case-insensitive. Equities are bare symbols (`AAPL`); every other class carries a prefix — rates (`R:SOFR`), crypto (`X:BTCUSD`), fx (`X:EURUSD`). Bare `BTC`/`ETH` are US-listed ETFs, not spot crypto. See Tickers.'}, 'cadence': {'enum': ['realtime', 'hourly', 'nyse_open'], 'type': 'string', 'description': 'How often to evaluate. `realtime` (the default) is evaluated on every data refresh (~1×/min); `hourly` and `nyse_open` throttle to a batch schedule. `1m` is a deprecated alias for `realtime`.'}, 'channel': {'enum': ['webhook', 'discord', 'in_app', 'mobile_push'], 'type': 'string', 'description': 'Delivery channel. `webhook` (POST to `target_url`), `discord` (post an embed to `discord_url`), `in_app` (dashboard only), or `mobile_push` (notify a phone signed in to the Tickerbot mobile app; requires a `device_id` from `POST /v2/devices/register`). Inferred when omitted: `webhook` if `target_url` is set, `discord` if `discord_url` is set, else `in_app`. `slack` is reserved and returns `501`. See the Delivery channels guide.'}, 'columns': {'type': 'string', 'description': 'Comma-separated extra signals to include in each fired payload match row, beyond the standard set (`ticker`, `name`, `asset_type`, `price`, `change_1d_pct`, `market_cap`). Each must be a real signal; an unknown signal is rejected at creation. `fields` accepted as an alias — and note the RESPONSE reports them under `fields`, as an array.'}, 'condition': {'type': 'string', 'description': 'Original name for `q` — accepted as well. The same WHERE-clause fragment; send either spelling.'}, 'device_id': {'type': 'string', 'description': 'Device to notify, from `POST /v2/devices/register`. Required when `channel` is `mobile_push`; unknown ids are a 404 `device_not_found`.'}, 'target_url': {'type': 'string', 'description': 'https:// URL to POST when the condition fires. Omit for in-app delivery (visible in the dashboard).'}, 'discord_url': {'type': 'string', 'description': 'Discord incoming-webhook URL (`https://discord.com/api/webhooks/…`). Required when `channel` is `discord`. Stored as a posting credential: the create response echoes it back under `channel_config`, but every later read (list, get, deliveries) strips it and sets `channel_config_present: true` instead.'}}}
Ausgabeschema
{'type': 'object', 'required': ['as_of', 'id', 'name', 'q', 'rule_id', 'fields', 'order', 'dir', 'universe_id', 'cadence', 'channel', 'target_url', 'delivery', 'status', 'source', 'subscription_origin', 'last_predicate_value', 'created_at', 'updated_at', 'last_fired', 'last_match_set', 'next_eval_at', 'last_evaluated_at', 'channel_config', 'signing_secret'], 'properties': {'q': {'type': 'string', 'description': 'The stored predicate. Custom signals appear expanded: the SQL is frozen at creation.'}, 'id': {'type': 'string', 'description': 'The webhook id — `wh_…`, the handle for every other call on this record.'}, 'dir': {'type': 'string', 'description': 'Sort direction for that list; `null` means the default (`desc`).'}, 'name': {'type': 'string', 'description': 'Your label for the subscription.'}, '_meta': {'type': 'object', 'description': 'Returned on create only, and only when the rule or `columns` named a column under its pre-2026-09-07 spelling: `deprecated_columns` lists each one (`requested`, `use`, `note`). The stored rule carries the current name.'}, 'as_of': {'type': 'string', 'description': 'Server time this response was assembled (ISO 8601).'}, 'order': {'type': 'string', 'description': 'Sort signal for the payload row list; `null` means the evaluator default (`market_cap`).'}, 'fields': {'type': 'string', 'description': 'Extra signals carried on each fired match row; `null` means the standard set.'}, 'source': {'type': 'string', 'description': 'Which API version created the record; `v2` for anything you create today.'}, 'status': {'type': 'string', 'description': '`active` or `disabled`. Auto-disable follows repeated delivery failure.'}, 'cadence': {'type': 'string', 'description': 'How often the trigger is evaluated — `realtime`, `hourly`, or `nyse_open`.'}, 'channel': {'type': 'string', 'description': 'Where deliveries go: `webhook`, `discord`, `in_app`, or `mobile_push`.'}, 'event_q': {'type': 'string', 'description': 'Event-trigger webhooks only: the payload filter, or `null`.'}, 'rule_id': {'type': 'string', 'description': 'Legacy link to a v1 alert rule; `null` on everything created through v2.'}, 'delivery': {'type': 'string', 'description': 'Legacy alias of `channel`, kept aligned for older readers.'}, 'test_url': {'type': 'string', 'description': 'Returned on create only: the `POST /v2/webhooks/{id}/test` URL for this record.'}, 'created_at': {'type': 'number', 'description': 'Creation timestamp.'}, 'last_error': {'type': 'string', 'description': 'The last evaluation error; `null` on a healthy hook. The answer to "why is my webhook not firing?".'}, 'last_fired': {'type': 'number', 'description': 'When a delivery last went out; `null` if it never has.'}, 'target_url': {'type': 'string', 'description': 'Your HTTPS endpoint; `null` on every channel except `webhook`.'}, 'updated_at': {'type': 'number', 'description': 'Last modification timestamp.'}, 'event_kinds': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Event-trigger webhooks only: the kinds subscribed (`split`, `dividend`, `insider`, `analyst`, `earnings`).'}, 'universe_id': {'type': 'string', 'description': 'Universe the trigger is scoped to, or `null` for the whole market.'}, 'next_eval_at': {'type': 'number', 'description': 'When the evaluator will next consider this subscription.'}, 'trigger_kind': {'type': 'string', 'description': 'Event-trigger webhooks only: `event`.'}, 'event_tickers': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Event-trigger webhooks only: the symbols the trigger is scoped to, or `null` for the universe / whole market.'}, 'channel_config': {'type': 'object', 'description': 'Returned on create only: the channel-specific delivery settings as stored (e.g. the Discord URL, the device id).'}, 'last_match_set': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Tickers matching at the last evaluation — the set the next run is diffed against, which is what makes firing edge-triggered.'}, 'signing_secret': {'type': 'string', 'description': 'Returned on create only — shown once, never again. HMAC key for verifying the `X-Tickerbot-Signature` header on deliveries.'}, 'last_evaluated_at': {'type': 'number', 'description': 'When it was last evaluated; `null` until the first run.'}, 'last_eval_error_at': {'type': 'number', 'description': 'When the last evaluation error happened; `null` on a healthy hook.'}, 'subscription_origin': {'type': 'object', 'description': 'Which door created it — `type` (`ticker`/`signal`/`scan`/`event`), its `ref`, and the `condition` in display form.'}, 'last_predicate_value': {'type': 'string', 'description': "The trigger's value at the last evaluation; `null` until it has run."}}, 'additionalProperties': False}
Eingabeschema
{'type': 'object', 'required': ['id'], 'properties': {'id': {'type': 'string', 'description': 'Webhook id.'}}}
Ausgabeschema
{'type': 'object', 'required': ['as_of', 'id', 'webhook_id', 'test', 'delivered', 'http_status', 'elapsed_ms', 'error', 'status', 'created_at'], 'properties': {'id': {'type': 'string', 'description': 'Delivery id of the test — `dl_…`, the same shape as a real delivery on the deliveries route.'}, 'test': {'type': 'boolean', 'description': '`true` — this delivery was a synthetic ping, not a trigger firing.'}, 'as_of': {'type': 'string', 'description': 'Server time this response was assembled (ISO 8601).'}, 'error': {'type': 'string', 'description': 'Why delivery failed, in words; `null` on success.'}, 'status': {'type': 'string', 'description': "The delivery record's status: `delivered` or `permanent_failure` (a test is never retried)."}, 'delivered': {'type': 'boolean', 'description': 'Whether your endpoint accepted the ping (2xx within the timeout).'}, 'created_at': {'type': 'string', 'description': 'When the ping was sent (ISO 8601).'}, 'elapsed_ms': {'type': 'number', 'description': 'Round-trip time of the ping.'}, 'webhook_id': {'type': 'string', 'description': 'The webhook that was tested.'}, 'http_status': {'type': 'number', 'description': 'The status your endpoint returned; `null` when it could not be reached.'}}, 'additionalProperties': False}
Eingabeschema
{'type': 'object', 'required': ['signal'], 'properties': {'expr': {'type': 'string', 'description': 'New SQL expression. Re-validated and re-inlined against your other custom signals. Same strict grammar as create — no `LIKE`/`ILIKE`, `CASE`, `::` casts, or functions beyond `abs`/`coalesce`/`round`/`least`/`greatest`. The response echoes your expression as stored, not its expansion (a pre-2026-09-07 column spelling is stored under its current name and reported in `_meta.deprecated_columns`).'}, 'signal': {'type': 'string', 'description': 'Custom signal slug (the signal name). A built-in name answers 404 — built-ins are read-only.'}, 'new_name': {'type': 'string', 'description': 'New slug — renames the signal and changes its API handle everywhere (same validation as create). Refused while other custom signals reference the current name. `name` is accepted as an alias (new_name wins when both are sent), but new_name is the unambiguous spelling since the URL already carries the current name.'}, 'description': {'type': 'string', 'description': 'New description. Not derived from `expr` — change both if the prose describes a threshold you are moving.'}}}
Ausgabeschema
{'type': 'object', 'required': ['as_of', 'signal'], 'properties': {'_meta': {'type': 'object', 'description': 'Only when `expr` named a column under its pre-2026-09-07 spelling: `deprecated_columns` lists each one (`requested`, `use`, `note`). The stored `expr` carries the current name.'}, 'as_of': {'type': 'string', 'description': 'Server time this response was assembled (ISO 8601).'}, 'signal': {'type': 'object', 'description': 'The stored signal: `name`, `kind` (`custom`), `description`, `expr` (your predicate as stored), `created_at`, `updated_at`.'}}, 'additionalProperties': False}
Eingabeschema
{'type': 'object', 'required': ['id'], 'properties': {'id': {'type': 'string', 'description': 'Universe slug.'}, 'add': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Add these tickers (deduplicated).'}, 'name': {'type': 'string', 'description': 'New label. Non-empty, max 80 characters.'}, 'remove': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Remove these tickers.'}, 'tickers': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Replace the full ticker list (up to 10,000; validated against the active universe). Does not combine with `add`/`remove` (400).'}, 'description': {'type': 'string', 'description': 'New notes. Max 500 characters.'}}}
Ausgabeschema
{'type': 'object', 'required': ['as_of', 'id', 'name', 'description', 'tickers', 'size', 'system', 'created_at', 'updated_at'], 'properties': {'id': {'type': 'string', 'description': "The slug — the universe's handle in `?universe=`."}, 'name': {'type': 'string', 'description': 'Display label.'}, 'size': {'type': 'number', 'description': 'Member count.'}, 'as_of': {'type': 'string', 'description': 'Server time this response was assembled (ISO 8601).'}, 'system': {'type': 'boolean', 'description': '`false` — this is your universe.'}, 'tickers': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Members, after this call.'}, 'created_at': {'type': 'number', 'description': 'Creation timestamp.'}, 'updated_at': {'type': 'number', 'description': 'Last modification timestamp.'}, 'description': {'type': 'string', 'description': 'Free-form notes; `""` when unset.'}, 'effective_at': {'type': 'number', 'description': 'System universes only; absent on yours.'}, 'rebalance_method': {'type': 'string', 'description': 'System universes only; absent on yours.'}, 'next_rebalance_at': {'type': 'number', 'description': 'System universes only; absent on yours.'}}, 'additionalProperties': False}
Eingabeschema
{'type': 'object', 'required': ['id'], 'properties': {'id': {'type': 'string', 'description': 'Webhook id.'}, 'name': {'type': 'string', 'description': 'New display name. Non-empty, max 80 characters.'}, 'cadence': {'enum': ['realtime', 'hourly', 'nyse_open'], 'type': 'string', 'description': 'Evaluation cadence. A user preference — never gated. Event triggers deliver on ingest — only `realtime` is accepted on them (400 otherwise).'}, 'enabled': {'type': 'boolean', 'description': '`false` disables the webhook (status → `disabled`). `true` is a no-op unless disabled, in which case use `POST /v2/webhooks/{id}/enable` instead.'}, 'target_url': {'type': 'string', 'description': "New https:// delivery URL (webhook channel only — a Discord/mobile subscription 400s here). `null` or empty switches to in-app delivery; `status` is untouched — a disabled webhook stays disabled until `POST /v2/webhooks/{id}/enable` (the only path that re-checks your account's webhook cap)."}}}
Ausgabeschema
{'type': 'object', 'required': ['as_of', 'id', 'name', 'q', 'rule_id', 'fields', 'order', 'dir', 'universe_id', 'cadence', 'channel', 'target_url', 'delivery', 'status', 'source', 'subscription_origin', 'last_predicate_value', 'created_at', 'updated_at', 'last_fired', 'last_match_set', 'next_eval_at', 'last_evaluated_at'], 'properties': {'q': {'type': 'string', 'description': 'The stored predicate. Custom signals appear expanded: the SQL is frozen at creation.'}, 'id': {'type': 'string', 'description': 'The webhook id — `wh_…`, the handle for every other call on this record.'}, 'dir': {'type': 'string', 'description': 'Sort direction for that list; `null` means the default (`desc`).'}, 'name': {'type': 'string', 'description': 'Your label for the subscription.'}, 'as_of': {'type': 'string', 'description': 'Server time this response was assembled (ISO 8601).'}, 'order': {'type': 'string', 'description': 'Sort signal for the payload row list; `null` means the evaluator default (`market_cap`).'}, 'fields': {'type': 'string', 'description': 'Extra signals carried on each fired match row; `null` means the standard set.'}, 'source': {'type': 'string', 'description': 'Which API version created the record; `v2` for anything you create today.'}, 'status': {'type': 'string', 'description': '`active` or `disabled`. Auto-disable follows repeated delivery failure.'}, 'cadence': {'type': 'string', 'description': 'How often the trigger is evaluated — `realtime`, `hourly`, or `nyse_open`.'}, 'channel': {'type': 'string', 'description': 'Where deliveries go: `webhook`, `discord`, `in_app`, or `mobile_push`.'}, 'event_q': {'type': 'string', 'description': 'Event-trigger webhooks only: the payload filter, or `null`.'}, 'rule_id': {'type': 'string', 'description': 'Legacy link to a v1 alert rule; `null` on everything created through v2.'}, 'delivery': {'type': 'string', 'description': 'Legacy alias of `channel`, kept aligned for older readers.'}, 'created_at': {'type': 'number', 'description': 'Creation timestamp.'}, 'last_error': {'type': 'string', 'description': 'The last evaluation error; `null` on a healthy hook. The answer to "why is my webhook not firing?".'}, 'last_fired': {'type': 'number', 'description': 'When a delivery last went out; `null` if it never has.'}, 'target_url': {'type': 'string', 'description': 'Your HTTPS endpoint; `null` on every channel except `webhook`.'}, 'updated_at': {'type': 'number', 'description': 'Last modification timestamp.'}, 'event_kinds': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Event-trigger webhooks only: the kinds subscribed (`split`, `dividend`, `insider`, `analyst`, `earnings`).'}, 'universe_id': {'type': 'string', 'description': 'Universe the trigger is scoped to, or `null` for the whole market.'}, 'next_eval_at': {'type': 'number', 'description': 'When the evaluator will next consider this subscription.'}, 'trigger_kind': {'type': 'string', 'description': 'Event-trigger webhooks only: `event`.'}, 'event_tickers': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Event-trigger webhooks only: the symbols the trigger is scoped to, or `null` for the universe / whole market.'}, 'last_match_set': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Tickers matching at the last evaluation — the set the next run is diffed against, which is what makes firing edge-triggered.'}, 'last_evaluated_at': {'type': 'number', 'description': 'When it was last evaluated; `null` until the first run.'}, 'last_eval_error_at': {'type': 'number', 'description': 'When the last evaluation error happened; `null` on a healthy hook.'}, 'subscription_origin': {'type': 'object', 'description': 'Which door created it — `type` (`ticker`/`signal`/`scan`/`event`), its `ref`, and the `condition` in display form.'}, 'last_predicate_value': {'type': 'string', 'description': "The trigger's value at the last evaluation; `null` until it has run."}}, 'additionalProperties': False}
Letzte Tool-Änderungen
Ähnliche MCP-Server
AlpineDataWorks Intelligence Server
Provides economic, market, supply-chain, real-estate, energy, consumer, labor, and other scored intelligence indices with histori…
Stratalize Finance
Provides financial, macroeconomic, banking, credit, commodities, M&A, ESG, labor, and regulatory benchmarks for analysis and plan…
Valuein — SEC EDGAR Fundamentals & Smart-Money Data
Provides point-in-time SEC EDGAR fundamentals, filings, ownership signals, financial analysis, valuation models, research reports…
equibles
Provides equity and market research tools covering SEC filings, company financials, portfolios, prices, options, macroeconomic da…
DFX Real Estate Intelligence
Provides US commercial real estate, parcel, debt maturity, bank CRE exposure, private capital, investor, ownership, occupancy, an…
simplefunctions
Provides prediction-market data, thesis analysis, market signals, portfolio tracking, and automated intent-based trading workflow…
EventTrader MCP
Provides prediction-market research and trading capabilities, including real-time event-market data, CLOB execution paths, fund i…
Signal8
Provides SEC filings, dilution data, insider and institutional ownership, and political-trade data.