<!-- source: https://docs.redpine.ai/docs/api-reference/search/searchQuery -->
# Search documents

> Search one or more collections using natural language or keyword queries. Results are ranked by relevance using hybrid retrieval (dense + sparse). Pass `collections` (up to 5) to search several collections in one call and receive a single merged, relevance-ranked list with per-result origin labels.

`POST` `https://api.redpine.ai/api/v1/search/query`

## Authentication

```
Authorization: Bearer sk_live_YOUR_API_KEY
```

## Request body

| Field | Type | Required | Description |
|---|---|---|---|
| `collection` | string | no | Name of the collection to search. Mutually exclusive with `collections`. |
| `collections` | array | no | Collections to search together (max 5, unique). Each collection is searched with its own access entitlements and the results are merged into one relevance-ranked list; each result carries its origin `collection`. Mutually exclusive with `collection`. |
| `filters` | object | no | Optional metadata filter. Two accepted forms. Flat (top-level keys are ANDed): `{"journal": "Nature", "publication_date": {"gte": "2020-01-01"}}`. Structured DSL (for OR / nesting): `{"and": [{"field": "journal", "eq": "Nature"}]}`. Operators: `eq`, `ne`, `in`, `not_in`, `gt`, `gte`, `lt`, `lte`, `between`. Combinators: `and`, `or`, `not`. One operator per condition, except range bounds (`gt`, `gte`, `lt`, `lte`) together; put other combinations in separate conditions under `and`. Mixing the flat and structured forms in one filter is rejected. Exclusion uses `ne` / `not_in` / `not` — there is no separate syntax: `{"and": [{"field": "issn", "not_in": ["1234-5679"]}]}`. Indexed on every collection (a field that is not a known result metadata field is rejected; a known field without an index, such as `pmid`, is matched by scanning and returns a `filterWarnings` entry, and is rejected on a collection that has no index for it): `article_type`, `chapter_authors`, `chapter_number`, `chapter_title`, `doi`, `isbn`, `issn`, `journal`, `keywords`, `open_access`, `publication_date`, `publisher`, `section`. Indexed on the editorial collections only: `has_results`, `last_updated_date`, `medical_board_approved`, `nct_id`, `overall_status`, `phases`, `topic`, `url`. `open_access` is also answered for a collection that holds only open-access content and carries no such field: `true` matches everything there, `false` (or the field under `or` / `not`) excludes that collection with a `filterWarnings` entry. `license` is returned in result metadata but is not filterable. `issn` accepts hyphenated or bare, upper- or lower-case X (`"1234-561X"`, `"1234561x"`). `doi` is matched case-insensitively and an optional `https://doi.org/` or `doi:` prefix is accepted. `journal_metric.2yr_mean_citedness`, `journal_metric.h_index`, `journal_metric.i10_index` and `journal_metric.impact_factor` accept range operators only and are resolved server-side into the matching ISSNs; see `journalMetricExpansions` in the response. `impact_factor` is an impact factor computed by Redpine from OpenAlex citation data with the JIF formula. It is not Clarivate's Journal Impact Factor. Journals that publish many news items, letters and editorials (for example BMJ, JAMA, The Lancet) score far below their JCR figure, because OpenAlex classifies those items as articles. A metric condition may match at most 35,000 journal ISSNs and a request may send at most 70,000 filter values. A threshold with one end must stay within its documented bound: journal_metric.2yr_mean_citedness: gte 1.1 or higher, or lte 0.0 or lower; journal_metric.h_index: gte 35 or higher, or lte 3 or lower; journal_metric.i10_index: gte 160 or higher (no upper bound alone); journal_metric.impact_factor: gte 0.9 or higher, or lte 0.2 or lower. On h_index and i10_index, gt N counts as gte N+1 and lt N as lte N-1. A range with both ends (gte with lte, or between) may sit anywhere if it matches no more than 35,000 ISSNs. For 'below X' use not with gte X, X at or above the metric's minimum; not also keeps documents with no journal metric, and on impact_factor journals with no impact_factor. Two conditions near their bounds use most of the 70,000 values, so a third, or a long in/not_in list beside them, can be refused. |
| `imageMaxHeight` | integer | no | Maximum image height in pixels |
| `imageMaxWidth` | integer | no | Maximum image width in pixels |
| `imageQuality` | integer | no | JPEG quality for fetched images |
| `includeFigures` | boolean | no | Fetch and include figure images as base64 in metadata (adds latency). includeImages is accepted as a deprecated alias. |
| `includeMetadata` | boolean | no | Whether to include metadata in results |
| `limit` | integer | no | Maximum results to return (default 10, max 30) |
| `query` | string | yes | Natural language or keyword search query. |

## Responses

| Status | Description |
|---|---|
| `200` | Search results |
| `401` | Missing or invalid API key |
| `403` | API key does not have access to the requested collection |
| `404` | Collection not found |
| `422` | Validation error (e.g. query too long) |
| `429` | Rate or quota limit exceeded |
| `503` | Search temporarily unavailable (Qdrant or the quota service is down) |

### 200 response fields

| Field | Type | Required | Description |
|---|---|---|---|
| `discovery` | object | no | A catalogue answer: what data sources, publishers or journals your key can reach. Present only when the query asked about the catalogue rather than for literature; then `results` is empty and nothing was charged (`X-Query-Cost: 0.000000`). |
| `filterWarnings` | array | no | Advisory warnings about the supplied filter — for example filtering on a known field with no payload index, which is matched by scanning, or a collection excluded because it holds only open-access content and the filter asked for open_access=false. The search still runs. Omitted when there are none. |
| `filtersApplied` | object | no | The filters you sent, after validation. Omitted when no filters were sent. |
| `journalMetricExpansions` | array | no | How each journal-metric condition resolved to ISSNs; omitted when no metric filter was used |
| `latencyMs` | integer | yes | Search latency in milliseconds |
| `queryId` | string | yes | Unique identifier for this query. Use it to re-fetch the same results for free within 7 days via GET /api/v1/search/results/{queryId}. |
| `results` | object[] | yes | Ranked list of matching document chunks. |