endpoint
POST /v1/fanout
Takes a question someone would ask an AI assistant and returns the web searches that assistant is likely to run before answering it. One question in, a list of searches out. This is the endpoint to use.
It is for generative-engine optimisation: the searches a question triggers are the searches your page has to rank for to be cited in the answer. Query Fanout 1 was fitted on 3,217 searches actually observed from ChatGPT, Claude and Gemini, so the output is a distribution of likely searches rather than a guess from a larger model.
Request
curl https://meragpt.com/v1/fanout \
-H "Authorization: Bearer $MERAGPT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "query-fanout-1",
"question": "What are the best project management tools available right now?"
}'| field | type | notes |
|---|---|---|
question | string | Required. One question, up to 2000 characters. This is a bound on the shape of the input, not the context window — the model takes a question, not a document. |
model | string | Optional, defaults to query-fanout-1. |
brands | string[] | Optional, first 12 used. The brands you already know compete in this category. Worth +0.011 coverage — small, but it survived cross-validation, and it costs nothing when you already know your competitors. |
category | string | Optional. Names what the brands are, so the hint reads Known project management tools: .... Ignored when brands is absent; defaults to the word brands. |
With the hint, in Python:
import os, requests
res = requests.post(
"https://meragpt.com/v1/fanout",
headers={"Authorization": f"Bearer {os.environ['MERAGPT_API_KEY']}"},
json={
"question": "What are the best project management tools available right now?",
"category": "project management tools",
"brands": ["Asana", "Linear", "Jira", "Monday.com"],
},
timeout=60,
)
res.raise_for_status()
for q in res.json()["queries"]:
print(q)Response
{
"object": "fanout",
"model": "query-fanout-1",
"question": "What are the best project management tools available right now?",
"queries": [
"best project management software 2026",
"project management tool comparison pricing",
"Asana vs Linear vs Jira",
"project management software reviews small teams"
],
"usage": {
"input_tokens": 34,
"output_tokens": 42,
"total_tokens": 76,
"cost_usd": "$0.000008"
},
"balance_usd": "$9.99",
"limits": { "max_queries": 6, "max_question_chars": 2000 }
}queries is ordered as the model produced it, and it is not padded. 6 is the cap, not the answer: near-duplicates are dropped after generation, because 6 ways of phrasing one search is worth nothing to you. The mean across the evaluation set is 4.2 queries. There is no streaming here — the list is deduplicated as a whole, so nothing can be emitted honestly before generation finishes.
Limits
| limit | value |
|---|---|
| Question | 2000 characters |
| Brands in the hint | 12, extras ignored |
| Queries returned | Up to 6 |
| Context window | 4,096 tokens, prompt and completion together |
| Generated tokens | 160 — a fan-out is a handful of short queries, not an essay |
Sampling is fixed at temperature 0.7, and this is the one model here that is not greedy. Greedy decoding collapses a set of searches into one search written 6 ways. Sampled and deduplicated, the spread inside one returned set measures 0.364: real engine fan-outs measure 0.394. The same question can therefore return a different list on a second call.
Errors
In the shared OpenAI envelope, alongside the auth, credit and capacity codes on the errors page:
| status | code | meaning |
|---|---|---|
| 400 | missing_question | No non-empty question string in the body. |
| 400 | input_too_large | The question was over 2000 characters. The message names its length. |
| 400 | wrong_endpoint_for_model | A rewrite model was named here. Pointing the Restyler at this endpoint would return a plausible-looking blob rather than an error, so it is refused instead of served badly. Use /v1/restyle for it. |
| 502 | empty_generation | The model returned nothing usable for that question. Worth one retry, and worth rephrasing after that. |
Through an OpenAI client
/v1/chat/completions also serves this model: name query-fanout-1, put the question in the last user message, and the searches come back newline-joined in the message content, with the structured list under meragpt.queries. Use it when you already have OpenAI client code. Prefer this endpoint otherwise — it returns a real array, and brands and category have nowhere to go in the chat envelope.
Cost
Billed on the tokens actually processed, at the rate on the model page. A fan-out is one short generation, so a call is a small fraction of a cent. A request that fails before the model generates anything is not charged.
What it will not do
Uses this model does not support at all:
- Telling you exactly what ChatGPT or Gemini will search. Ask the same engine twice and it writes different queries both times, so nobody can promise you that, us included. Treat the output as the ground a question covers.
- Keyword volume, difficulty or ranking data. You get the searches themselves and nothing about how valuable they are.
- Questions with no buying intent. We trained it on how people shop across forty commercial categories.
And what it does imperfectly, from the published evaluation:
- Expect the right territory rather than the exact wording. Engines rewrite their queries every time they answer, so nothing can match one run word for word and still match the next.
- Check any brand name it gives you. At this size the model will sometimes invent a competitor that sounds plausible and does not exist.
- We trained it on buyer questions in forty commercial categories. Support, medical, legal and local-services questions are untested.
The measured numbers behind those are on the model page.