<!-- source: https://docs.redpine.ai/docs/assisted-search -->
# Assisted search

> Agentic retrieval that plans its own searches and verifies every result.

## How this differs from Search

`/search/query` runs one hybrid retrieval pass and returns whatever ranks highest. `/search/assisted` runs a multi-round agent loop: it reads the query for entities, intent, and aspects, plans internal searches to cover them, and keeps searching and replanning until it has gathered enough candidates or hits the iteration cap. Every candidate gathered is then verified against the query before delivery: a full pool of candidates is not the same as a full pool of verified results, which is why a request can still come back as `no_relevant_results` after several rounds.

**Billing differs too:** only delivered, verified results are charged. A clarification request or an honest "no relevant results" answer costs nothing: internal search fan-out and LLM tokens spent along the way are absorbed by Redpine, not billed to you. See [Rate limits](/docs/rate-limits) for the shared billing and rate-limit headers.

## Assisted Search

`POST /api/v1/search/assisted`

Runs the agentic search loop and returns verified results, a clarifying question, or an explicit no-relevant-results outcome. Accepts the same `filters` as `/search/query`, applied to every internal search.

### Request body

| Parameter          | Type           | Required                          | Description                                                                                                                                         |
| ------------------ | -------------- | --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `collection`       | string         | One of `collection`/`collections` | Collection name to search                                                                                                                           |
| `collections`      | string\[]      | One of `collection`/`collections` | Collections to search together (max 5)                                                                                                              |
| `query`            | string         | Yes                               | A natural-language question, or a whole document such as a patient case or chart note (max 16,000 characters). See [Long queries](#long-queries)    |
| `limit`            | integer        | No                                | Maximum verified results to return (default 10, max 30)                                                                                             |
| `filters`          | object \| null | No                                | Same filter forms as `/search/query`, applied to every internal search                                                                              |
| `include_metadata` | boolean        | No                                | Include chunk metadata in results (default true)                                                                                                    |
| `include_figures`  | boolean        | No                                | Fetch and attach figure images as base64 in metadata.figures\[].image\_data, for delivered results only (default false, requires include\_metadata) |

### Response fields

| Field                | Type                                                               | Description                                                                                                                                                                                                                                        |
| -------------------- | ------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `status`             | `"results"` \| `"clarification_needed"` \| `"no_relevant_results"` | Outcome of the assisted search                                                                                                                                                                                                                     |
| `queryUnderstanding` | object                                                             | How the query was read: entities, intent, aspects, and any structured filters named in the query text. For a long query, also `caseSummary` (the summary results were judged against) and `subQuestions` (the separate problems it was split into) |
| `results`            | array                                                              | Verified results. Empty unless status is `results`                                                                                                                                                                                                 |
| `clarification`      | object \| null                                                     | The clarifying question and reason. Set only when status is `clarification_needed`                                                                                                                                                                 |
| `billing`            | object                                                             | What was actually charged: `chargedResults` and `tokensCharged`                                                                                                                                                                                    |
| `queryId`            | string                                                             | Query identifier for audit reference                                                                                                                                                                                                               |
| `latencyMs`          | integer                                                            | End-to-end latency in milliseconds                                                                                                                                                                                                                 |
| `iterationsRun`      | integer                                                            | Number of search + replan rounds executed                                                                                                                                                                                                          |
| `filterWarnings`     | array \| null                                                      | Advisory warnings for filter fields with no payload index; omitted when there are none                                                                                                                                                             |
| `discovery`          | object \| null                                                     | A catalogue answer, set only when the query asked about the catalogue rather than for literature; nothing is charged. See [Catalogue questions](/docs/collections#catalogue-questions)                                                             |

### Result object

| Field         | Type           | Description                                                                                                                                              |
| ------------- | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`          | string         | Chunk/point ID                                                                                                                                           |
| `text`        | string         | Chunk text content                                                                                                                                       |
| `metadata`    | object \| null | Chunk metadata (if `include_metadata=true`)                                                                                                              |
| `collection`  | string \| null | Origin collection of this result. Populated only for requests made with the `collections` (multi-collection) form                                        |
| `doiUrl`      | string \| null | Resolvable DOI link (`https://doi.org/{doi}`)                                                                                                            |
| `section`     | string \| null | Comma-joined source section(s) of the article (abstract, introduction, background, methods, results, discussion, conclusion, case, supplementary, other) |
| `relevance`   | object         | Relevance verdict: `matchedTerms`, `judgeScore` (0..1), and a one-sentence `rationale`                                                                   |
| `subQuestion` | string \| null | The sub-question of a multi-problem query that this result answers; `null` when the query was answered as a single question                              |

### Example request

<CodeBlockTabs defaultValue="cURL" groupId="lang">
  <CodeBlockTabsList>
    <CodeBlockTabsTrigger value="cURL">
      cURL
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="Python">
      Python
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="TypeScript">
      TypeScript
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="Go">
      Go
    </CodeBlockTabsTrigger>
  </CodeBlockTabsList>

  <CodeBlockTab value="cURL">
    ```bash  
    curl -X POST "https://api.redpine.ai/api/v1/search/assisted" \
      -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "collection": "my-collection",
        "query": "Does topical retinoid use increase photosensitivity?",
        "limit": 10,
        "include_metadata": true
      }'
    ```
  </CodeBlockTab>

  <CodeBlockTab value="Python">
    ```python  
    from redpine import Redpine

    client = Redpine()  # reads REDPINE_API_KEY

    a = client.assisted_search(
        "Does topical retinoid use increase photosensitivity?",
        collection="my-collection",
        limit=10,
    )
    if a.status == "results":
        for hit in a.results:
            print(hit.relevance.judge_score, hit.section, hit.text[:200])
    elif a.status == "clarification_needed":
        print(a.clarification.question)
    else:
        print("No relevant results")
    print(a.billing.charged_results, a.billing.tokens_charged, a.iterations_run)
    ```
  </CodeBlockTab>

  <CodeBlockTab value="TypeScript">
    ```typescript  
    import { Redpine } from "@redpine-ai/sdk";

    const client = new Redpine(); // reads REDPINE_API_KEY

    const a = await client.assistedSearch("Does topical retinoid use increase photosensitivity?", {
      collection: "my-collection",
      limit: 10,
    });
    if (a.status === "results") {
      for (const hit of a.results ?? []) {
        console.log(hit.relevance.judgeScore, hit.section, hit.text.slice(0, 200));
      }
    } else if (a.status === "clarification_needed") {
      console.log(a.clarification?.question);
    } else {
      console.log("No relevant results");
    }
    console.log(a.billing.chargedResults, a.billing.tokensCharged, a.iterationsRun);
    ```
  </CodeBlockTab>

  <CodeBlockTab value="Go">
    ```go  
    client, err := redpine.New() // reads REDPINE_API_KEY
    if err != nil {
        return err
    }

    a, err := client.AssistedSearch(ctx, "Does topical retinoid use increase photosensitivity?",
        redpine.AssistedSearchOptions{Collection: "my-collection", Limit: 10})
    if err != nil {
        return err
    }
    switch a.Status {
    case "results":
        for _, hit := range *a.Results {
            fmt.Println(hit.Relevance.JudgeScore, hit.Text)
        }
    case "clarification_needed":
        fmt.Println(a.Clarification.Question)
    default:
        fmt.Println("No relevant results")
    }
    fmt.Println(a.Billing.ChargedResults, a.Billing.TokensCharged, a.IterationsRun)
    ```
  </CodeBlockTab>
</CodeBlockTabs>

Pass `allow_clarification=False` (`allowClarification: false`, `AllowClarification: &f`) to make the endpoint search on its best interpretation instead of asking. A `503` while the assisted service is unavailable raises `AssistedUnavailable`; the SDKs retry it twice with backoff before surfacing it.

### Example response (verified results)

```json
{
  "status": "results",
  "queryUnderstanding": {
    "entities": ["retinoid", "photosensitivity"],
    "intent": "Determine whether an adverse effect is associated with a treatment",
    "aspects": ["mechanism of action", "clinical outcomes"],
    "filters": {}
  },
  "results": [
    {
      "id": "abc123",
      "text": "Topical retinoids increase skin sensitivity to UV light by thinning the stratum corneum...",
      "metadata": {
        "title": "Retinoid Dermatology Review"
      },
      "collection": null,
      "doiUrl": "https://doi.org/10.1234/example",
      "section": "discussion",
      "relevance": {
        "matchedTerms": ["retinoid", "photosensitivity"],
        "judgeScore": 0.91,
        "rationale": "Directly states the photosensitizing mechanism of topical retinoids."
      }
    }
  ],
  "clarification": null,
  "billing": {
    "chargedResults": 1,
    "tokensCharged": 612
  },
  "queryId": "qry_a1b2c3d4e5f6",
  "latencyMs": 3840,
  "iterationsRun": 2
}
```

## Long queries

`query` takes up to 16,000 characters, so you can send a whole document, such as a patient case or chart note, instead of a question distilled from it. Other search endpoints still take 1,000.

A long query is read as a document. `queryUnderstanding.caseSummary` holds the summary results were judged against, and when the document raises several separate problems, `queryUnderstanding.subQuestions` lists them, up to four. Each sub-question is searched and verified on its own and gets its own result slots; each result's `subQuestion` says which one it answers. Assisted search returns at most one result per article.

A long query takes longer than a short one. The Python and Go SDKs wait up to 120 seconds for assisted search by default; if you set your own timeout, allow for it. See [SDKs](/docs/sdks).

## Clarification flow

When the query genuinely cannot be searched as written, the endpoint returns `status: "clarification_needed"` with a question instead of running the full search. Re-issue the request with the query augmented by the user's answer. Clarification requests are never billed.

```json
{
  "status": "clarification_needed",
  "queryUnderstanding": {
    "entities": ["treatment"],
    "intent": "Unclear -- no specific condition or drug named",
    "aspects": [],
    "filters": {}
  },
  "results": [],
  "clarification": {
    "question": "Which treatment and condition are you asking about?",
    "reason": "The query is too underspecified to search usefully."
  },
  "billing": {
    "chargedResults": 0,
    "tokensCharged": 0
  },
  "queryId": "qry_f6e5d4c3b2a1",
  "latencyMs": 1120,
  "iterationsRun": 0
}
```

## Filtering

The `filters` parameter accepts the same simple and structured-DSL forms as `/search/query`, and is applied to every internal search the agent runs. See [Filtering](/docs/filtering) for operators, indexed fields, and the filters that are rejected.