npx skills add ...
npx skills add exa-labs/agent-skills --skill build-with-exa
Build applications and agents with Exa's API: search, contents extraction, answer, Agent API, monitors, websets, OpenAI-compatible endpoints, and exa-py/exa-js SDKs. Use when choosing Exa endpoints, writing Exa API calls, integrating semantic web search or research into products, or debugging Exa request shapes.
npx skills add exa-labs/agent-skills --skill build-with-exa
Included by default:
/agent)exa-py, TypeScript exa-jsNote on data retention:
/search,/answer, and/agent/offer Zero Data Retention (ZDR). Websets and Monitors are not ZDR. If a use case requires ZDR, stay on the ZDR surfaces or contact Exa.
Install the latest SDK release with the package manager so it resolves the latest release and all SDK surfaces will be available.
Exa accepts either the x-api-key header or Authorization: Bearer <key>.
The recommended Exa search request is the query plus token-efficient content extraction, and nothing else. Content extraction is a recommendation, not a server default: omit contents and results carry only metadata (title, URL, dates), no page content.
Every other request field is gated: add it only when the user's task explicitly requires it. Do not restate server defaults, and do not add controls because they seem plausibly useful. In particular:
type defaults to auto; stating type: "auto" explicitly is fine, but do not send another mode unless the task requires it (for example a latency-critical UX or deep synthesis).numResults defaults to 10; omit numResults unless the task requires a different number of results. Set it only as an intentional product decision, not as boilerplate.category. Use it only when the user explicitly asks for category-constrained retrieval.includeDomains and excludeDomains should be set only when the user explicitly requests a hard allowlist or blocklist and supplies or approves its contents. Express source preferences through query phrasing or systemPrompt instead.maxAgeHours should be set only when extracted page content must be current. It caps cache age before a live crawl; it is not a publication-recency filter.startPublishedDate / endPublishedDate are hard filters that drop undated and misdated pages; add them only when the task states a bounded window that must be enforced ("from the last seven days", "published in 2026"). Do not reach for maxAgeHours.highlights should be set to true by default for all tasks unless otherwise specified. Do not add maxCharacters or other highlight options without an explicit budget requirement in the task.Before picking an endpoint, decide which workflow shape fits:
/search with the recommended request above/search and add outputSchema (and systemPrompt if behavior guidance is needed). The user does not have to say "JSON" or "schema": "the funding amount each article reports", "name, title, and company for each person", or a field the result must carry that result metadata only sometimes has (a required author) are all structured-output requests. Fields every result already carries (title, URL, published date) are not: "10 articles with title and URL" is the recommended request with numResults. A compact schema (author and URL per article) stays on auto; type: "deep" when the schema is wide or its fields take more than one search to fill, since it runs several. See Structured Output in references/search.md./agent), with the same outputSchema rule for its fieldsDefault to the search endpoint. Use the search endpoint (/search) for most new integrations, then move to a more specialized Exa surface only when the task shape clearly calls for it.
/search)/contents)/search) with a query derived from the page (for example title, topic, or text from /contents)/answer). If the product already has a chat LLM, give it /search as a tool instead./chat/completions, /responses)/agent)/monitors)references/migrate-websets-to-agent.md) and transition to the Agent API (references/agent.md). Do not use Websets for new work; use the Agent API instead.snapshotAsOf field on /contents (top level) or /search (inside contents). See references/snapshot.md.For more complete examples, see the relevant reference file in the table below.
Python (/search):
TypeScript (/search):
Raw HTTP (/search):
category, domain filters, boilerplate numResults, or freshness controls without an explicit task requirement is the most common integration mistake.outputSchema; keep/drop rules go in systemPrompt; query is retrieval intent only. If a clause of the query says only, include, exclude, drop, or return, it is in the wrong field. Do not add outputSchema for fields every result already carries (title, URL, published date).text, highlights, and summary belong inside contents, not at the top level.text, highlights, and summary are top-level fields, not nested inside contents.highlights, text, or summary. Do not stack them. summary requires an explicit user request for Exa-side per-result synthesis.highlights: true. numSentences and highlightsPerUrl are deprecated, and maxCharacters needs an explicit budget requirement./agent), not on /search with category: "people" or category: "company". Those categories are only for retrieving raw people or company documents.maxAgeHours controls crawl/cache freshness (how old extracted page content may be before a live crawl), not publication recency. Do not use it as a "recent results" control; recency belongs in query phrasing. startPublishedDate / endPublishedDate are for task-stated bounded windows ("the last seven days", "in 2026") that must be enforced, not for "recent" or "latest" alone.github, documentation, qa, or pdf. When a user does request category-constrained retrieval, check the search reference first: specialized categories such as people and company restrict which filters are valid./agent as a drop-in replacement for /search. It is higher-latency and async, so use the dedicated Agent reference when that workflow shape is the real fit. Prefer it over Websets for new collection-building work.effort explicitly, wait for a terminal status via polling or SSE and check how the run ended before reading output, and expose output.grounding when relevant in a product./findSimilar as deprecated. Prefer /search (optionally after /contents on the seed URL) for related-page discovery.| File | Topics |
|---|---|
| references/search.md | Search endpoint request/response shape, search types, filters, nested contents, structured output |
| references/contents.md | Contents endpoint extraction, freshness, statuses, top-level content fields |
| references/snapshot.md | Exa Snapshot: snapshotAsOf historical page versions on /contents and /search, limits, snapshot vs freshness |
| references/answer.md | Grounded answer generation with citations and structured output |
| references/agent.md | Agent API for async multi-step research, enrichment, structured output, polling, and events |
| references/openai-compat.md | OpenAI-compatible endpoints, model routing, extra_body usage |
| references/monitors.md | Standalone Monitors API for scheduled recurring search |
| references/migrate-websets-to-agent.md | Migrate Websets to the Agent API: call-site classification, request mapping, delivery rewrite, verification |
| references/sdks.md | Python and TypeScript SDK naming, methods, and shape differences |
| references/http-requests.md | Minimal raw HTTP examples across major Exa surfaces |
| references/models-and-modes.md | Search type selection, answer/research model routing, latency tradeoffs |
| references/prompting-and-patterns.md | Durable query, prompting, freshness, and output-schema patterns |
| references/common-mistakes.md | Over-specification and parameter-shape corrections |
https://exa.ai/docshttps://exa.ai/docs/llms.txthttps://exa.ai/docs/reference/searchhttps://exa.ai/docs/reference/agent-api-guidehttps://exa.ai/docs/reference/agent-api/connect/overviewhttps://exa.ai/docs/search/snapshothttps://exa.ai/docs/sdks/python-sdk-specificationhttps://exa.ai/docs/sdks/typescript-sdk-specification{
"query": "latest developments in LLMs",
"type": "auto",
"contents": { "highlights": true }
}from exa_py import Exa
exa = Exa(api_key="YOUR_EXA_API_KEY")
result = exa.search(
"latest developments in LLMs",
type="auto",
contents={"highlights": True}
)
for item in result.results:
print(item.title, item.url)import Exa from "exa-js";
const exa = new Exa();
const result = await exa.search("latest developments in LLMs", {
type: "auto",
contents: { highlights: true }
});
for (const item of result.results) {
console.log(item.title, item.url);
}curl -X POST "https://api.exa.ai/search" \
-H "Content-Type: application/json" \
-H "x-api-key: $EXA_API_KEY" \
-d '{
"query": "latest developments in LLMs",
"type": "auto",
"contents": {
"highlights": true
}
}'