---
title: "Search articles by meaning"
method: POST
path: "/search_articles_by_meaning"
---

# Search articles by meaning

`POST /search_articles_by_meaning`

## Request

- Base URL: `https://newsmind.app/api/v1`
- URL: `https://newsmind.app/api/v1/search_articles_by_meaning`
- Auth: OAuth 2 (authorization code, authorization URL `https://newsmind.app/oauth/authorize`, token URL `https://newsmind.app/oauth/token`, scopes: `mcp`)

Conceptual search via vector embeddings; prefer over keyword search for paraphrased questions ('GPU bottleneck' matches 'AI chip supply'). Newsmind Max only — Pro gets max_required. The `retention` field carries the 90-day window + cutoff_hit flag — surface when set.

## Request body

- object
  - `query` string, required: Natural-language description of what you're looking for. Conceptual / topical phrasing works better than keyword phrasing.
  - `limit` integer: Max results. Default 20; values outside 1-100 are clamped.
  - `unread_only` boolean: Exclude articles the user has marked read.

## Response `200`

Success

- object
  - `query` string
  - `count` integer
  - `articles` object[]
    - `id` integer
    - `feed_id` integer
    - `feed_title` string, nullable
    - `title` string, nullable
    - `url` string, nullable
    - `image_url` string, uri, nullable
    - `image_width` integer, nullable
    - `image_height` integer, nullable
    - `image_mime` string, nullable
    - `summary` string, nullable
    - `published_at` string, date-time, nullable
    - `added_at` string, date-time, nullable
    - `similarity` number
  - `search_scope` SearchScope: Present only when the caller's feeds hold more in-window articles than one search can cover (#303). Everything published since `since` was searched; older articles were not. Surface the note when present.
    - `since` string, date-time, required: ISO timestamp; articles published before it were not searched.
    - `bounded` boolean, required: Always true when the field is present.
    - `articles_searched` integer, nullable: Semantic search: how many of the caller's articles the scan read (the newest ones).
    - `matches_ranked` integer, nullable: Keyword search: how many caller-visible matches the rank was chosen from.
    - `note` string, required: One sentence for the user, ready to relay.
  - `retention` RetentionMeta: Tier-based retention window for the caller. Articles older than cutoff_at are invisible to discovery (search, unread, counts) regardless of query. cutoff_hit is set when retention likely truncated the result set — surface to the user when present.
    - `window_days` integer, required: Retention window in days. Pro = 30, Max = 90.
    - `cutoff_at` string, date-time, required: ISO timestamp; articles with published_at < cutoff_at are filtered out.
    - `cutoff_hit` boolean, nullable: Present (and set to true) only when retention likely bounded the result set: user asked for older data than retention covers, query came back empty for a multi-term ask, or the oldest returned article is right at the wall. Absent on queries where retention wasn't the limiter.

## Other responses

- `400`: Bad request
- `401`: Unauthorized
- `402`: Subscription required (trial expired or cancelled)
- `429`: Too many calls. Either the per-account rate limit ({error: "rate_limited", message}) or the account's in-flight work ({error: <sentence>, code: "busy"}). Wait Retry-After seconds.
- `500`: Server error on our side (error: internal_error). The team has been notified.
- `503`: Temporarily unable to answer. error: timeout (the request ran too long; narrow it), server_busy or tier_unavailable (retry after Retry-After seconds when sent).

---

[API](https://skmtc.dev/newsmind/apis/newsmind-api.md) · [All operations](https://skmtc.dev/newsmind/apis/newsmind-api/llms.txt) · [OpenAPI document](https://skmtc.dev/newsmind/apis/newsmind-api/revisions/f8af23fb5a10?raw)
