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

# Search Recordings

> Semantic search over an end user's transcript chunks

Run a hybrid (semantic + keyword) search across an end user's transcripts and get back the most relevant excerpts. Each result carries `start_ms`/`end_ms` so you can deep-link a citation back to the moment in the audio. This is the retrieval primitive behind cross-recording [AI Ask](/api-reference/ask/create-session).

## Authentication

Requires an [API key](/authentication) with `recordings:read` scope.

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST https://api.bota.dev/v1/recordings/search \
    -H "Authorization: Bearer sk_live_..." \
    -H "Content-Type: application/json" \
    -d '{
      "end_user_id": "eu_abc123",
      "query": "what did we agree on the budget?",
      "limit": 8
    }'
  ```

  ```javascript Node.js theme={null}
  const response = await fetch('https://api.bota.dev/v1/recordings/search', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer sk_live_...',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      end_user_id: 'eu_abc123',
      query: 'what did we agree on the budget?',
      limit: 8,
    }),
  });

  const { results } = await response.json();
  ```

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

  response = requests.post(
      'https://api.bota.dev/v1/recordings/search',
      headers={
          'Authorization': 'Bearer sk_live_...',
          'Content-Type': 'application/json',
      },
      json={
          'end_user_id': 'eu_abc123',
          'query': 'what did we agree on the budget?',
          'limit': 8,
      },
  )

  results = response.json()['results']
  ```
</RequestExample>

## Request Body

<ParamField body="query" type="string" required>
  Natural-language search query (1–1000 characters).
</ParamField>

<ParamField body="end_user_id" type="string">
  End user whose recordings to search (`eu_*`). Required unless the API key is itself scoped to an end user.
</ParamField>

<ParamField body="recording_ids" type="string[]">
  Restrict the search to these recordings. Omit to search all of the end user's recordings.
</ParamField>

<ParamField body="recorded_after" type="string">
  Only include chunks from recordings on or after this time (ISO 8601).
</ParamField>

<ParamField body="recorded_before" type="string">
  Only include chunks from recordings before this time (ISO 8601).
</ParamField>

<ParamField body="limit" type="integer" default="8">
  Maximum number of chunks to return (1–50).
</ParamField>

## Response

Returns the top-K most relevant transcript chunks, best first.

<ResponseExample>
  ```json 200 theme={null}
  {
    "results": [
      {
        "chunk_id": "chk_abc123",
        "recording_id": "rec_def456",
        "transcription_id": "txn_ghi789",
        "chunk_text": "Let's lock the Q3 budget at 1.2M and revisit in August.",
        "speaker": "SPEAKER_0",
        "start_ms": 754000,
        "end_ms": 761200,
        "recorded_at": "2026-05-16T09:12:00Z",
        "score": 0.0312
      }
    ]
  }
  ```
</ResponseExample>

## Response Fields

| Field              | Type           | Description                                                                  |
| ------------------ | -------------- | ---------------------------------------------------------------------------- |
| `chunk_id`         | string         | Chunk identifier (`chk_*`)                                                   |
| `recording_id`     | string         | Recording the chunk belongs to (`rec_*`)                                     |
| `transcription_id` | string         | Source transcription (`txn_*`)                                               |
| `chunk_text`       | string         | The excerpt text                                                             |
| `speaker`          | string \| null | Dominant speaker label, or null if mixed/unknown                             |
| `start_ms`         | integer        | Chunk start offset in the audio (milliseconds) — use for citation deep-links |
| `end_ms`           | integer        | Chunk end offset (milliseconds)                                              |
| `recorded_at`      | string \| null | When the recording was captured (ISO 8601)                                   |
| `score`            | number         | Relevance score (higher is more relevant)                                    |

<Note>
  Search only covers recordings that have a completed transcription — chunking + embedding runs automatically after transcription completes.
</Note>
