List Fan-out Queries
Returns the search queries LLMs fanned out to per tracked prompt, attributed by model.
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'
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']}")
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}`);
}
}
{
"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"
}
{
"detail": "domain_id query parameter is required. List the domains this key can access with GET /api/v1/domains, then pass ?domain_id=<uuid>."
}
{
"detail": "Invalid or revoked API key"
}
{
"detail": "API access is not enabled for this team. Contact support@aiclicks.io."
}
{
"detail": "Domain not found"
}
{
"detail": "Too many requests. Please try again later."
}
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 GET /api/v1/domains to discover which domains the calling key can access.
Authorizations
Your API key formatted as Bearer ak_live_<your-key>. Create one in the dashboard under Settings → Developers.
Optional UUID for log correlation. If omitted, we generate one and echo it back in the response.
Query parameters
UUID of the domain. Find domains via GET /api/v1/domains. Omitting this returns 400.
Look-back window, 1–365. Defaults to 30. Counted as an exact window (today - days + 1), not snapped to buckets.
Filter to a single model channel. Accepts either the generic name (ChatGPT, Claude, Gemini, Perplexity, AI Overviews, AI Mode, Grok, Microsoft Copilot, Meta AI, Mistral, Qwen, DeepSeek, Naver) or the underlying model key. Defaults to all — every channel.
Optional. The UUID of one tracked prompt. If you send it, the API returns the fan-out queries for this prompt only.
Optional. If true, each fan-out query gets a cited_urls list. The list holds the URLs that the answer cited for the response that ran this query. The default is false.
Optional. If you send it, the API returns one page of prompts. data then contains items, total, page, size and total_pages. If you do not send it, the API returns all prompts. The first page is 1.
Optional. The number of prompts on each page, 1–500. The default is 100. The API uses it only when you send page.
Optional. The first day of a fixed window, in YYYY-MM-DD format. Send it with end_date. A fixed window overrides days.
Optional. The last day of a fixed window, in YYYY-MM-DD format. The window includes this day. Send it with start_date.
Optional. If true, the API ignores the cached result and calculates a new one. The new result replaces the cached one. The default is false.
Response
The list payload.
Array of prompts that produced at least one fan-out query in the window.
Number of prompts that produced at least one fan-out query. Equals items.length.
Echo of the requested domain.
Echo of the requested window.
Echo of the requested model filter.
ISO-8601 timestamp of when the server produced (or cached) this response.
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
Cached for 1 hour per request parameter set. Fresh analyses that complete inside the cache window appear after the TTL expires.
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:
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.
Errors
domain_id query parameter missing. Body points you at /api/v1/domains.
Missing, malformed, or revoked API key.
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.
domain_id is malformed, does not exist, or your user is not a member of its team.
Rate limit exceeded. Inspect the Retry-After header for how long to wait.
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:
{
"data": { "items": [], "total": 0 },
"domain_id": "8f1d3c0a-2f9b-4c11-9b80-7a82e1f0c3f3",
"days": 30,
"model": "all",
"generated_at": "2026-06-17T10:00:11.218Z"
}