Skip to main content
Exa is a web search engine built for AI agents. Venice’s web search endpoint can run your queries on Exa: set search_provider to "exa" and Venice runs the search with Exa under zero data retention. You authenticate with your Venice API key, Venice bills the search, and you don’t need an Exa account. Results come back in the same shape for every provider, so Exa slots into anything you’ve built on Venice’s default Brave search, and switching providers is a one-field change. This guide covers calling the endpoint, giving a Venice model Exa search as a tool, grounding a prompt in Exa results yourself, and when to call Exa’s own API instead.

Prerequisites

  • A Venice API key
  • Python 3.10 or later, or Node.js 22 or later
  • For the agent example, a Venice model that supports function calling. The examples use z-ai-glm-5-3-flash.

Setup

Install the OpenAI SDK, plus requests for Python. Node.js has fetch built in:
Add your Venice API key to the environment:

Search with Exa

Send a query to /augment/search with search_provider set to "exa":
The response holds the query and a list of results, each with four fields:
limit defaults to 10 and accepts 1 to 20, and query accepts 1 to 400 characters. Values outside those ranges return 400 rather than being clamped. Treat date as optional, since many pages don’t publish one. To let a model decide when and what to search, describe a web_search function in the tools array of a chat request, and run the search yourself whenever the model calls it. This program wraps the request above in a search helper, returns the results to the model as a tool message, and loops until the model answers in text:
The model only writes the query. Your code decides everything else: the provider, the number of results, and what happens when a search fails. Three details are worth keeping when you adapt the loop:
  • Truncate model-written queries. The endpoint rejects queries longer than 400 characters instead of shortening them, and models sometimes write long ones.
  • Return errors as tool results. A failed search becomes a tool message starting with Error:, so the model can try a different query or explain the failure instead of the loop crashing.
  • Append the assistant message before its tool results. Every tool message has to follow the assistant turn that requested it. Appending the message object itself also keeps reasoning_content, which reasoning models like GLM 5.3 Flash return, so the model keeps its reasoning across rounds.
Each result’s content is page text, up to about 10,000 characters, so the model can usually answer from the search results alone. When it needs a whole page, add a second tool that calls /augment/scrape, which returns the page as Markdown.

Search first, then generate

Function calling lets the model decide when and what to search. When your code already knows what to search, you can skip the tool loop: run one Exa search, number the results, and ask Venice to answer from them. This works with any Venice text model, and because you keep the list of sources that went into the prompt, every citation in the answer maps back to a URL. Using the search helper, client, and model from the previous example:
Cited Answers with Web Search extends this pattern with source selection, page scraping, and handling pages that fail to load. Its search helper takes a provider argument, so pass "exa" to run it on Exa.

Use the Exa API directly

Venice’s search endpoint takes a query and a result count. Exa’s own API has more controls: categories for news, research papers, companies, people, and financial reports, domain and date filters, query-focused highlights and full page text, and deep multi-step search. To use them, call Exa directly with an API key from the Exa dashboard. Those requests go from your application to Exa, fall under Exa’s terms rather than Venice’s, and are billed to your Exa account. Exa offers Zero Data Retention on Enterprise plans. The Exa SDKs, exa-py and exa-js 2.24.0 or later, include tools in the Chat Completions format that drop into the loop above. Replace the tool list with Exa’s tools:
Then pass each tool-calling message to the SDK instead of your own tool runner: messages += exa.openai.handle_tool_calls(message) in Python, or messages.push(...(await exa.openai.handleToolCalls(message))) in Node.js. It runs each Exa call and returns the matching tool messages, with failures reported as Error: results. Keep the page text cap, because exa-js returns whole pages without one. Keyword arguments such as category, include_domains, and start_published_date pass through to Exa’s search. See Exa’s tool calling guide for every option. Model IDs rotate. Resolve the current function-calling default at runtime with GET /models/traits, or browse the text models for others that support function calling.

Privacy

With search_provider: "exa", your application only talks to Venice, and Venice runs each search with Exa under zero data retention. Venice doesn’t store prompt or response content, and the model’s privacy tier decides what happens at the inference layer. Private models run on zero-data-retention infrastructure. The part that’s easy to miss is that the model writes search queries from the conversation, so details from a prompt can end up in a query sent to Exa. If prompts may contain personal or confidential information, tell the model in your system prompt to keep those details out of searches, or use the search-first pattern so your own code writes every query. If you call the Exa API directly, those requests go to Exa under Exa’s terms instead.

Costs

Each search costs $0.01, or $10 per 1,000, the same as a Brave or Google search. Venice bills it to your Venice account alongside the tokens your chat requests use, so there’s no separate Exa bill. Searches that fail with an error aren’t charged, but a search that comes back empty still is. Search results go back to the model as input on the next round, and because they carry page text, a five-result search often adds 5,000 to 10,000 input tokens. A few habits keep both down:
  • Lower limit when a handful of sources is enough. A search costs the same at any limit, but fewer results mean fewer input tokens on the next round.
  • Keep max_rounds low. Each extra round can add searches as well as tokens.
  • Use the search-first pattern when your code knows what to search. It runs exactly one search and one chat request.
Agents with a crypto wallet can skip the API key. /augment/search and /chat/completions both accept x402 wallet authentication, so an agent can pay for Exa searches and inference from one prepaid USDC balance.

Troubleshooting

Confirm VENICE_API_KEY is set in the process that runs your code. Without it, Python raises KeyError: 'VENICE_API_KEY', and the Node.js OpenAI SDK falls back to OPENAI_API_KEY. If that’s unset too, you get a Missing credentials error. If it’s set, the SDK sends your OpenAI key to Venice, which rejects it with 401. A 401 with VENICE_API_KEY set means Venice rejected the key itself, so check it for typos or generate a new one.
query must be 1 to 400 characters, limit must be 1 to 20, and search_provider must be brave, google, or exa. Values outside those ranges are rejected rather than clamped. In the tool loop, a rejected search reaches the model as an Error: tool result instead of raising.
Your Venice balance can’t cover the request. Requests made with an API key return INSUFFICIENT_BALANCE, so top up your Venice balance. Requests made with x402 wallet authentication return top-up instructions in the response.
Some models, including Claude and GPT models, return 400 when a tool call isn’t followed by a tool message with its tool_call_id. GLM models accept the conversation anyway, so this can first appear when you switch models. The loop answers every call right after the assistant message that made it, so keep that shape if you add tools.
Check that the model supports function calling, and say when to search in the system prompt. Models often skip the tool when they think they can answer from memory, unless you tell them to search for recent or specific facts.

Resources

Web Search API

Parameters, search providers, and the response schema

Cited Answers

A full search, scrape, and cite pipeline on Venice

Function Calling

How tool calls work on Venice

Exa Docs

Exa’s own API, SDKs, and search options