Skip to main content
For AI agents: a documentation index is available at https://docs.parallel.ai/llms.txt. The full text of all docs is at https://docs.parallel.ai/llms-full.txt. You may also fetch any page as Markdown by appending .md to its URL or sending Accept: text/markdown.
This guide maps the request you make today to its Parallel Search equivalent. Parallel Search takes keyword search_queries, plus an optional natural language objective, and returns ranked, LLM-optimized excerpts in a single call. search_queries is the only required field, so most migrations are a one-field change. Picking a mode is optional; requests default to advanced.
Coming fromClosest Parallel equivalent
Exa instant or fastSearch with mode: "turbo"
Exa autoSearch with mode: "basic"
Exa deep-lite or deepTask API or Chat API (synthesized output)
Exa deep-reasoningTask API
Tavily fast or ultra-fastSearch with mode: "turbo"
Tavily basicSearch with mode: "basic"
Tavily advancedSearch with mode: "advanced"
SERP APISearch with mode: "turbo" or "basic" (one call, ranked excerpts)
Built-in model search (e.g. OpenAI web_search)Search as a function tool, any mode (OpenAI, Anthropic)

Start with one field

Exa, Tavily, and SERP APIs all center on a single query string. The fastest migration is to pass that string as one entry in search_queries. That alone is a complete, valid request, since mode is optional and defaults to advanced:
{ "search_queries": ["latest developments in solid state batteries"] }
For the lowest latency and cost, add "mode": "turbo". For better results, also add an optional objective, a natural language description of your full intent, and split the query into 2-3 short keyword queries:
{
  "objective": "Latest developments in solid state batteries. Focus on manufacturing progress and commercialization timelines.",
  "search_queries": ["solid state battery progress", "solid state battery commercialization"],
  "mode": "turbo"
}
See Best Practices for how to write objectives and queries.

From Exa

Exa parameterParallel equivalent
querysearch_queries (the only required field); optionally add an objective describing your full intent
type: "instant" or "fast"mode: "turbo"
type: "auto"mode: "basic"
type: "deep-lite" or "deep"Use the Task API or Chat API (both return synthesized output)
type: "deep-reasoning"Use the Task API
numResultsadvanced_settings.max_results
additionalQueriesAdd them as extra entries in search_queries; Parallel searches multiple queries in one call
includeDomains / excludeDomainsadvanced_settings.source_policy.include_domains / exclude_domains
startPublishedDateadvanced_settings.source_policy.after_date (YYYY-MM-DD)
userLocationadvanced_settings.location (ISO 3166-1 alpha-2 country code)
contents.text (full page text)Search returns compressed excerpts, not full page bodies. For full page contents, use the Extract API
category: "company" or "people"Consider Entity Search
outputSchema / summaryStructured, synthesized outputs are the Task API or Chat API
Before and after:
curl https://api.exa.ai/search \
  -H "x-api-key: $EXA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "latest developments in solid state batteries",
    "type": "fast",
    "numResults": 10,
    "contents": { "text": { "maxCharacters": 1500 } }
  }'
curl https://api.parallel.ai/v1/search \
  -H "x-api-key: $PARALLEL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "search_queries": ["latest developments in solid state batteries"],
    "mode": "turbo"
  }'
Excerpts are on by default and sized dynamically, so most requests need no excerpt configuration at all. Add advanced_settings knobs only when you have a specific product constraint. Restrictive settings can reduce result quality.

From Tavily

Tavily’s search_depth tiers map one-to-one onto Parallel modes.
Tavily parameterParallel equivalent
querysearch_queries (the only required field); optionally add an objective describing your full intent
search_depth: "fast" or "ultra-fast"mode: "turbo"
search_depth: "basic"mode: "basic"
search_depth: "advanced"mode: "advanced"
max_resultsadvanced_settings.max_results
include_domains / exclude_domainsadvanced_settings.source_policy.include_domains / exclude_domains
start_dateadvanced_settings.source_policy.after_date (YYYY-MM-DD). Tavily time_range (relative, e.g. week) has no direct equivalent; convert to an absolute date first
countryadvanced_settings.location (ISO 3166-1 alpha-2; convert Tavily’s country name to a code)
topic: "news" or "finance"State the focus in your objective (for example “recent news about…” or “latest financial results for…”)
include_answerSearch returns excerpts for your model to reason over. For grounded completions, use the Chat API
include_raw_contentFull page contents are the Extract API
Before and after:
curl https://api.tavily.com/search \
  -H "Authorization: Bearer $TAVILY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "latest developments in solid state batteries",
    "search_depth": "fast",
    "max_results": 10
  }'
curl https://api.parallel.ai/v1/search \
  -H "x-api-key: $PARALLEL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "search_queries": ["latest developments in solid state batteries"],
    "mode": "turbo"
  }'
Parallel authenticates with an x-api-key header rather than Authorization: Bearer, so a request that keeps the Tavily-style Bearer header returns 401.

From a SERP API

A SERP API returns a ranked list of links and snippets, but you must make subsequent fetches to extract usable information. Parallel Search combines everything into a single call. Instead of links you fetch and process, you get ranked, compressed excerpts sized for a model, so there is no fetch round and no chunking or ranking to build yourself. If a workflow still needs a specific page’s full contents, use the Extract API.
You search, then fetch and process each result in your own code:
import os, requests
from bs4 import BeautifulSoup
# split_into_chunks() and rank_by_relevance() are helpers you write and maintain

query = "solid state battery developments"

# Step 1: search returns links + snippets, no page content
hits = requests.get("https://serpapi.com/search", params={
    "q": query, "api_key": os.environ["SERPAPI_KEY"],
}).json()["organic_results"][:10]

# Step 2: fetch every result URL yourself, one at a time
pages = []
for h in hits:
    try:
        html = requests.get(h["link"], timeout=10).text
    except requests.RequestException:
        continue  # dead links, timeouts, bot blocks: your problem to handle
    text = BeautifulSoup(html, "html.parser").get_text(" ", strip=True)
    # (a scraper that returns markdown lets you skip this HTML parsing)
    pages.append(text)

# Step 3: chunk and rank locally so it fits the model context
chunks = [c for p in pages for c in split_into_chunks(p)]
context = rank_by_relevance(chunks, query)[:15]
Parallel does it in one call:
import os
from parallel import Parallel

client = Parallel(api_key=os.environ["PARALLEL_API_KEY"])

# one call returns ranked, model-ready excerpts
search = client.search(search_queries=["solid state battery developments"], mode="turbo")
context = [ex for r in search.results for ex in r.excerpts]
“Built-in model search” splits into two cases that migrate differently. Building on the API. If you call a provider’s hosted search tool in your own app (for example OpenAI’s web_search in the Responses API), the provider runs the search inside its own walls. Migrate by registering Parallel Search as a function tool your app executes, which gives you mode control (Turbo today), the excerpts, and the provider choice.
def search_web(search_queries: list[str], objective: str | None = None) -> dict:
    return parallel_client.search(
        search_queries=search_queries,
        objective=objective,
        mode="turbo",
    )
The model decides when to search. Your handler decides how. Full walkthroughs with the tool schema and the tool-result loop live on the OpenAI, Anthropic, and Ollama pages. Inside the ChatGPT app (no code). If you rely on web search in ChatGPT itself rather than building on the API, add Parallel as a connector through the Search MCP.

What you parse now

Parallel returns a results array. Each item has a url, title, publish_date, and excerpts (the compressed, relevant snippets your model reads), with a top-level warnings field worth checking on early calls:
{
  "results": [
    { "url": "https://...", "title": "...", "publish_date": null, "excerpts": ["..."] }
  ],
  "warnings": null
}
If your current integration expects a field Search does not return, here is where that capability lives:
If your integration expectsWith Parallel SearchNext step
a relevance score to sort onresults come back already rankedpreserve the returned order; there is no per-result score
full page text (Exa text, Tavily raw_content)you get compressed excerpts, not full page bodiesuse the Extract API for full contents
a synthesized answer or report (Tavily include_answer, Exa summary / deep)Search returns excerpts for your model to reason overuse the Chat API for grounded answers, or the Task API for multi-step research
a list of people or companies (Exa category)Search retrieves pages and excerpts across the webuse Entity Search
imagesnot returned

Verify your migration

Before moving production traffic, run your top queries in the Playground and start with the mapped mode. On your first calls, check the response warnings field for any parameters that were adjusted or ignored, and confirm Pricing and Rate Limits for your volume.