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

# Search research

> Runnable TypeScript example: search research, with inputs, output, source code, and execution limits.

[Raw TypeScript source](https://raw.githubusercontent.com/user-intuition/examples/main/examples/search-research/index.ts) · [Workflow walkthrough](https://github.com/user-intuition/examples/tree/main/examples/search-research) · [All examples](/api-reference/developer-examples)

## Run locally

Requires Node.js 22.18 or later. Run from the cloned repository; this file imports the shared client and contracts in `src/`. The default uses fictional local fixtures with no credentials, network calls, invitations, or spending.

```sh theme={null}
git clone https://github.com/user-intuition/examples.git
cd examples
npm run search
```

For live calls, supply `USERINTUITION_API_KEY` securely in the environment and explicitly select `--live`. Follow the walkthrough for action-specific arguments and approvals. The report and search adapters were [checked against the released API and staging](https://github.com/user-intuition/examples/blob/main/docs/release-check.md); recheck the live contract when integrating a newer API version.

## Inputs

Use --query with the research question and --study for a live scoped search. Optional --cursor, --limit, and --fetch-source constrain or extend retrieval. Fixture mode returns a fixed match and does not execute the query.

## Expected output

JSON containing mode, request, and response. The response groups canonical results under studies and includes next\_cursor. With --fetch-source, a second object contains source\_kind and source or explains that there are no matches.

## Side effects

Retrieves existing evidence; does not create studies, regenerate reports, invite people, or launch recruitment.

## Failures

Invalid limits, missing live credentials or study ID, HTTP errors, invalid response shapes, and unresolved sources are failures. A successful empty nested results array is distinct from these errors.

## Complete source file

The following is generated from `examples/search-research/index.ts`, not maintained as a separate snippet. SHA-256: `f9d5d4e9d49b518feb7e22fbce170bbc661184ccc16c039cb94e282bbcabbfe5`.

```typescript theme={null}
import { args, limit, required } from "../../src/args.ts";
import {
  ResearchClient,
  fixture,
  output,
} from "../../src/client.ts";
import {
  routes,
  type SearchRequest,
  type SearchResponse,
} from "../../src/contracts.ts";
const options = args();
const request: SearchRequest = {
  query:
    options.query ?? "What makes people think the product is too expensive?",
  limit: limit(options.limit),
  cursor: options.cursor ?? null,
  filters: {
    study_ids: [options.live ? required(options.study, "study") : (options.study ?? "example-study")],
    content_types: ["study_finding", "participant_response"],
  },
};
const response = options.live
  ? await new ResearchClient().request<SearchResponse>(
      "POST",
      routes.search,
      request,
    )
  : await fixture<SearchResponse>("search");
if (!Array.isArray(response.studies) ||
    response.studies.some((study) => !Array.isArray(study.results)))
  throw new Error(
    "Unexpected search response: studies or nested results is not an array.",
  );
output({
  mode: options.live
    ? "live"
    : "fictional fixture; query is illustrative, not executed",
  request,
  response,
});
// Fetch a source with routes.reportFull(study.study_id) or routes.interview(result.interview_id).
// Paginate with the same query/filters and next_cursor. No new study is created by this example.

if (options["fetch-source"]) {
  const first = response.studies.flatMap((study) =>
    study.results.map((result) => ({ study, result })),
  )[0];
  if (!first) {
    output({ source_status: "No search matches; no source was fetched." });
  } else {
    const { study, result } = first;
    const interviewId = result.interview_id;
    const source = options.live
      ? await new ResearchClient().request(
          "GET",
          interviewId
            ? routes.interview(interviewId)
            : routes.reportFull(study.study_id),
        )
      : interviewId
        ? (
            await fixture<Array<{ id: string; messages: unknown[] }>>(
              "interviews",
            )
          ).find((item) => item.id === interviewId)
        : await fixture("report");
    if (!source)
      throw new Error(
        "Search source was not found; do not infer its contents.",
      );
    output({
      content_id: result.content_id,
      study_id: study.study_id,
      indexed_report_id: study.indexed_report_id,
      source_kind: interviewId ? "interview" : "report",
      source,
      instruction:
        "Check source context and the indexed report ID before citing. This is one result, not exhaustive coverage.",
    });
  }
}
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.