exa-py 2.22.2


pip install exa-py

  Latest version

Released: Sep 21, 2026

Project Links

Meta
Author: Exa AI
Requires Python: >=3.9

Classifiers

License
  • OSI Approved :: MIT License

Programming Language
  • Python :: 3
  • Python :: 3.9
  • Python :: 3.10
  • Python :: 3.11
  • Python :: 3.12
  • Python :: 3.13
  • Python :: 3.14
  • Python :: 3.15

Exa Python SDK

PyPI version

The official Python SDK for Exa, the web search API for AI.

Documentation | Dashboard

Install

pip install exa-py

Requires Python 3.9+

Quick Start

from exa_py import Exa

exa = Exa(api_key="your-api-key")

# Search the web
results = exa.search(
    "blog post about artificial intelligence",
    type="auto",
    contents={"highlights": True}
)

# Ask a question
response = exa.answer("What is the capital of France?")

Search

results = exa.search(
    "machine learning startups",
    contents={"highlights": True}
)
results = exa.search(
    "climate tech news",
    num_results=20,
    start_published_date="2024-01-01",
    include_domains=["techcrunch.com", "wired.com"],
    contents={"highlights": True}
)
results = exa.search(
    "What are the latest battery breakthroughs?",
    type="auto",
    system_prompt="Prefer official sources and avoid duplicate results",
    output_schema={
        "type": "object",
        "properties": {
            "summary": {"type": "string"},
            "key_companies": {"type": "array", "items": {"type": "string"}},
        },
        "required": ["summary", "key_companies"],
    },
)
print(results.output.content if results.output else None)
for chunk in exa.stream_search(
    "What are the latest battery breakthroughs?",
    type="auto",
):
    if chunk.content:
        print(chunk.content, end="", flush=True)

Search output_schema modes:

  • {"type": "text", "description": "..."}: return plain text in output.content
  • {"type": "object", ...}: return structured JSON in output.content

system_prompt and output_schema are supported on every search type. Search streaming is available via stream_search(...), which yields OpenAI-style chat completion chunks.

For type: "object", search currently enforces:

  • max nesting depth: 2
  • max total properties: 10

Deep search variants that also support additional_queries:

  • deep-lite
  • deep
  • deep-reasoning

Contents

results = exa.get_contents(
    ["https://docs.exa.ai"],
    text=True
)
results = exa.get_contents(
    ["https://arxiv.org/abs/2303.08774"],
    highlights=True
)

Answer

response = exa.answer("What caused the 2008 financial crisis?")
print(response.answer)
for chunk in exa.stream_answer("Explain quantum computing"):
    print(chunk, end="", flush=True)

Web Search and Contents tools

Use Exa as a web_search tool in an OpenAI or Anthropic loop. Call web_search() with no arguments to get Exa's recommended settings for agentic search (type="auto" and contents={"highlights": True}).

from exa_py import Exa
from openai import OpenAI

exa = Exa()
openai_client = OpenAI()

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

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

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

client = anthropic.Anthropic()
response = client.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=1024,
    messages=messages,
    tools=[exa.anthropic.web_search()],
)

Pass name (and optionally description) to rename the tool. Anthropic requires tool names to be unique, so a custom name lets the Exa tool run alongside Anthropic's built-in web_search_20250305 tool:

response = client.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=1024,
    messages=messages,
    tools=[
        exa.anthropic.web_search(name="exa_web_search"),
        {"type": "web_search_20250305", "name": "web_search", "max_uses": 5},
    ],
)

get_contents is available in the same namespaces and lets the model read pages it already has URLs for. It takes a list of URLs and accepts every Exa.get_contents option:

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

For the OpenAI Responses API, use exa.openai.responses.web_search() and the same handle_tool_calls helper. The handlers answer every tool call: calls naming a tool they can't resolve get an Error: unknown tool "<name>" output instead of being dropped, so follow-up requests stay valid. If you run other tools alongside Exa's, replace those error outputs with your own results before the next request.

Agent API

The Agent API is available without a beta header.

run = exa.agent.runs.create(
    query="Find engineering leaders at AI infrastructure companies that raised a Series A or B in the last 6 months.",
    output_schema={
        "type": "object",
        "properties": {
            "people": {
                "type": "array",
                "maxItems": 10,
                "items": {
                    "type": "object",
                    "properties": {
                        "name": {"type": "string"},
                        "contact_email": {"type": "string", "format": "email"},
                        "linkedin_url": {"type": "string", "format": "uri"},
                    },
                    "required": ["name", "linkedin_url"],
                },
            }
        },
        "required": ["people"],
    },
    effort="auto",
)

run = exa.agent.runs.poll_until_finished(run.id)
print(run.output.structured if run.output else None)

For Agent Max, use the beta namespace and pass the beta token explicitly:

from exa_py import Exa
from exa_py.agent import AGENT_MAX_EFFORT_BETA

exa = Exa()
run = exa.beta.agent.runs.create(
    query="Find all companies building browser automation tools in the United States.",
    effort="max",
    budget={"maxCostDollars": 10},
    betas=[AGENT_MAX_EFFORT_BETA],
)

Agent Monitors (Beta)

Agent Monitors use the beta namespace and require the AGENT_MONITORS_BETA_HEADER beta identifier (agent-monitors-2026-08-04).

An Agent Monitor keeps a table of entities × fields fresh on a cadence: static fields are answered once per entity over the live web, dynamic fields are tracked from news on every refresh.

from exa_py.agent import AGENT_MONITORS_BETA_HEADER

betas = [AGENT_MONITORS_BETA_HEADER]

# Create a monitor. Creation is async: it returns with status "creating"
# and becomes "active" once the first refresh completes.
monitor = exa.beta.agent.monitors.create(
    betas=betas,
    cadence="7d",
    entities=[
        {"name": "Acme Corp", "domain": "acme.com"},
        {"name": "Globex", "domain": "globex.com"},
    ],
    fields=[
        {"name": "funding", "description": "New funding rounds"},  # dynamic by default
        {"name": "ceo", "description": "The company's current CEO", "mode": "static"},
    ],
    idempotency_key="my-monitor-1",  # safe retries: same key returns the same monitor
)

# Page the monitor's current entities and their contents.
for view in exa.beta.agent.monitors.entities.list_all(monitor.id, betas=betas):
    print(view.entity.name, view.contents)

# Follow the content change feed (resume later from the page's next_cursor).
changes = exa.beta.agent.monitors.changes.list(
    monitor.id,
    betas=betas,
    since="2026-01-01T00:00:00Z",
)

# One-shot backtest of a past news window — no monitor persists.
backtest = exa.beta.agent.monitors.backtests.create_and_wait(
    betas=betas,
    entities=[{"name": "Acme Corp", "domain": "acme.com"}],
    fields=[{"name": "funding", "description": "New funding rounds"}],
    start_time="2026-01-01T00:00:00Z",
    end_time="2026-01-08T00:00:00Z",
)
print(backtest.data)

# Add entities, inspect refresh progress, clean up.
exa.beta.agent.monitors.entities.add(
    monitor.id,
    betas=betas,
    entities=[{"name": "Initech", "domain": "initech.com"}],
)
current = exa.beta.agent.monitors.get(monitor.id, betas=betas)
print(current.status, current.refresh, current.usage)
exa.beta.agent.monitors.delete(monitor.id, betas=betas)

Async

from exa_py import AsyncExa

exa = AsyncExa(api_key="your-api-key")

results = await exa.search("async search example", contents={"highlights": True})

More

See the full documentation for all features including websets, filters, and advanced options.

2.22.2 Sep 21, 2026
2.22.0 Sep 17, 2026
2.21.0 Sep 16, 2026
2.20.0 Sep 01, 2026
2.19.0 Aug 27, 2026
2.18.1 Aug 14, 2026
2.18.0 Aug 13, 2026
2.17.0 Aug 07, 2026
2.16.2 Jul 27, 2026
2.16.0 Jul 02, 2026
2.15.0 Jun 24, 2026
2.14.0 Jun 16, 2026
2.13.2 Jun 08, 2026
2.13.0 May 13, 2026
2.12.1 Apr 22, 2026
2.12.0 Apr 15, 2026
2.11.0 Apr 04, 2026
2.10.2 Mar 26, 2026
2.10.1 Mar 25, 2026
2.10.0 Mar 23, 2026
2.9.0 Mar 13, 2026
2.8.1 Mar 10, 2026
2.8.0 Mar 10, 2026
2.7.1 Mar 10, 2026
2.7.0 Mar 04, 2026
2.6.1 Feb 27, 2026
2.6.0 Feb 27, 2026
2.5.0 Feb 25, 2026
2.4.0 Feb 10, 2026
2.3.0 Feb 01, 2026
2.2.0 Jan 27, 2026
2.1.1 Jan 22, 2026
2.1.0 Jan 22, 2026
2.0.2 Dec 19, 2025
2.0.1 Nov 21, 2025
2.0.0 Oct 28, 2025
1.16.2 Apr 24, 2026
1.16.1 Oct 09, 2025
1.16.0 Oct 08, 2025
1.15.6 Sep 10, 2025
1.15.5 Sep 05, 2025
1.15.4 Aug 29, 2025
1.15.3 Aug 25, 2025
1.15.2 Aug 23, 2025
1.15.1 Aug 21, 2025
1.15.0 Aug 21, 2025
1.14.20 Jul 30, 2025
1.14.19 Jul 29, 2025
1.14.18 Jul 21, 2025
1.14.17 Jul 17, 2025
1.14.16 Jul 10, 2025
1.14.15 Jul 03, 2025
1.14.14 Jul 02, 2025
1.14.13 Jun 27, 2025
1.14.12 Jun 24, 2025
1.14.11 Jun 23, 2025
1.14.10 Jun 21, 2025
1.14.9 Jun 18, 2025
1.14.8 Jun 21, 2025
1.14.7 Jun 17, 2025
1.14.6 Jun 09, 2025
1.14.5 Jun 07, 2025
1.14.4 Jun 07, 2025
1.14.3 Jun 06, 2025
1.14.2 Jun 04, 2025
1.14.1 Jun 03, 2025
1.14.0 Jun 01, 2025
1.13.2 May 31, 2025
1.13.1 May 14, 2025
1.13.0 May 10, 2025
1.12.5 May 29, 2025
1.12.4 May 28, 2025
1.12.3 May 15, 2025
1.12.1 Apr 18, 2025
1.12.0 Apr 13, 2025
1.11.0 Apr 04, 2025
1.10.0 Mar 31, 2025
1.9.1 Mar 21, 2025
1.9.0 Mar 11, 2025
1.8.9 Feb 18, 2025
1.8.8 Feb 06, 2025
1.8.7 Jan 30, 2025
1.8.6 Jan 30, 2025
1.8.5 Jan 24, 2025
1.8.4 Jan 22, 2025
1.8.3 Jan 22, 2025
1.7.3 Jan 21, 2025
1.7.2 Jan 14, 2025
1.7.1 Dec 25, 2024
1.7.0 Nov 26, 2024
1.6.0 Nov 05, 2024
1.5.2 Nov 01, 2024
1.5.1 Oct 29, 2024
1.5.0 Oct 28, 2024
1.4.1b0 Oct 15, 2024
1.4.0 Oct 04, 2024
1.3.1b0 Oct 03, 2024
1.3.0b0 Oct 03, 2024
1.2.1 Oct 01, 2024
1.2.0 Oct 01, 2024
1.1.8 Sep 26, 2024
1.1.7 Sep 17, 2024
1.1.6 Sep 17, 2024
1.1.5 Sep 17, 2024
1.1.4 Sep 14, 2024
1.1.3 Sep 13, 2024
1.1.2 Sep 13, 2024
1.1.1 Sep 13, 2024
1.1.0 Sep 07, 2024
1.0.18 Aug 16, 2024
1.0.18b1 Aug 28, 2024
1.0.17 Jul 29, 2024
1.0.16 Jul 16, 2024
1.0.15 Jul 16, 2024
1.0.14 Jul 14, 2024
1.0.13 Jul 08, 2024
1.0.12 May 26, 2024
1.0.11 May 24, 2024
1.0.10 May 24, 2024
1.0.9 Mar 12, 2024
1.0.8 Feb 05, 2024
1.0.7 Jan 25, 2024
1.0.6 Jan 25, 2024
1.0.5 Jan 25, 2024
1.0.2 Jan 23, 2024
1.0.1 Jan 23, 2024
1.0.0 Jan 23, 2024

Wheel compatibility matrix

Platform Python 3
any

Files in release

Extras: None
Dependencies:
httpcore (>=1.0.9)
httpx (>=0.28.1)
openai (>=1.48)
pydantic (>=2.10.6)
python-dotenv (>=1.0.1)
requests (>=2.32.3)
typing-extensions (>=4.12.2)