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

# Search

> Vector search across your organization's memory. Returns ranked hits with metadata.

The simplest retrieval endpoint. Use it when you want raw hits and will craft your own prompt downstream. For grounded answers with citations + exclusions, use [`/v1/context`](/api-reference/context) or [`/v1/ask`](/api-reference/ask).

## Required action

`search` — see [Authentication → Actions](/authentication#actions).

## Cost

Each successful call consumes **1 credit**. On Builder tier this is hard-blocked at the monthly cap. On Studio/Scale tiers calls past the cap are billed at \$0.015 per answer overage. See [Billing](/billing).

## Body

<ParamField body="query" type="string" required>
  The user-facing question or search phrase. Sent as-is to the embedding model.
</ParamField>

<ParamField body="limit" type="integer" default="8">
  Maximum number of hits to return. Min 1, max 25.
</ParamField>

## Response

```json theme={null}
{
  "query": "What did we decide about the brand color?",
  "hits": [
    {
      "sourceItemId": "9c0e7a3f-1234-4abc-bdef-1234567890ab",
      "title": "Brand decisions",
      "content": "We're keeping the lime-green accent because Q2 testing showed...",
      "url": "https://www.notion.so/Brand-decisions-...",
      "provider": "notion",
      "score": 0.8432,
      "metadata": {
        "workspaceId": "ws-1",
        "workspaceName": "Repo Labs"
      },
      "syncedAt": "2026-05-30T20:00:00Z"
    }
  ]
}
```

<ResponseField name="query" type="string">
  Echo of the input query for convenience.
</ResponseField>

<ResponseField name="hits" type="array">
  Ranked array of source items matching the query, ordered by `score` descending.

  <Expandable title="Hit fields">
    <ResponseField name="sourceItemId" type="string">Stable Repo UUID for the source item.</ResponseField>
    <ResponseField name="title" type="string">Human-facing title (Notion page title, Slack message preview, etc.).</ResponseField>
    <ResponseField name="content" type="string">The matched chunk text.</ResponseField>
    <ResponseField name="url" type="string">Deep-link back to the original source.</ResponseField>
    <ResponseField name="provider" type="string">`slack`, `google_drive`, `notion`, or `gmail`.</ResponseField>
    <ResponseField name="score" type="number">Cosine similarity to the query embedding (0.0–1.0).</ResponseField>
    <ResponseField name="metadata" type="object">Provider-specific metadata (workspace IDs, channel names, sender info, etc.).</ResponseField>
    <ResponseField name="syncedAt" type="string">When this source was last synced by Repo.</ResponseField>
  </Expandable>
</ResponseField>

## Example

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://api.userepo.com/v1/search \
    -H "Authorization: Bearer repo_your_key" \
    -H "Content-Type: application/json" \
    -d '{"query": "Q3 OKRs", "limit": 5}'
  ```

  ```typescript Node theme={null}
  const res = await fetch("https://api.userepo.com/v1/search", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.REPO_API_KEY}`,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({ query: "Q3 OKRs", limit: 5 })
  });
  const { hits } = await res.json();
  ```

  ```python Python theme={null}
  import requests, os

  r = requests.post(
      "https://api.userepo.com/v1/search",
      headers={"Authorization": f"Bearer {os.environ['REPO_API_KEY']}"},
      json={"query": "Q3 OKRs", "limit": 5}
  )
  print(r.json()["hits"])
  ```
</CodeGroup>

## Provider scoping

If the calling key has `allowedProviders` set, hits from excluded providers are filtered out server-side before the response is built. See [Scopes](/concepts/scopes) for details. The `exclusions` array that explains *why* something was filtered is only returned by `/v1/context` — `/v1/search` is silent about scope filtering.
