Search

Unifies web, neural/semantic, and keyword search behind one schema: a query in, a ranked list of results out.

POST/api/v1/search

The contract is identical across providers, so you switch engines (Exa, Tavily, Serper, Brave, Linkup, …) by changing only the model string. No standard exists for search yet - this is SearchRouter's canonical shape.

Request

ParameterTypeRequiredDescription
modelstringrequiredModel slug, e.g. exa/neural. Or use models for cross-model fallback.
querystringrequiredThe search query.
search_type"web" | "neural" | "keyword" | "auto"optionalSearch mode. Defaults to auto.
num_resultsintegeroptionalNumber of results to return. Default 10.
include_contentbooleanoptionalFetch full page text where the provider supports it. Default false.
include_domainsstring[]optionalRestrict results to these domains.
exclude_domainsstring[]optionalExclude these domains from results.
start_published_datestring | nulloptionalISO 8601 lower bound on publish date.
end_published_datestring | nulloptionalISO 8601 upper bound on publish date.
providerobjectoptionalRouting preferences. See Routing.
json
{
  "model": "exa/neural",
  "query": "best vector databases for RAG 2026",
  "search_type": "auto",
  "num_results": 10,
  "include_content": false,
  "include_domains": ["arxiv.org"],
  "exclude_domains": [],
  "start_published_date": null,
  "end_published_date": null,
  "provider": {
    "order": ["exa", "tavily"],
    "allow_fallbacks": true,
    "sort": "price"
  }
}

Response

FieldTypeRequiredDescription
idstringoptionalUnique request id.
modelstringoptionalThe resolved model slug.
providerstringoptionalThe provider that actually served the request.
search_typestringoptionalThe search mode used.
resultsobject[]optionalRanked result objects (see below).
usageobjectoptional{ requests, results, cost } - cost in USD.

Result object

FieldTypeRequiredDescription
titlestringoptionalResult title.
urlstringoptionalCanonical URL.
snippetstringoptionalShort extract.
contentstring | nulloptionalFull page text when include_content is set and supported.
scorenumber | nulloptionalRelevance score, or null for providers that don't return one.
published_datestring | nulloptionalISO 8601 publish date or null.
authorstring | nulloptionalAuthor, when available.
rawobjectoptionalOriginal provider payload, for debugging.
json
{
  "id": "sr-gen-abc123",
  "model": "exa/neural",
  "provider": "exa",
  "search_type": "neural",
  "results": [
    {
      "title": "Comparing Vector Databases",
      "url": "https://example.com/vdb",
      "snippet": "A short extract...",
      "content": null,
      "score": 0.87,
      "published_date": "2025-11-02",
      "author": null,
      "raw": { }
    }
  ],
  "usage": { "requests": 1, "results": 10, "cost": 0.005 }
}
Normalization. Adapters map provider fields into this shape - Exa's text content, dates normalized to ISO 8601, and a null score for engines (Brave/Google/Linkup) that don't rank. The untouched provider payload is kept under result.raw.

Examples

cURL

bash
curl https://searchrouter.ai/api/v1/search \
  -H "Authorization: Bearer $SR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "exa/neural",
    "query": "best vector databases for RAG 2026",
    "num_results": 10
  }'

Python

python
import os, requests

resp = requests.post(
    "https://searchrouter.ai/api/v1/search",
    headers={"Authorization": f"Bearer {os.environ['SR_API_KEY']}"},
    json={
        "model": "exa/neural",
        "query": "best vector databases for RAG 2026",
        "num_results": 10,
    },
)
resp.raise_for_status()
for r in resp.json()["results"]:
    print(r["score"], r["title"], r["url"])

JavaScript

javascript
const resp = await fetch("https://searchrouter.ai/api/v1/search", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.SR_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    model: "exa/neural",
    query: "best vector databases for RAG 2026",
    num_results: 10,
  }),
});
const { results } = await resp.json();
results.forEach((r) => console.log(r.score, r.title, r.url));