Skip to main content
New to Exa? Try the Coding Agent Quickstart to get started in under a minute.

OpenAI recommends the Responses API for all new projects. See the Responses API section below.
OpenAI’s tool calling allows models to call functions that you define in your code. The Exa SDKs ship ready-made web search and page reading tools for OpenAI, so you don’t have to hand-write the tool schema, parse tool calls, or format Exa results yourself.

Get started

1

Install the SDKs

2

Set up your API keys

Set the EXA_API_KEY and OPENAI_API_KEY environment variables. Visit the OpenAI dashboard and the Exa dashboard to generate your API keys.

Get your Exa API key

3

Add the Exa tools to your tool loop

Pass the tools in the request’s tools list, then hand the assistant message to handle_tool_calls. It executes every Exa tool call in the message and returns the matching role: "tool" messages, ready to append to the conversation.web_search searches the web for pages the model hasn’t seen; get_contents reads pages it already has URLs for, whether from an earlier search or from the user. Register either or both.
This is one round for brevity. A real agent keeps tools on every request and repeats the handler step until the model replies without tool calls — that’s how a search result turns into a follow-up page read.Calling the factories with no arguments gives Exa’s recommended defaults: type="auto" with contents={"highlights": True} for search, and page text capped at 10,000 characters for contents.

Responses API

For the OpenAI Responses API, use the responses factory with the same handle_tool_calls helper. The handler returns function_call_output items for a follow-up request.
Chat Completions and the Responses API use different tool shapes and reject each other’s, so use the factory that matches the endpoint you’re calling.

Configuring the tools

Keyword arguments are regular Exa options, passed through when the tool runs — search options to exa.search(), contents options to exa.get_contents():
The model picks the search query and the urls to read; everything else is bound when you create the tool, so it can’t change what gets crawled or extracted. name (defaulting to "web_search" and "get_contents") and description instead override the tool definition the model sees. Use a custom name to run differently-configured Exa tools side by side, or to avoid clashes with other tools that reserve those names.

Mixing in your own tools

The handlers answer every tool call in the message: a call naming a tool they can’t resolve gets an Error: unknown tool "<name>" output instead of being dropped, so the follow-up request never omits a required tool response. If you run your own tools alongside Exa’s, replace those error outputs with your own results before the next request.

Writing the loop by hand

If you’d rather own the tool schema and execution yourself, define the tool and process the calls manually. exa.tools.web_search() and exa.tools.get_contents() give you the same provider-neutral tool specs (with a run method) for hand-rolled loops, or you can write everything from scratch:
Python
See the Python SDK specification and TypeScript SDK specification for the full search and contents options.
Last modified on September 1, 2026