> ## Documentation Index
> Fetch the complete documentation index at: https://exa.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> The Exa API is served at https://api.exa.ai. Authenticate with `Authorization: Bearer $EXA_API_KEY` (or `x-api-key: $EXA_API_KEY`); create keys at https://dashboard.exa.ai/api-keys?utm_source=docs&utm_medium=docs&utm_campaign=markdown_instructions. Every way an agent can get access to Exa is described at https://exa.ai/auth.md.
> Prefer the official SDKs, `exa-py` (`pip install exa-py`) and `exa-js` (`npm install exa-js`); both read `EXA_API_KEY` from the environment.
> Tool-using agents can call Exa without writing code through the hosted MCP server at https://mcp.exa.ai/mcp, or install the Exa agent skill with `npx skills add exa-labs/agent-skills` (skill file: https://exa.ai/docs/skill.md).
> The OpenAPI specs at https://exa.ai/docs/exa-spec.yaml and https://exa.ai/docs/team-management-spec.yaml are the source of truth for request and response schemas.

# Start building with Exa

> A powerful web search tool designed for agents. Everything optimized to get you token-efficient, accurate results.

Get an API key at [dashboard.exa.ai/api-keys](https://dashboard.exa.ai/api-keys?utm_source=docs\&utm_medium=docs\&utm_campaign=home) and export it as `EXA_API_KEY`; the SDKs and the examples below read it from the environment. Start with the [quickstart](https://exa.ai/docs/get-started/quickstart.md), or connect an agent directly to the hosted [Exa MCP server](https://exa.ai/docs/get-started/exa-mcp.md).

## Examples

### Search the web

```python theme={null}
from exa_py import Exa

exa = Exa()

result = exa.search(
    "companies selling AI voice agents to dental practices",
    contents={"highlights": True},
)

for hit in result.results:
    print(hit.title, hit.url)
    print(hit.highlights)
```

```javascript theme={null}
import Exa from "exa-js";

const exa = new Exa();

const result = await exa.search(
  "companies selling AI voice agents to dental practices",
  { contents: { highlights: true } },
);

for (const hit of result.results) {
  console.log(hit.title, hit.url);
  console.log(hit.highlights);
}
```

```bash theme={null}
curl -s -X POST "https://api.exa.ai/search" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $EXA_API_KEY" \
  -d '{
    "query": "companies selling AI voice agents to dental practices",
    "contents": { "highlights": true }
  }'
```

### Get page contents

```python theme={null}
from exa_py import Exa

exa = Exa()

result = exa.get_contents(
    ["https://www.anthropic.com/pricing"],
    highlights={"query": "enterprise plan features and pricing"},
)

print(result.results[0].highlights)
```

```javascript theme={null}
import Exa from "exa-js";

const exa = new Exa();

const result = await exa.getContents(
  ["https://www.anthropic.com/pricing"],
  {
    highlights: {
      query: "enterprise plan features and pricing",
    },
  },
);

console.log(result.results[0].highlights);
```

```bash theme={null}
curl -s -X POST "https://api.exa.ai/contents" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $EXA_API_KEY" \
  -d '{
    "ids": ["https://www.anthropic.com/pricing"],
    "highlights": {
      "query": "enterprise plan features and pricing"
    }
  }'
```

### Get structured output

```python theme={null}
from exa_py import Exa

exa = Exa()

result = exa.search(
    "Who is Anthropic's CEO, when was the company founded, and where is it headquartered?",
    type="deep",
    output_schema={
        "type": "object",
        "required": ["company", "ceo", "founded_year", "headquarters"],
        "properties": {
            "company": {"type": "string"},
            "ceo": {"type": "string"},
            "founded_year": {"type": "number"},
            "headquarters": {"type": "string"},
        },
    },
)

print(result.output.content)
```

```javascript theme={null}
import Exa from "exa-js";

const exa = new Exa();

const result = await exa.search(
  "Who is Anthropic's CEO, when was the company founded, and where is it headquartered?",
  {
    type: "deep",
    outputSchema: {
      type: "object",
      required: ["company", "ceo", "founded_year", "headquarters"],
      properties: {
        company: { type: "string" },
        ceo: { type: "string" },
        founded_year: { type: "number" },
        headquarters: { type: "string" },
      },
    },
  },
);

console.log(result.output?.content);
```

```bash theme={null}
curl -s -X POST "https://api.exa.ai/search" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $EXA_API_KEY" \
  -d '{
    "query": "Who is Anthropic'\''s CEO, when was the company founded, and where is it headquartered?",
    "type": "deep",
    "outputSchema": {
      "type": "object",
      "required": ["company", "ceo", "founded_year", "headquarters"],
      "properties": {
        "company": { "type": "string" },
        "ceo": { "type": "string" },
        "founded_year": { "type": "number" },
        "headquarters": { "type": "string" }
      }
    }
  }'
```

### Give an LLM web search

```python theme={null}
from exa_py import Exa
from openai import OpenAI

exa = Exa()
openai = OpenAI()

messages = [{"role": "user", "content": "What's the latest on AI chips?"}]

completion = openai.chat.completions.create(
    model="gpt-5.6",
    messages=messages,
    tools=[exa.openai.web_search(), exa.openai.get_contents()],
)

message = completion.choices[0].message
messages.append(message)
messages += exa.openai.handle_tool_calls(message)

completion = openai.chat.completions.create(model="gpt-5.6", messages=messages)

print(completion.choices[0].message.content)
```

```javascript theme={null}
import Exa from "exa-js";
import { OpenAI } from "openai";

const exa = new Exa();
const openai = new OpenAI();

const messages = [{ role: "user", content: "What's the latest on AI chips?" }];

let completion = await openai.chat.completions.create({
  model: "gpt-5.6",
  messages,
  tools: [exa.openai.webSearch(), exa.openai.getContents()],
});

const message = completion.choices[0].message;
messages.push(message, ...(await exa.openai.handleToolCalls(message)));

completion = await openai.chat.completions.create({ model: "gpt-5.6", messages });

console.log(completion.choices[0].message.content);
```

```bash theme={null}
# 1. Offer the model an Exa search tool and let it pick the query.
USER_MSG='{ "role": "user", "content": "What'\''s the latest on AI chips?" }'
TOOLS='[{ "type": "function", "function": {
  "name": "web_search",
  "description": "Search the web and return the most relevant pages.",
  "parameters": { "type": "object", "properties": { "query": { "type": "string" } }, "required": ["query"] }
}}]'
ASSISTANT="$(curl -s "https://api.openai.com/v1/chat/completions" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d "{ \"model\": \"gpt-5.6\", \"messages\": [$USER_MSG], \"tools\": $TOOLS }" \
  | python3 -c 'import json,sys; print(json.dumps(json.load(sys.stdin)["choices"][0]["message"]))')"

# 2. Run the tool call against Exa.
SEARCH_BODY="$(echo "$ASSISTANT" | python3 -c '
import json, sys
args = json.loads(json.load(sys.stdin)["tool_calls"][0]["function"]["arguments"])
print(json.dumps({"query": args["query"], "contents": {"highlights": True}}))')"
RESULTS="$(curl -s -X POST "https://api.exa.ai/search" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $EXA_API_KEY" \
  -d "$SEARCH_BODY")"

# 3. Hand the results back to the model for the final answer.
TOOL_MSG="$(echo "$ASSISTANT" | python3 -c '
import json, sys
assistant = json.load(sys.stdin)
print(json.dumps({"role": "tool", "tool_call_id": assistant["tool_calls"][0]["id"], "content": sys.argv[1]}))' "$RESULTS")"
curl -s "https://api.openai.com/v1/chat/completions" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d "{ \"model\": \"gpt-5.6\", \"messages\": [$USER_MSG, $ASSISTANT, $TOOL_MSG] }" \
  | python3 -c 'import json,sys; print(json.load(sys.stdin)["choices"][0]["message"]["content"])'
```

### Build a researched list

```python theme={null}
import json
from exa_py import Exa

exa = Exa()

run = exa.agent.runs.create(
    query="Find 10 seed-stage companies building infrastructure for AI coding agents.",
    output_schema={
        "type": "object",
        "required": ["companies"],
        "properties": {
            "companies": {
                "type": "array",
                "maxItems": 10,
                "items": {
                    "type": "object",
                    "required": ["name", "website"],
                    "properties": {
                        "name": {"type": "string"},
                        "website": {"type": "string", "format": "uri"},
                    },
                },
            }
        },
    },
    effort="auto",
)

run = exa.agent.runs.poll_until_finished(run.id)

print(json.dumps(run.output.structured if run.output else None, indent=2))
```

```javascript theme={null}
import Exa from "exa-js";

const exa = new Exa();

const run = await exa.agent.runs.create({
  query:
    "Find 10 seed-stage companies building infrastructure for AI coding agents.",
  outputSchema: {
    type: "object",
    required: ["companies"],
    properties: {
      companies: {
        type: "array",
        maxItems: 10,
        items: {
          type: "object",
          required: ["name", "website"],
          properties: {
            name: { type: "string" },
            website: { type: "string", format: "uri" },
          },
        },
      },
    },
  },
  effort: "auto",
});

const completedRun = await exa.agent.runs.pollUntilFinished(run.id);

console.log(JSON.stringify(completedRun.output?.structured, null, 2));
```

```bash theme={null}
RUN_ID="$(curl -s -X POST "https://api.exa.ai/agent/runs" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $EXA_API_KEY" \
  -d '{
    "query": "Find 10 seed-stage companies building infrastructure for AI coding agents.",
    "effort": "auto",
    "outputSchema": {
      "type": "object",
      "required": ["companies"],
      "properties": {
        "companies": {
          "type": "array",
          "maxItems": 10,
          "items": {
            "type": "object",
            "required": ["name", "website"],
            "properties": {
              "name": { "type": "string" },
              "website": { "type": "string", "format": "uri" }
            }
          }
        }
      }
    }
  }' | python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])')"

while true; do
  RUN_JSON="$(curl -s "https://api.exa.ai/agent/runs/$RUN_ID" \
    -H "Authorization: Bearer $EXA_API_KEY")"
  STATUS="$(printf '%s' "$RUN_JSON" | python3 -c 'import json,sys; print(json.load(sys.stdin)["status"])')"

  if [ "$STATUS" = "completed" ]; then
    printf '%s' "$RUN_JSON" | python3 -c 'import json,sys; print(json.dumps(json.load(sys.stdin)["output"]["structured"], indent=2))'
    break
  elif [ "$STATUS" = "failed" ] || [ "$STATUS" = "cancelled" ]; then
    printf '%s' "$RUN_JSON"
    break
  fi

  sleep 4
done
```

### Analyze a complex topic

```python theme={null}
from exa_py import Exa

exa = Exa()

run = exa.agent.runs.create(
    query=(
        "Analyze how the EU AI Act affects startups selling AI products in Europe. "
        "Cover key dates, obligations, and practical risks, citing official sources."
    ),
    effort="medium",
)

run = exa.agent.runs.poll_until_finished(run.id)

print(run.output.text if run.output else None)
```

```javascript theme={null}
import Exa from "exa-js";

const exa = new Exa();

const run = await exa.agent.runs.create({
  query:
    "Analyze how the EU AI Act affects startups selling AI products in Europe. Cover key dates, obligations, and practical risks, citing official sources.",
  effort: "medium",
});

const completedRun = await exa.agent.runs.pollUntilFinished(run.id);

console.log(completedRun.output?.text);
```

```bash theme={null}
RUN_ID="$(curl -s -X POST "https://api.exa.ai/agent/runs" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $EXA_API_KEY" \
  -d '{
    "query": "Analyze how the EU AI Act affects startups selling AI products in Europe. Cover key dates, obligations, and practical risks, citing official sources.",
    "effort": "medium"
  }' | python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])')"

while true; do
  RUN_JSON="$(curl -s "https://api.exa.ai/agent/runs/$RUN_ID" \
    -H "Authorization: Bearer $EXA_API_KEY")"
  STATUS="$(printf '%s' "$RUN_JSON" | python3 -c 'import json,sys; print(json.load(sys.stdin)["status"])')"

  if [ "$STATUS" = "completed" ]; then
    printf '%s' "$RUN_JSON" | python3 -c 'import json,sys; print(json.load(sys.stdin)["output"]["text"])'
    break
  elif [ "$STATUS" = "failed" ] || [ "$STATUS" = "cancelled" ]; then
    printf '%s' "$RUN_JSON"
    break
  fi

  sleep 4
done
```

## Available APIs

* [Search](https://exa.ai/docs/search/quickstart.md): real-time, grounded data with token-efficient page contents
* [Agent](https://exa.ai/docs/agent/quickstart.md): async agents for deep research, list building, and enrichment
* [Deep Search](https://exa.ai/docs/search/deep-search.md): search that reasons across sources and returns structured output
* [Contents](https://exa.ai/docs/contents/quickstart.md): full text, highlights, and summaries from any URL
