---
title: Search Streams in depth
category: find
summary: Every way to search the Stream inventory, what each parameter does, how results are ranked and labelled, and the query patterns that answer real user questions.
order: 4
updated: 2026-10-07
next: stream-schema-and-filters
related: choose-a-stream, stream-schema-and-filters
reference: /docs/mcp, /openapi.json
---

Stream search is how an agent learns what Synorb covers. It is free, it is keyless for discovery, and it is the step that decides whether everything after it can succeed. Do it well and your pulls are small, cheap and sharp. Do it badly and you pull the wrong thing confidently.

## When to use this

Use search whenever your user asks what exists: "do you have Bloomberg?", "what business podcasts can you read?", "which Streams cover semiconductors?", "show me every central bank". Search finds **Streams**. It never returns content. To read content, scope a pull with the IDs search gives you.

Pick the discovery tool that fits the question:

| Tool | Best for | Notes |
| --- | --- | --- |
| `synorb-stream-search` (MCP) | A user's natural-language ask: a source name, a topic, a format | Ranked, handles typos and synonyms, free |
| `POST /streams/search` (REST) | The same ranked search from backend code | Same engine, REST parameters |
| `synorb-catalog` (MCP) | Browsing by facets and pages | Returns match reasons, volume indicators and facets |
| `GET /streams` (REST) | Exact, filterable catalog listing | Exact filters only. There is **no** free-text `search=` here |

## Smallest working call

```mcp
synorb-stream-search
{"query": "do you have Bloomberg?", "page_size": 5}
```

```bash
curl -sS -X POST https://api.synorb.com/streams/search \
  -H "Authorization: Bearer $SYNORB_KEY" \
  -H "Content-Type: application/json" \
  -d '{"query": "do you have Bloomberg?", "page_size": 5}'
```

### Parameters of `synorb-stream-search`

| Parameter | What it does |
| --- | --- |
| `query` | Free-text intent. Typos and synonyms are handled. |
| `home_domain`, `home_domains` | Restrict to one or more of the 12 canonical domains. `["all"]` or omitted means full scope. |
| `cross_domains`, `cross_domain_logic` | Up to three secondary domains, combined with `or` (broader) or `and` (intersection). |
| `media_format` | `audio`, `video`, `social`, `text`, `data` or `regulatory`. Synonyms such as "podcasts" map to `audio`. |
| `company_kind` | `public` or `private`. Synorb derives it from organization Tags. |
| `organization_subtype` | An exact organization subtype, for example `public_company` or `private_company`. Must not be blank. |
| `ticker`, `isin` | Exact, case-insensitive. The reliable path for tickers that free text drops, such as `ON`, `IT` or `ALL`. |
| `surface` | A canonical Surface id such as `public_companies`. Synorb returns only Streams whose curated Surfaces include it. An unknown value returns an error listing the valid ids. |
| `page`, `page_size` | Zero-based page. `page_size` defaults to 10, and is silently capped at 200. |
| `include_details` | Adds a short description of each source channel so you can start a pull at once. |
| `verbosity` | `minimal` (default), `standard` (adds workflow scaffolding) or `verbose`. |
| `inventory_scope` | Only `live_public_active_mcp` is honored today. Leave it alone. |

`POST /streams/search` also accepts `surface`, although `openapi.json` does not list it yet. `GET /streams?surface=...` lists it in the schema.

A request that clearly means "all of them", such as "all podcast Streams", raises the page size to 200. If the full set fits, one page returns all of it.

## What you get back

```json response
{
  "counts": {},
  "results": [
    {
      "id": "...",
      "name": "...",
      "description": "...",
      "home_domain": "economics-business-work",
      "media_formats": ["text"],
      "manifests_last7d": 41,
      "freshness_state": "fresh",
      "match_reasons": ["name match"]
    }
  ],
  "pagination": {"page_num": 0, "page_size": 5},
  "next_call": {}
}
```

- **`id`** is a 17-digit identifier. Keep it a string.
- **`match_reasons`** tells you why a row matched. Use it to avoid presenting a loose match as an exact one.
- **`freshness_state`** is `fresh`, `quiet`, `stale`, `never_published` or `unknown`. A listed Stream is queryable. That does not mean it is publishing, so check this.
- **`manifests_last7d`** is a volume indicator. Use it to set expectations about how much a window will return.
- **`security`** carries `ticker`, `isin` and `figi` for company Streams.
- **`next_call`** is a ready-made suggestion for the next call, for example to look at tickers, source channels or filters.

Ranking favors exact identity, then multi-token relevance, then recent volume. It demotes a single generic-token match on an inactive Stream. Ranking leans on names and tokens, so lead with the source name, the company name or the ticker. Do not lead with a description. "Apple" or `AAPL` is a safer query than "the iPhone maker".

### Patterns that answer real questions

| Your user asks | Call |
| --- | --- |
| "Do you have Bloomberg?" | `query: "Bloomberg"`, then check `match_reasons` |
| "What business podcasts?" | `media_format: "audio"` plus `home_domains: ["economics-business-work"]` |
| "All central banks" | `surface: "central_banks"` |
| "Streams for NVDA" | `ticker: ["NVDA"]` |
| "Public companies in AI" | `company_kind: "public"` plus `query: "AI"` |
| "Sports podcasts" | The `home_domain` that covers sports, plus `media_format: "audio"` |

For "find podcasts", compose `media_format: "audio"` with a domain. A curated `podcasts` Surface also exists. It can include whole organizations that carry only one podcast source channel. This makes the set wider and sometimes off target.

## Failure modes

| Symptom | Cause | What to do |
| --- | --- | --- |
| Junk results for a broad word | Search is lexical, and broad words match loosely | Add `home_domain`, `media_format` or a ticker. Read `match_reasons`. |
| A Stream you expect is missing | It is not covered, is not live and public, or the index has not caught up yet | Say so. Search again after a while. Do not guess an ID. |
| `400 unsupported_filter_param` | You passed `search=` to `GET /streams` | Use `POST /streams/search`. |
| `422` on `media_format` or `home_domain` | A value outside the list, such as `podcast` | Use the values the error names. |
| A ticker returns nothing | The company is not covered, or the ticker is mistyped | Try the company name. |
| You treated search as content | Search returns Streams only | Scope `synorb-manifests` with the returned IDs. |

## Make it good for your user

Never answer "yes, we cover that" from memory. Never answer from a count you did not read in this session. Search, then say what you found in one line, with how fresh it is: "I found three Bloomberg Streams. The main one published 41 items in the last week." If the match is weak, say so and offer the two closest alternatives. Do not substitute one without telling your user.

## Next guide

[The Stream schema and every filter](/agent-resources/stream-schema-and-filters): what each field on a Stream means and how to use it to filter.
