> ## Documentation Index
> Fetch the complete documentation index at: https://docs.get-exo.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Search

> Hybrid vector and keyword search over stored content, with no reasoning layer.

## What this family does

Search is the cheap primitive. It runs pgvector and BM25 over the organization's memory chunks and fuses the two rankings, then stops. There is no brain inference, no cognition block and no contradiction detection.

Reach for it when you want matching text and you already know what you are going to do with it. Reach for `POST /v1/retrieve` when you want Exo to reason.

## Routes

| Method | Path                                         | Scope  | What it does       |
| ------ | -------------------------------------------- | ------ | ------------------ |
| `POST` | [`/v1/search`](/api-reference/search/search) | `read` | Lean hybrid search |

## Headers that apply here

Neither header is declared as an OpenAPI parameter, so neither appears in the generated schema tables.

* **`X-Exo-Subject`** selects which subject the call acts for on the subject-aware routes above. Omit it to act as the key owner. See [Subjects](/api-reference/subjects).

## The shape of a call

Search stored content.

<CodeGroup>
  ```bash cURL theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  curl -X POST https://api.get-exo.com/v1/search \
    -H "X-Exo-API-Key: $EXO_KEY" \
    -H "Content-Type: application/json" \
    -d '{"query": "pricing model", "scope": "user", "topK": 10}'
  ```

  ```python Python theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  import httpx

  response = httpx.post(
      "https://api.get-exo.com/v1/search",
      headers={"X-Exo-API-Key": EXO_KEY},
      json={"query": "pricing model", "scope": "user", "topK": 10},
  )
  for hit in response.json()["results"]:
      print(hit["score"], hit["title"])
  ```

  ```typescript TypeScript theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  const response = await fetch("https://api.get-exo.com/v1/search", {
    method: "POST",
    headers: {
      "X-Exo-API-Key": process.env.EXO_KEY!,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ query: "pricing model", scope: "user", topK: 10 }),
  });
  const { results } = await response.json();
  ```
</CodeGroup>

The response:

```json theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
{
  "results": [
    {
      "chunk": "We agreed to drop the freemium tier and price on usage.",
      "nodeId": "ingest:4a1e88f0-9c2d-4f31-b7a0-5e6c1d820b93:7d3c9b1e04a2",
      "title": "Pricing working session",
      "score": 0.031746
    }
  ],
  "usage": { "readUnits": 1, "embedTokens": 4 }
}
```

## Traps

**`scope` is a body field.** `user` filters to the effective subject, `org` searches the whole organization. This is separate from the `X-Exo-Subject` header, which decides which subject `user` means.

**Search meters its own rate-limit family.** It embeds the query on every call, so it does not draw on the generous `reads` bucket.

## Related

<Columns cols={2}>
  <Card title="API reference" icon="book-open" href="/api-reference/overview">
    Base URL, authentication, and the conventions every route shares.
  </Card>

  <Card title="Errors" icon="circle-alert" href="/platform/errors">
    The problem envelope and the full code catalogue.
  </Card>
</Columns>
