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#
https://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#
| Parameter | Type | Required | Description |
|---|---|---|---|
q | string | Yes | The prompt (1–500 chars) |
gl | string | No | Country, max 5 chars (e.g. us). Best-effort country for the answer |
hl | string | No | Language, 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) |
cache | boolean | No | Default true: a repeat of the same prompt within about an hour returns the cached answer. false forces a fresh run, billed as usual |
mode | string | No | Max 20 chars. Echoed in searchParameters.mode and part of the cache key; it does not change the answer |
model | string | No | Max 40 chars. Accepted but not used: answers come from each engine's default model |
html | boolean | No | true 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#
{ "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}| Field | Description |
|---|---|
answer | The answer as plain text |
answerMarkdown | The answer as markdown when the engine provides it, otherwise the same text |
citations | The sources cited, in order: index, url, title, domain. Copilot citations also carry snippet and date |
sources | The unique cited domains, for share-of-voice counts |
citationPills | Copilot's source pills (position, label, title, url, domain); empty on the other engines |
related | Follow-up questions the engine suggested, when it shows any |
model | The model the engine reported: gemini-flash (anonymous) on Gemini, empty on ChatGPT and Copilot |
threadUrl | A link to the engine's thread when it exposes one; null on ChatGPT and Copilot |
complete | false 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 |
cached | true when the answer came from cache (also X-Cache: HIT) |
html | With 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) |
pageUrl | With 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,hlandmode, within about an hour is served from cache and billed at the full rate. Passcache=falseto force a new run. - Identical requests in flight at the same moment,
cache=falseones 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
citationscan be empty on a valid answer. html=truealways runs the engine (a snapshot is never cached), and a snapshot request is merged only with identical snapshot requests in flight.
Errors#
| Status | code | Meaning |
|---|---|---|
400 | VALIDATION_ERROR | A missing or invalid parameter, or an unknown engine |
429 | AT_CAPACITY | The engine is at capacity. Retry after Retry-After; a retry before then is refused |
403 | FEATURE_NOT_AVAILABLE | The engine is switched off on this deployment (retryable: false) |
503 | UPSTREAM_UNAVAILABLE | The 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 180async 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 onlyimport 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.