> For the complete documentation index, see [llms.txt](https://docs.aiclicks.io/llms.txt).
> Use it to discover all available pages before exploring further.

# List Fan-out Queries

Returns the search queries LLMs fanned out to per tracked prompt, attributed by model.

When you ask an LLM a question, it doesn't just answer it. Internally it issues one or more **fan-out search queries** to ground its response in fresh information. These are the real searches the LLM ran on your behalf — and the closest thing you have to "what queries should I rank for" inside AI search.

This endpoint groups fan-out queries **under the tracked prompt that triggered them**. Each fan-out entry is one actual emission, attributed to a specific response and model channel. To rank queries by global frequency across prompts, flatten the result client-side.

`domain_id` is a required query parameter. Use `` to discover which domains the calling key can access.

<Request show-lines="true" tabs={[]}>
  ```bash
  curl --request GET \
    --url 'https://api.aiclicks.io/api/v1/fanout-queries?domain_id=8f1d3c0a-2f9b-4c11-9b80-7a82e1f0c3f3&days=30' \
    --header 'Authorization: Bearer ak_live_xxx'
  ```

  ```python
  import httpx, os

  resp = httpx.get(
      "https://api.aiclicks.io/api/v1/fanout-queries",
      params={
          "domain_id": "8f1d3c0a-2f9b-4c11-9b80-7a82e1f0c3f3",
          "days": 30,
      },
      headers={"Authorization": f"Bearer {os.environ['AICLICKS_API_KEY']}"},
  )
  resp.raise_for_status()
  for prompt in resp.json()["data"]["items"]:
      print(prompt["text"])
      for f in prompt["fanout_queries"]:
          print(f"  [{f['model']}] {f['query']}")
  ```

  ```javascript
  const url = new URL("https://api.aiclicks.io/api/v1/fanout-queries");
  url.searchParams.set("domain_id", "8f1d3c0a-2f9b-4c11-9b80-7a82e1f0c3f3");
  url.searchParams.set("days", "30");

  const resp = await fetch(url, {
    headers: { Authorization: `Bearer ${process.env.AICLICKS_API_KEY}` },
  });
  const { data } = await resp.json();
  for (const prompt of data.items) {
    console.log(prompt.text);
    for (const f of prompt.fanout_queries) {
      console.log(`  [${f.model}] ${f.query}`);
    }
  }
  ```
</Request>

<Response show-lines="true" tabs={[]}>
  ```json
  {
    "data": {
      "items": [
        {
          "id": "21c1f9aa-9b6d-4e3a-8a31-2b0c0e1f2a3b",
          "text": "best CRM for small business",
          "fanout_queries": [
            {
              "id": "8a3c2e91-1f44-4b6e-9a01-2c0d8f3e1aab",
              "query": "top CRM software 2026",
              "model": "ChatGPT"
            },
            {
              "id": "9b4d3f02-2055-4c7f-aa12-3d1e9f4f2bbc",
              "query": "Salesforce vs HubSpot review",
              "model": "Claude"
            },
            {
              "id": "ac5e4013-3166-4d80-bb23-4e2faf503ccd",
              "query": "best CRM cheap",
              "model": "Perplexity"
            }
          ]
        },
        {
          "id": "32d2e8bb-aa7e-5f4b-9b42-3c1d1f2a3b4c",
          "text": "Salesforce vs HubSpot",
          "fanout_queries": [
            {
              "id": "bd6f5124-4277-4e91-cc34-5f3fbf614dde",
              "query": "HubSpot pricing 2026",
              "model": "ChatGPT"
            }
          ]
        }
      ],
      "total": 12
    },
    "domain_id": "8f1d3c0a-2f9b-4c11-9b80-7a82e1f0c3f3",
    "days": 30,
    "model": "all",
    "generated_at": "2026-06-17T10:00:11.218Z"
  }
  ```

  ```json
  {
    "detail": "domain_id query parameter is required. List the domains this key can access with GET /api/v1/domains, then pass ?domain_id=<uuid>."
  }
  ```

  ```json
  {
    "detail": "Invalid or revoked API key"
  }
  ```

  ```json
  {
    "detail": "API access is not enabled for this team. Contact support@aiclicks.io."
  }
  ```

  ```json
  {
    "detail": "Domain not found"
  }
  ```

  ```json
  {
    "detail": "Too many requests. Please try again later."
  }
  ```
</Response>

## Authorizations

<ParamField header="Authorization" param-type="string" required="true" deprecated="false" show-location="true">
  Your API key formatted as `Bearer ak_live_<your-key>`. Create one in the dashboard under **Settings → Developers**.
</ParamField>

<ParamField header="X-Request-Id" param-type="string" required="false" deprecated="false" show-location="true">
  Optional UUID for log correlation. If omitted, we generate one and echo it back in the response.
</ParamField>

## Query parameters

<ParamField query="domain_id" param-type="string" required="true" deprecated="false" show-location="true">
  UUID of the domain. Find domains via ``. Omitting this returns `400`.
</ParamField>

<ParamField query="days" param-type="integer" required="false" deprecated="false" show-location="true">
  Look-back window, 1–365. Defaults to `30`. Counted as an exact window (`today - days + 1`), not snapped to buckets.
</ParamField>

<ParamField query="model" param-type="string" required="false" deprecated="false" show-location="true">
  Filter to a single model channel. Accepts either the generic name (`ChatGPT`, `Claude`, `Gemini`, `Perplexity`, `AI Overviews`, `AI Mode`, `Grok`, `Microsoft Copilot`) or the underlying model key. Defaults to `all` — every channel.
</ParamField>

## Response

<ResponseField name="data" field-type="object" required="true" deprecated="false">
  The list payload.
</ResponseField>

<ResponseField name="data.items" field-type="array" required="true" deprecated="false">
  Array of prompts that produced at least one fan-out query in the window.

  <Expandable title="Prompt-with-fanouts properties" default-open="false">
    <ResponseField name="id" field-type="string" required="true" deprecated="false">
      UUID of the tracked prompt.
    </ResponseField>

    <ResponseField name="text" field-type="string" required="true" deprecated="false">
      The prompt text exactly as you track it.
    </ResponseField>

    <ResponseField name="fanout_queries" field-type="array" required="true" deprecated="false">
      One entry per emission. Same query string may appear multiple times — each represents a distinct LLM run.

      <Expandable title="Fan-out query properties" default-open="false">
        <ResponseField name="id" field-type="string" required="true" deprecated="false">
          UUID of the response that emitted this fan-out query. Lets you correlate emissions if you later expose response data.
        </ResponseField>

        <ResponseField name="query" field-type="string" required="true" deprecated="false">
          The actual fan-out search query the LLM ran.
        </ResponseField>

        <ResponseField name="model" field-type="string" required="true" deprecated="false">
          Generic channel name. Possible values: `ChatGPT`, `Claude`, `Gemini`, `Perplexity`, `AI Overviews`, `AI Mode`, `Grok`, `Microsoft Copilot`.
        </ResponseField>
      </Expandable>
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="data.total" field-type="integer" required="true" deprecated="false">
  Number of prompts that produced at least one fan-out query. Equals `items.length`.
</ResponseField>

<ResponseField name="domain_id" field-type="string" required="true" deprecated="false">
  Echo of the requested domain.
</ResponseField>

<ResponseField name="days" field-type="integer" required="true" deprecated="false">
  Echo of the requested window.
</ResponseField>

<ResponseField name="model" field-type="string" required="true" deprecated="false">
  Echo of the requested model filter.
</ResponseField>

<ResponseField name="generated_at" field-type="string" required="true" deprecated="false">
  ISO-8601 timestamp of when the server produced (or cached) this response.
</ResponseField>

## Response headers

| Header                  | Description                                                      |
| ----------------------- | ---------------------------------------------------------------- |
| `X-Cache`               | `HIT` or `MISS`. Indicates whether the response came from cache. |
| `X-Request-Id`          | Unique request id. Echoes incoming if you set one.               |
| `X-RateLimit-Limit`     | Max requests per minute for this key.                            |
| `X-RateLimit-Remaining` | Requests remaining in current minute.                            |
| `X-RateLimit-Reset`     | Unix epoch seconds when the window resets.                       |

## Caching

<Callout kind="info" collapsed="false">
  Cached for **1 hour** per `(domain_id, days, model)`. Fresh analyses that complete inside the cache window appear after the TTL expires.
</Callout>

## Frequency and ranking

There is no `count` field. Each entry in `fanout_queries` is one actual LLM emission — frequency is `fanout_queries.filter(f => f.query === target).length`. To rank fan-out queries globally across prompts:

```javascript
const counts = {};
for (const p of data.items) {
  for (const f of p.fanout_queries) {
    const key = f.query.toLowerCase().trim();
    counts[key] = (counts[key] || 0) + 1;
  }
}
const ranked = Object.entries(counts).sort((a, b) => b[1] - a[1]);
```

## Artefact filtering

Some LLMs emit metadata strings that are not real searches (e.g. `answer_guess`, `related_queries`, internal field names). AIclicks strips these server-side before you see them. The filter is defensive and may evolve — if you see a string that shouldn't be in the list, [contact support](mailto:support@aiclicks.io).

## Errors

<ResponseField name="400 Bad Request" field-type="error" required="false" deprecated="false">
  `domain_id` query parameter missing. Body points you at `/api/v1/domains`.
</ResponseField>

<ResponseField name="401 Unauthorized" field-type="error" required="false" deprecated="false">
  Missing, malformed, or revoked API key.
</ResponseField>

<ResponseField name="403 Forbidden" field-type="error" required="false" deprecated="false">
  Team's `developer_access` flag is off, the domain belongs to a team your API key is not scoped to, or your `allowed_domains` allowlist excludes it.
</ResponseField>

<ResponseField name="404 Not Found" field-type="error" required="false" deprecated="false">
  `domain_id` is malformed, does not exist, or your user is not a member of its team.
</ResponseField>

<ResponseField name="429 Too Many Requests" field-type="error" required="false" deprecated="false">
  Rate limit exceeded. Inspect the `Retry-After` header for how long to wait.
</ResponseField>

## Empty result

If no analyses ran in the window — or every fan-out string was filtered as an artefact — the response is a successful `200` with an empty list:

```json
{
  "data": { "items": [], "total": 0 },
  "domain_id": "8f1d3c0a-2f9b-4c11-9b80-7a82e1f0c3f3",
  "days": 30,
  "model": "all",
  "generated_at": "2026-06-17T10:00:11.218Z"
}
```
