> Searlo API Docs — AI Answers
> Source: https://searlo.tech/docs#ai-answers
> Full docs: https://searlo.tech/docs/full.md

# 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

```
GET /search/ai/{engine}
```

> `engine` is one of `chatgpt`, `copilot` or `gemini`; `GET /search/ai?engine=chatgpt` is the same route, and `GET /search/ai` without an engine asks ChatGPT. `perplexity` (paused), `aimode` (Google AI Mode) and `grok` are switched off in production: they answer `403` `FEATURE_NOT_AVAILABLE` and are not charged.

**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

```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
}
```

| 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`, `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

| 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.

## Code Examples

### cURL

```bash
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
```

### JavaScript

```javascript
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 domains
console.log(answer.citationPills); // Copilot only
```

### Python

```python
import os
import 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 parallel
for engine in ["chatgpt", "copilot", "gemini"]:
    a = ask_ai(engine, "best crm for startups")
    print(engine, "cached" if a["cached"] else "live", a["sources"])
```


---
*From https://searlo.tech/docs — see full docs at https://searlo.tech/docs/full.md*