AI answers

AI Answers

Answers from AI assistants and the sources they cited: ChatGPT, Microsoft Copilot and Google Gemini. Perplexity answers are paused: GET /search/ai/perplexity answers 403 FEATURE_NOT_AVAILABLE and is not charged. Each answer is generated live for your prompt, with no account history shaping it: the answer the engine's own users see.

Searlo is independent and not affiliated with OpenAI, Microsoft, Google or Perplexity.

Endpoint#

GEThttps://api.searlo.tech/api/v1/search/ai/{engine}

Credits: per answer: Gemini 4, ChatGPT 8, Copilot 8. A cached answer is billed at the full rate.

Parameters#

ParameterTypeRequiredDescription
qstringYesThe prompt (1–500 chars)
glstringNoCountry, max 5 chars (e.g. us). Best-effort country for the answer
hlstringNoLanguage, max 5 chars (e.g. en). The language to ask in. On Copilot, gl and hl become the Bing market code (e.g. en-US)
cachebooleanNoDefault true: a repeat of the same prompt within about an hour returns the cached answer. false forces a fresh run, billed as usual
modestringNoMax 20 chars. Echoed in searchParameters.mode and part of the cache key; it does not change the answer
modelstringNoMax 40 chars. Accepted but not used: answers come from each engine's default model
htmlbooleanNotrue also returns html, an HTML snapshot of the answer page, and pageUrl (default: false). Same credits. A snapshot is of its own run: it is never served from or written to the cache

Structured output (schema) is not available on this endpoint yet. Do not send it: a JSON value is rejected with 400, and a bracketed schema[field]=type is dropped.

These engines take no location beyond gl: location and uule are ignored.

Response#

JSON
{  "success": true,  "searchParameters": { "q": "best crm for startups", "type": "ai", "engine": "chatgpt", "mode": "ui", "gl": "us", "hl": "en" },  "answer": "For most early-stage startups, a free tier is enough to begin with...",  "answerMarkdown": "For most early-stage startups, a **free tier** is enough to begin with...",  "citations": [    { "index": 1, "url": "https://www.example.com/best-crm-startups", "title": "The best CRMs for startups", "domain": "example.com" },    { "index": 2, "url": "https://blog.example.org/crm-guide", "title": "Choosing a CRM", "domain": "blog.example.org" }  ],  "sources": ["example.com", "blog.example.org"],  "citationPills": [],  "related": ["Which CRM is free for small teams?"],  "model": "",  "threadUrl": null,  "complete": true,  "via": "dom",  "fetchedAt": "2026-09-29T10:00:00.000Z",  "source": "searlo.tech(chatgpt)",  "cached": false}
FieldDescription
answerThe answer as plain text
answerMarkdownThe answer as markdown when the engine provides it, otherwise the same text
citationsThe sources cited, in order: index, url, title, domain. Copilot citations also carry snippet and date
sourcesThe unique cited domains, for share-of-voice counts
citationPillsCopilot's source pills (position, label, title, url, domain); empty on the other engines
relatedFollow-up questions the engine suggested, when it shows any
modelThe model the engine reported: gemini-flash (anonymous) on Gemini, empty on ChatGPT and Copilot
threadUrlA link to the engine's thread when it exposes one; null on ChatGPT and Copilot
completefalse when the answer was still streaming at the deadline, or (Copilot) when its text stops mid-sentence, so it may be cut short. Incomplete answers are never cached
cachedtrue when the answer came from cache (also X-Cache: HIT)
htmlWith html=true: an HTML snapshot of the answer page (the rendered DOM, not a screenshot). On Copilot it is the answer frame's document. Stylesheets and scripts stay linked, not inlined. Hundreds of KB to about 2 MB (Gemini)
pageUrlWith html=true: the page's URL at that moment, for resolving its relative links

Responses also set X-AI-Engine.

Latency, Caching and Variance#

  • A live answer typically takes 10–30 seconds. Set a generous client timeout.
  • Answers are non-deterministic: the same prompt can return different text and different citations from one run to the next. That variance is part of what you are measuring.
  • A repeat of the same prompt (ignoring case and extra spaces) on the same engine, with the same gl, hl and mode, within about an hour is served from cache and billed at the full rate. Pass cache=false to force a new run.
  • Identical requests in flight at the same moment, cache=false ones included, are merged into one run: every call is billed and all of them get the same answer. Parallel identical calls are not independent samples, so space your samples out.
  • ChatGPT and Gemini show sources only when they searched the web, so citations can be empty on a valid answer.
  • html=true always runs the engine (a snapshot is never cached), and a snapshot request is merged only with identical snapshot requests in flight.

Errors#

StatuscodeMeaning
400VALIDATION_ERRORA missing or invalid parameter, or an unknown engine
429AT_CAPACITYThe engine is at capacity. Retry after Retry-After; a retry before then is refused
403FEATURE_NOT_AVAILABLEThe engine is switched off on this deployment (retryable: false)
503UPSTREAM_UNAVAILABLEThe engine returned something unusable (retryable: true, short Retry-After). Try again shortly

Failed calls are refunded.

Examples

curl "https://api.searlo.tech/api/v1/search/ai/chatgpt?q=best+crm+for+startups&gl=us&hl=en" \  -H "x-api-key: sk_your_api_key" \  --max-time 180 # Force a fresh run instead of the cached answer (billed)curl "https://api.searlo.tech/api/v1/search/ai/chatgpt?q=best+crm+for+startups&cache=false" \  -H "x-api-key: sk_your_api_key" \  --max-time 180
async function askAi(engine, prompt, { gl = "us", hl = "en", cache = true } = {}) {  const params = new URLSearchParams({ q: prompt, gl, hl, cache: String(cache) });  const res = await fetch(    `https://api.searlo.tech/api/v1/search/ai/${engine}?${params}`,    {      headers: { "x-api-key": process.env.SEARLO_API_KEY },      signal: AbortSignal.timeout(180_000), // live answers take 10-30 s, sometimes longer    }  );  if (res.status === 429) {    throw new Error(`${engine} at capacity, retry after ${res.headers.get("retry-after")}s`);  }  return res.json();} const answer = await askAi("copilot", "best crm for startups");console.log(answer.answer);console.log(answer.sources);       // unique cited domainsconsole.log(answer.citationPills); // Copilot only
import osimport requests def ask_ai(engine, prompt, gl="us", hl="en", cache=True):    r = requests.get(        f"https://api.searlo.tech/api/v1/search/ai/{engine}",        params={"q": prompt, "gl": gl, "hl": hl, "cache": str(cache).lower()},        headers={"x-api-key": os.environ["SEARLO_API_KEY"]},        timeout=180,    )    r.raise_for_status()    return r.json() # One sample per engine, run one after another rather than in parallelfor engine in ["chatgpt", "copilot", "gemini"]:    a = ask_ai(engine, "best crm for startups")    print(engine, "cached" if a["cached"] else "live", a["sources"])

Stuck? Write to [email protected], or check live status.