Search
Exa-compatible web search with page Markdown, highlights and a query-pruned context per result, up to 25 results for 1 credit.
POST/v1/search
Try itCredits: 1Also at: /search, /exa/search
Exa-compatible search. Pass contents (text, highlights, pruned_context) to get page Markdown, highlights and a query-pruned context per result, included in the 1 credit; without contents, results carry no page text. Accepts camelCase or snake_case.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| query | body | string | yes | Search query, up to 2,000 characters. |
| numResults / num_results | body | int | no | Default 10, capped at 25. |
| type | body | string | no | Any Exa search type is accepted; all run the same pipeline. |
| includeDomains / include_domains | body | string[] | no | Only return results from these domains. |
| excludeDomains / exclude_domains | body | string[] | no | Never return results from these domains. |
| startPublishedDate / start_published_date | body | ISO date | no | Only results published on or after this date. |
| contents | body | object | bool | no | text, highlights and pruned_context (or prunedContext), each true/false or an options object as Exa SDKs send it. Omit it and results have no text, highlights or prunedContext. |
Example request
curl -s https://api.contextfetch.dev/v1/search \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"vector database benchmarks 2026","numResults":3,"contents":{"text":true,"highlights":true,"pruned_context":true}}'# pip install exa-pyfrom exa_py import Exa exa = Exa(api_key="YOUR_API_KEY", base_url="https://api.contextfetch.dev") res = exa.search( "vector database benchmarks 2026", num_results=5, contents={"text": True, "highlights": True},)for r in res.results: print(r.url, r.highlights)// npm i exa-jsimport Exa from "exa-js"; const exa = new Exa("YOUR_API_KEY", "https://api.contextfetch.dev"); const res = await exa.search("vector database benchmarks 2026", { numResults: 5, contents: { text: true, highlights: true },});for (const r of res.results) console.log(r.url, r.highlights);Example response
{
"requestId": "4f9d2c0e8b5a4b0f9a1e6c2d7b3f8a10",
"results": [
{
"id": "0b6f3c1e-5d2a-5f4b-9c8e-7a1d2e3f4b5c",
"url": "https://example.com/blog/vector-database-benchmarks",
"title": "Vector database benchmarks",
"score": 0.93,
"publishedDate": "2026-02-11",
"text": "# Vector database benchmarks\n\nWe measured recall and p99 latency for...",
"highlights": ["We measured recall and p99 latency for..."],
"highlightScores": [0.97],
"prunedContext": "We measured recall and p99 latency for..."
}
],
"costDollars": {"total": 0.001},
"searchTimeMs": 412,
"contextfetch": {"cache": "miss", "timingsMs": {...}, "tokens": {...}, "sources": {...}}
}Response headers
| Header | Meaning |
|---|---|
| X-Credits-Remaining | On every billable response: free requests left today for keyless calls, credits left for a paid key. |
Errors
| Status | Body | When |
|---|---|---|
| 401 | {"error": "invalid_api_key"} | The key is unknown. |
| 402 | {"error": "insufficient_credits" | "keyless_limit", "message": "...", "checkout_url": "...", "pricing": {...}, "packs": [...], "action": {"type": "payment_link", "url": "https://api.contextfetch.dev/buy/instant", "prompt_to_user": "..."}} | Out of credits, or the keyless allowance is used up. Also sends X-Payment-URL. |
| 422 | - | Request validation failed, e.g. a query over 2,000 characters or a threshold outside 100 to 100,000. |
| 503 | {"error": "recall_unavailable", "message": "..."} | Web search backends are down; retry shortly. |
Responses also carry a contextfetch field with cache state, stage timings and token counts: response field.