# POST /v2/events/subscribe

**Subscribe to events**

Creates an event-trigger webhook: it fires when NEW events of the chosen kinds land in the archives — "every split in my universe", "Goldman downgrades on tickers I hold" — with no polling on your side. Sugar for [`POST /v2/webhooks`](/docs/endpoints/webhooks/create) with `trigger: { type: "event", … }`; the webhook is listed/updated/deleted at `/v2/webhooks` like any other.

Two optional, composable filters — they answer different questions about different objects:

- **`q` filters the event's TICKER STATE** at fire time — `"downgrades, but only where market_cap > 1e10"`. Scan grammar; custom signals expand and freeze at creation.
- **`event_q` filters the EVENT CONTENT** — `"only where payload->>'firm' = 'Goldman Sachs'"`. The [`GET /v2/events`](/docs/endpoints/events) grammar over exactly `(ticker, ts, kind, payload)`.

Deliveries carry `event: "events.fired"` with an `events` array of `{ ticker, ts, kind, payload }` rows (same shapes as [`GET /v2/events`](/docs/endpoints/events)).

**Latency is ingest cadence, not sub-minute**: analyst actions ≤1 hour (the archive refreshes hourly, 24/7); dividend/split/insider kinds refresh daily in the evening ET pipeline. Only genuinely new events fire — historical backfills never do.

## Plan access

- **Plan access.** Paid plans (Hobby and above).
- **Cadence.** Real-time on every paid plan — evaluated on every data refresh (~1×/min), so a match is delivered within seconds of it landing. Optionally throttle a webhook to hourly or at-market-open.
- **Capacity.** Hobby 10 · Pro 100 · Scale 1,000 · Enterprise unlimited.

## Body parameters

| Name | In | Type | Required | Description |
|------|----|----|----------|-------------|
| `kinds` | body | string | yes | Event kinds to fire on — array or comma list. Enum: `dividend`, `split`, `insider`, `analyst`. Example: `split,analyst`. |
| `tickers` | body | string | no | Scope to specific tickers (max 50). Mutually exclusive with `universe`. Omit both for all tickers. Example: `AAPL,NVDA`. |
| `universe` | body | string | no | Scope to a universe slug (`top_10`, `top_100`, or one of yours). |
| `q` | body | string | no | 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. Example: `market_cap > 1e10`. |
| `event_q` | body | string | no | Optional event-CONTENT filter in the `/v2/events` grammar — only `ticker`, `ts`, `kind`, `payload` may appear. Composes with `q`. Example: `payload->>'firm' = 'Goldman Sachs'`. |
| `target_url` | body | string | no | HTTPS delivery URL; or use `channel` + `discord_url`/`device_id`. Omit for in-app. |
| `channel` | body | string | no | Delivery channel. Enum: `webhook`, `in_app`, `discord`, `mobile_push`. |
| `name` | body | string | no | Display name. Defaults to `events: <kinds> · <scope>`. |

## Status codes

- **201** — The created webhook record + `test_url`.
- **400** — `bad_request` — missing/unknown `kinds`, >50 tickers, `tickers`+`universe` together, or invalid `q`.
- **403** — `webhook_tier_required` (Free) or `webhook_limit_reached` (at cap) — event webhooks consume the same plan slots.
- **404** — Referenced `universe` does not exist.

## Sample response

```json
{
  "as_of": "2026-07-27T16:40:00.000Z",
  "id": "wh_e9Kp3q-r52s",
  "name": "events: analyst · top_100",
  "q": "market_cap > 1e10",
  "trigger_kind": "event",
  "event_kinds": ["analyst"],
  "universe_id": "top_100",
  "channel": "discord",
  "status": "active",
  "subscription_origin": { "type": "event", "ref": "analyst", "condition": "market_cap > 1e10" },
  "test_url": "/v2/webhooks/wh_e9Kp3q-r52s/test",
  "created_at": 1785170400
}
```

## Examples

### Downgrades on large caps in the top 100 → Discord

Request:

```shell
curl -X POST "https://api.tickerbot.io/v2/events/subscribe" \
  -H "Authorization: Bearer YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"kinds":"analyst","universe":"top_100","q":"market_cap > 1e10","channel":"discord","discord_url":"https://discord.com/api/webhooks/123…"}'
```

Response (`201`):

```json
{
  "as_of": "2026-07-27T16:40:00.000Z",
  "id": "wh_e9Kp3q-r52s",
  "name": "events: analyst · top_100",
  "q": "market_cap > 1e10",
  "trigger_kind": "event",
  "event_kinds": ["analyst"],
  "universe_id": "top_100",
  "channel": "discord",
  "status": "active",
  "subscription_origin": { "type": "event", "ref": "analyst", "condition": "market_cap > 1e10" },
  "test_url": "/v2/webhooks/wh_e9Kp3q-r52s/test",
  "created_at": 1785170400
}
```

## Notes

- Delivery payloads use `event: "events.fired"` (not `webhook.fired`) with an `events` array — receivers handling both webhook types should branch on the `event` field.

---

Interactive sandbox + parameter editor: https://tickerbot.io/docs/endpoints/events/subscribe
