← tickerbot.io
View as markdown

Subscribe to events

POSThttps://api.tickerbot.io/v2/events/subscribe

Push new events: we POST your endpoint when events of the kinds you chose land in the archives.

enum[]required

Event kinds to fire on — array or comma list.

earningsQuarterly earnings reports — reported vs estimated EPS and the surprise, timestamped at the report date.
dividendCash-dividend declarations, timestamped at the ex-dividend date.
splitStock splits and reverse splits, timestamped at the execution date.
insiderOfficer and director trades — one event per reported Form 4 transaction.
analystUpgrades, downgrades, initiations, and price-target changes. Lands within the hour, 24/7.
string[]

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.

string

Single-symbol shorthand for tickers.

string

Scope to a universe slug (top_10, top_100, or one of yours). universe_id accepted as an alias.

string

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. See the signals catalog for columns + flags you can compose.

string

Optional event-CONTENT filter in the /v2/events grammar — only ticker, ts, kind, payload may appear. Composes with q.

string

HTTPS delivery URL; or use channel + discord_url/device_id. Omit for in-app.

enum

Delivery channel. slack is reserved and returns 501.

webhookPOST the payload to an HTTPS endpoint you own, signed with X-Tickerbot-Signature.
in_appDeliver to the in-app feed. No external receiver, so nothing to validate and no test_url.
discordPost to a Discord channel via its webhook URL. Delivered as a Discord embed, never HMAC-signed — the URL is itself the credential.
mobile_pushPush to a registered device. Requires a device_id from Register a device.
string

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.

string

Device to notify, from POST /v2/devices/register. Required when channel is mobile_push; unknown ids are a 404 device_not_found.

string

Display name. Defaults to events: <kinds> · <scope>.

string

Optional unique string (≤255 chars). A retry carrying the same key within 24h replays the original response (Idempotency-Replayed: true header) instead of creating a duplicate; a concurrent duplicate gets 409 idempotency_in_flight; reusing a key for a *different* request (another method or path) gets 422 idempotency_key_reused. 5xx responses are not stored — those retries re-execute.

as_ofstring

Server time this response was assembled (ISO 8601).

idstring

The webhook id — `wh_…`, the handle for every other call on this record.

namestring

Your label for the subscription.

qstring

The stored predicate. Custom signals appear expanded: the SQL is frozen at creation.

rule_idstring

Legacy link to a v1 alert rule; `null` on everything created through v2.

fieldsstring

Extra signals carried on each fired match row; `null` means the standard set.

orderstring

Sort signal for the payload row list; `null` means the evaluator default (`market_cap`).

dirstring

Sort direction for that list; `null` means the default (`desc`).

universe_idstring

Universe the trigger is scoped to, or `null` for the whole market.

cadencestring

How often the trigger is evaluated — `realtime`, `hourly`, or `nyse_open`.

channelstring

Where deliveries go: `webhook`, `discord`, `in_app`, or `mobile_push`.

target_urlstring

Your HTTPS endpoint; `null` on every channel except `webhook`.

deliverystring

Legacy alias of `channel`, kept aligned for older readers.

statusstring

`active` or `disabled`. Auto-disable follows repeated delivery failure.

sourcestring

Which API version created the record; `v2` for anything you create today.

subscription_originobject

Which door created it — `type` (`ticker`/`signal`/`scan`/`event`), its `ref`, and the `condition` in display form.

last_predicate_valuestring

The trigger's value at the last evaluation; `null` until it has run.

created_atnumber

Creation timestamp.

updated_atnumber

Last modification timestamp.

last_firednumber

When a delivery last went out; `null` if it never has.

last_match_setarray

Tickers matching at the last evaluation — the set the next run is diffed against, which is what makes firing edge-triggered.

last_eval_error_atnumber

When the last evaluation error happened; `null` on a healthy hook.

last_errorstring

The last evaluation error; `null` on a healthy hook. The answer to "why is my webhook not firing?".

next_eval_atnumber

When the evaluator will next consider this subscription.

last_evaluated_atnumber

When it was last evaluated; `null` until the first run.

event_kindsarray

Event-trigger webhooks only: the kinds subscribed (`split`, `dividend`, `insider`, `analyst`, `earnings`).

event_qstring

Event-trigger webhooks only: the payload filter, or `null`.

event_tickersarray

Event-trigger webhooks only: the symbols the trigger is scoped to, or `null` for the universe / whole market.

trigger_kindstring

Event-trigger webhooks only: `event`.

channel_configobject

Returned on create only: the channel-specific delivery settings as stored (e.g. the Discord URL, the device id).

signing_secretstring

Returned on create only — shown once, never again. HMAC key for verifying the `X-Tickerbot-Signature` header on deliveries.

test_urlstring

Returned on create only: the `POST /v2/webhooks/{id}/test` URL for this record.

_metaobject

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.

201
The created webhook record + test_url.
400
bad_request — missing/unknown kinds, >50 tickers, tickers+universe together, or invalid q. Also: cadence, order, dir, and columns are not parameters here — event deliveries are ingest-driven and carry the event payload, not ranked state rows, so sending one is a 400 (unknown_parameter), never silently ignored.
403
webhook_tier_required (Free) or webhook_limit_reached (at cap) — event webhooks consume the same plan slots.
404
Referenced universe does not exist (universe_not_found), or unknown device_id (device_not_found).
409
idempotency_in_flight — a concurrent request carried the same Idempotency-Key.
422
idempotency_key_reused — the Idempotency-Key was already used for a different request.
501
channel_not_implemented — channel: "slack" is reserved.
  • Sugar for POST /v2/webhooks with trigger: { type: "event", … } — the webhook is listed, updated, and deleted at /v2/webhooks like any other. No polling on your side: "every split in my universe", "Goldman downgrades on tickers I hold".
  • Two optional, composable filters, answering different questions about different objects. `q` filters the event's TICKER STATE at fire time — "downgrades, but only where market_cap > 1e10" — in scan grammar, with custom signals expanded and frozen at creation. `event_q` filters the EVENT CONTENT — "only where payload->>'firm' = 'Goldman Sachs'" — in the /v2/events grammar over exactly (ticker, ts, kind, payload).
  • Latency is ingest cadence, not sub-minute. Analyst actions land within an hour (the archive refreshes hourly, 24/7); earnings, dividend, split, and insider kinds refresh daily in the evening ET pipeline. Only genuinely new events fire — historical backfills never do.
  • Delivery payloads use event: "events.fired" (not webhook.fired) with an events array of { ticker, ts, kind, payload } rows, the same shapes GET /v2/events serves — receivers handling both webhook types should branch on the event field.