---
title: "Search Endpoint"
method: GET
path: "/v1/search"
---

# Search Endpoint

`GET /v1/search`

## Request

- Base URL: `https://api.storyflo.com` (the document declares no server; this is the origin it was published from)
- URL: `https://api.storyflo.com/v1/search`
- Auth: none declared

Text search across persona briefings + articles. ILIKE-based; at
~95 briefings + ~52K articles the seq scan + LIMIT stays fast enough on
Postgres without a tsvector index. Swap to plainto_tsquery once article
volume passes ~250K; the response contract is stable.

Declassified segregation 2026-07-06: the ~198 bulk-ingested
``briefing_kind='declassified'`` rows (Vietnam study, FBI cryptography
files, …) were swamping general-search relevance — ``q=tech`` / ``ai`` /
``news`` returned declassified case briefings instead of the matching
vertical persona briefings, and a new self-expanding ingest cron makes
this strictly worse over time. General search (``kind`` unset) now
EXCLUDES declassified via the same ``is_distinct_from('declassified')``
gate the X-autopost rotation uses (app/daily_brief_worker.py). Declassified
stays fully discoverable on its OWN surfaces — the declassified RSS feed,
the ``search_declassified`` MCP tool, ``digest_declassified`` — and, for
parity, callers can scope this endpoint to it explicitly with
``kind=declassified``.

Pool-exhaustion fix 2026-06-21 (overnight Sentry SEV — TimeoutError
QueuePool size=5 overflow=3 reached on /v1/search): deliberately
no ``db: AsyncSession = Depends(get_db)`` parameter. The two ILIKE
scans below can each take 5-15s over the 52K-article body_text
seq-scan path; with Depends(get_db) the session is held for the
FULL request duration. Under load that triggers the same pool-
exhaustion class as PRs #657/#658/#674/#677/#678 — on the writer
pool. Canonical fix-pattern: open a short-lived session inside
the handler body + release via ``_close_session_safely`` in
``finally`` BEFORE building the response shape.

## Query parameters

- `q` string, required
- `vertical` string, nullable
- `limit` integer
- `kind` string, nullable: Briefing-kind scope. Default (unset) is GENERAL search: the declassified archive is segregated OUT so vertical queries (tech/ai/news) surface vertical persona briefings instead of being swamped by the bulk-ingested declassified corpus. Pass ``kind=declassified`` to search ONLY the declassified archive (the same scope as /v1/podcasts/storyflo-declassified.xml and the search_declassified MCP tool).

## Response `200`

Successful Response

- object

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/storyflo/apis/storyflo-inference-router.md) · [All operations](https://skmtc.dev/storyflo/apis/storyflo-inference-router/llms.txt) · [OpenAPI document](https://skmtc.dev/storyflo/apis/storyflo-inference-router/revisions/c3a1a735ac7a?raw)
