# Overview (/docs/listening/overview) What a listener is, what you can call today, which release brings the rest, and the names a listener does not take A listener watches keywords or a boolean topic on the platforms you choose, on a schedule you set, and will deliver each new mention it finds. Listeners ship in LRel2a. Today you can price and validate one: `POST /v1/listening/streams?dry_run=1` takes the same body a create will take, answers with the monthly cost in credits and money, costs 0 credits and creates nothing. ```bash title="cURL" curl -X POST "https://www.socialcrawl.dev/v1/listening/streams?dry_run=1" \ -H "x-api-key: YOUR_API_KEY" -H "Content-Type: application/json" \ -d '{"keywords": ["Acme", "Acme Cloud"], "platforms": ["reddit"], "schedule": {"every": "1h", "name": "Acme brand"}}' ``` The answer holds the listener as it would be stored, each group's rule as a tree and in words (`read_back`), the estimate at `data.estimate`, the per-lane plan at `data.plan`, the use screen's verdict at `data.screen`, `warnings` and `next_step`. The [quickstart](/docs/listening/quickstart.md) walks through a full answer, and [pricing](/docs/listening/pricing.md) shows how the estimate is computed. ## What is a listener? A listener holds one or more groups, each a boolean `rule` or plain `keywords`, with an optional `context` that says which sense of an ambiguous keyword you mean. It also holds the platforms to watch and a required `schedule`: ```json title="JSON" { "groups": [ { "id": "outage", "rule": "\"Globex Mobile\" AND (outage OR down OR \"no signal\")" }, { "id": "pricing", "rule": "(\"Globex Mobile\" OR \"Globex Prepaid\") AND (price OR bill OR tariff)" } ], "platforms": ["youtube", "reddit"], "context": "Globex Mobile, the mobile network operator, and its Globex Prepaid plans. Not Globex Corporation or any other company named Globex.", "schedule": { "every": "1h", "max_credits_per_month": 15000, "name": "Client B: Globex Mobile" } } ``` Top-level `keywords` or `rule` is the shorthand for one group. Send exactly one of `keywords`, `rule` and `groups`. `schedule.every` is one of `30m`, `1h`, `3h`, `6h`, `1d` and `7d`, and `30m` works only when every chosen platform is read newest first ([lanes](/docs/listening/lanes.md)). `schedule.max_credits_per_month` is a cap in credits, never money. The names are discover's wherever the meaning is the same, so a body you send to a [discover schedule](/docs/prism/discover.md#schedules) reads the same way here. ## What ships when Every route below is mounted today. A route of a later release answers a 400 `not_released` with `details.release` naming the release that brings it, and charges nothing. On the create route, `next_step` points at the dry run. | Route | What it does | Release | | --- | --- | --- | | `POST /v1/listening/streams?dry_run=1` | Price and validate a listener; creates nothing | LRel1, available now | | `POST /v1/listening/streams` | Create a listener | LRel2a | | `GET /v1/listening/streams` | List your listeners | LRel2a | | `GET /v1/listening/streams/{id}` | Read one listener | LRel2a | | `PATCH /v1/listening/streams/{id}` | Change a listener | LRel2a | | `POST /v1/listening/streams/{id}/pause` | Pause a listener | LRel2a | | `POST /v1/listening/streams/{id}/resume` | Resume a listener | LRel2a | | `DELETE /v1/listening/streams/{id}` | Delete a listener | LRel2a | | `GET /v1/listening/streams/{id}/mentions` | Read a listener's mentions | LRel2a | | `GET /v1/listening/streams/{id}/runs` | Read a listener's checks | LRel2a | | `POST /v1/listening/preview` | Run a listener body once over the last 24 hours | LRel2b | | `GET /v1/listening/usage` | Credits and checks per client, listener or platform | LRel2b | There is no estimate route: `POST /v1/listening/estimate` answers 404 with `did_you_mean` naming the dry run. LRel2a also adds the listener events to the [events feed](/docs/events.md) and [webhook endpoints](/docs/webhook-endpoints.md). Comments under matching posts arrive in LRel3, and panels of accounts filtered by a topic in LRel4. ## Which call fits the job? Until listeners ship, a recurring watch on a topic is a [discover schedule](/docs/prism/discover.md#schedules), and the new posts of an account you already know are a Monitor with `webhook_rows: "new"`. The dry run answers what a keyword or boolean topic listener would cost. [Choosing endpoints](/docs/choosing-endpoints.md#watch) holds the one routing rule for every standing watch. ## Names a listener does not take These names answer a 400 `not_offered`, with `docs_url` pointing at this page and, where one exists, `did_you_mean`. Nothing is charged. | Name sent | Send instead | | --- | --- | | `query` | `rule`: a listener's boolean text. Discover's `query` is one phrase sent as written. | | `rules` | `groups`, each with an `id` and a `rule` or `keywords` | | `refresh_interval_minutes` | `schedule.every` | | `budget` | `schedule.max_credits_per_month`: divide a money budget by `money_per_credit` ([pricing](/docs/listening/pricing.md)) | | `match_in` | Nothing: a listener matches a post's title and text together | | `delivery.endpoint_ids` | `subject_ids` on a [webhook endpoint](/docs/webhook-endpoints.md) | | `stream_id` | `subject_id` on the events feed and webhook endpoints | | `stream_ids` | `subject_ids` on the events feed and webhook endpoints | | `threads` | Nothing: new comments of a known post are a Monitor with `webhook_rows: "new"` | Some names belong to a later release and answer `not_released` naming it instead: `accounts` and `schedule.purpose` (LRel4), comments under matching posts (LRel3), `label` and `questions` (once their accuracy gate passes), `sentiment` (with `label=stance`) and `tz` (local-time schedules; a listener's slots and months are UTC). ## Errors Each refusal is free and carries `details.reason`, `details.fields` and `details.next_step`. Change the field it names rather than retrying. | `details.reason` | Status | What to do | Reference | | --- | --- | --- | --- | | `invalid_param` | 400 | Send the field or value in `did_you_mean`, `allowed_values` or `suggested_value` | [INVALID_REQUEST](/docs/errors.md#invalid-request) | | `conflicting_params` | 400 | Drop one of the fields in `details.fields` | [INVALID_REQUEST](/docs/errors.md#invalid-request) | | `not_released` | 400 | Drop the field, value or route, or wait for `details.release` | [INVALID_REQUEST](/docs/errors.md#invalid-request) | | `not_offered` | 400 | Send the name in `did_you_mean`, or drop it (table above) | [INVALID_REQUEST](/docs/errors.md#invalid-request) | | `interval_below_lane_minimum` | 400 | Pick an `every` from `allowed_values`, or drop the platform whose lane `details.lane` names | [INVALID_REQUEST](/docs/errors.md#invalid-request) | | `unsupported_operator` | 400 | Use the rule in `nearest` | [INVALID_REQUEST](/docs/errors.md#invalid-request) | | `plan_limit` | 400 | Send fewer groups or search terms, within `limit` | [INVALID_REQUEST](/docs/errors.md#invalid-request) | | `budget_below_one_check` | 400 | Ask the user to approve `suggested_value`, then send it in `field` | [INVALID_REQUEST](/docs/errors.md#invalid-request) | | `prohibited_use` | 400 | Do not rephrase to pass. A dry run reports the verdict in `data.screen` instead; a create refuses it from LRel2a | [INVALID_REQUEST](/docs/errors.md#invalid-request) | | `judge_unavailable` | 503 | Retry after `Retry-After`. A dry run never answers it: when the use screen cannot run, `data.screen.result` is `unavailable` | [SERVICE_UNAVAILABLE](/docs/errors.md#service-unavailable) | The use screen checks what you declare in each group's `rule` or `keywords` and in `context` against the uses the Terms of Service section 7.2 forbid: monitoring a named private individual, a protest group or its organisers, or government or intelligence monitoring of people. On a dry run it returns its verdict in `data.screen` with a warning and creates nothing either way. A create or a change that declares such a use is refused with `prohibited_use` from LRel2a, and a preview from LRel2b. - [Quickstart](/docs/listening/quickstart.md): Send a dry run and read the answer - [Pricing](/docs/listening/pricing.md): How the estimate and the cap are computed - [Lanes](/docs/listening/lanes.md): Platforms, order and the release that fetches each