How do I migrate from the Brave Search API?

Grounder's Brave-shaped endpoint honors q, count, freshness and search_lang; offset, Goggles, extra_snippets and news search are not supported.

Last checked

To keep your Brave code, change https://api.search.brave.com/res/v1/web/search to https://api.grounder.net/compat/brave/res/v1/web/search and send a search-scoped OAuth access token; q, count, freshness and search_lang are honored. Existing legacy search keys still work.

Last checked: 20 October 2026. Disclosure: Grounder (grounder.net) publishes this page, and Brave is one of the 10 search providers Grounder routes searches to.

What changes

Brave Search APIGrounder's Brave-shaped endpoint
URLGET https://api.search.brave.com/res/v1/web/searchGET https://api.grounder.net/compat/brave/res/v1/web/search
AuthorizationX-Subscription-Token header with a Brave keyX-Subscription-Token header with a Grounder OAuth access token scoped to search; Authorization: Bearer and existing legacy search keys also work
Rate limit50 queries a second (Search plan)120 requests a minute per key, about 2 a second
countMaximum 20, default 20Default 20, up to 100
Cost$5 per 1,000 requests; $5 free credit a month, tied to attributionFirst 1,000 searches free per account in total, up to 100 a day
Other endpointsNews, images, videos, suggest, summarizer, LLM Context, AnswersNot available: web results only

Request parameters:

Brave parameterOn GrounderNote
qHonoredRequired; site: and -site: operators become domain filters (include wins over exclude; OR between them is dropped)
countHonoredDefault 20, up to 100
freshnessHonored for pd, pw, pm, py1, 7, 31 and 365 days; Brave's custom date ranges are not read
search_langHonoredBecomes the language filter
country, offset, safesearch, result_filter, extra_snippets, spellcheck, Goggles and any other parameterNot supportedIgnored

The response keeps Brave's shape: type, query (read query.original) and web.results[] with type, title, url, description, language, family_friendly, page_age (only when known), meta_url and profile, plus a grounder object with provider, found_by, licensed, rank and, for licensed results, publisher_name. extra_snippets is never returned, and offset paging does not work: raise count instead. Do not rely on other query fields such as more_results_available; they are not documented here.

Results are merged and deduplicated across providers, not taken from Brave's own index alone, so Brave's statement that its results come from its own index with no fallback to Google or Bing does not describe them. Licensed sources only is on by default for signed-up accounts, so a call can return fewer results than count.

Steps

1. Authorize HTTP

Read https://api.grounder.net/.well-known/oauth-protected-resource/v1/search, register a public OAuth client, then sign in and request scope=search for resource https://api.grounder.net/v1/search. Store the returned access token as GROUNDER_ACCESS_TOKEN and refresh it before it expires. The API docs describe the flow. Existing legacy search keys still work.

2. Change the URL and access token

Diff
- https://api.search.brave.com/res/v1/web/search
+ https://api.grounder.net/compat/brave/res/v1/web/search

Before:

Shell
curl -G https://api.search.brave.com/res/v1/web/search \
  -H "X-Subscription-Token: $BRAVE_API_KEY" \
  --data-urlencode "q=half-life of caffeine site:ncbi.nlm.nih.gov" \
  --data-urlencode "count=5" \
  --data-urlencode "freshness=pm"

After:

Shell
curl -G https://api.grounder.net/compat/brave/res/v1/web/search \
  -H "X-Subscription-Token: $GROUNDER_ACCESS_TOKEN" \
  --data-urlencode "q=half-life of caffeine site:ncbi.nlm.nih.gov" \
  --data-urlencode "count=5" \
  --data-urlencode "freshness=pm"

3. Update your code

Python:

Python
import os

import requests

resp = requests.get(
    "https://api.grounder.net/compat/brave/res/v1/web/search",
    headers={"X-Subscription-Token": os.environ["GROUNDER_ACCESS_TOKEN"]},
    params={"q": "half-life of caffeine site:ncbi.nlm.nih.gov", "count": 5, "freshness": "pm"},
    timeout=30,
)
resp.raise_for_status()
for r in resp.json()["web"]["results"]:
    print(r["url"], r["grounder"]["provider"], r["grounder"]["licensed"])

TypeScript (Node 18 or later, as an ES module):

TypeScript
const params = new URLSearchParams({
  q: "half-life of caffeine site:ncbi.nlm.nih.gov",
  count: "5",
  freshness: "pm",
});
const res = await fetch(`https://api.grounder.net/compat/brave/res/v1/web/search?${params}`, {
  headers: { "X-Subscription-Token": process.env.GROUNDER_ACCESS_TOKEN ?? "" },
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const data = await res.json();
for (const r of data.web.results) console.log(r.url, r.grounder.provider, r.grounder.licensed);

4. Keep Brave's results

By default Grounder sends each call to the provider, or pair of providers, most likely to answer it well. To keep Brave, set Brave to Always and Licensing to Any source on the account page, under Routing. To have Brave bill you directly, add your own Brave key in the same table. To pin one search, call the native endpoint, which returns Grounder's own response shape:

Shell
curl https://api.grounder.net/v1/search \
  -H "Authorization: Bearer $GROUNDER_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"query": "half-life of caffeine", "top_k": 5, "requested_provider": "brave", "routing_settings": {"licensed_only": false}}'

5. Verify

Send 10 to 20 real queries to both APIs and compare result counts and URLs. Check grounder.provider and grounder.licensed on each result; fewer results than expected usually means Licensed sources only is on. Each call is a recorded search and counts toward the 1,000 free ones. curl https://api.grounder.net/v1/providers needs no key and lists the 10 providers.

6. Use MCP instead

Add https://api.grounder.net/mcp to your MCP client and sign in with Google, GitHub or Apple. The search tool takes query, top_k, domains, days, include_text and requested_provider; steps are in Docs.

If you move to another API directly

BraveTavilyExaPerplexity Search API
qqueryqueryquery
count (maximum 20)max_results (0 to 20)numResults (1 to 100)max_results (1 to 20)
country (2-character code)country (a country name, topic general only)userLocationcountry (ISO 3166-1 alpha-2)
search_langlanguage, filter_by_languageNo request field foundsearch_language_filter (up to 10 codes)
freshness: pd, pw, pm, pytime_range: day, week, month, yearstartPublishedDate, endPublishedDatesearch_recency_filter: hour, day, week, month, year
freshness as YYYY-MM-DDtoYYYY-MM-DDstart_date, end_datestartPublishedDate, endPublishedDatesearch_after_date_filter, search_before_date_filter (M/D/YYYY)
offset (maximum 9)No equivalent in the specNo pagination; raise numResultsNo equivalent in the spec
site: in qinclude_domains (300), exclude_domains (150)includeDomains, excludeDomains (1,200 each)search_domain_filter (20 domains, allow or deny)
goggles (custom re-ranking)No equivalent; domain lists onlyNo equivalent; domain lists onlyNo equivalent; domain lists only
extra_snippetsClosest: chunks_per_source (1 to 3)Closest: contents.highlightsClosest: max_tokens_per_page
web.results[].descriptionresults[].contentresults[].highlights or textresults[].snippet

Brave's LLM Context endpoint, which returns extracted chunks, has no one-field equivalent; the closest are Exa's highlights, Tavily's include_raw_content and Perplexity's max_tokens. Side by side, in more depth: Tavily vs Brave, Exa vs Brave and Brave Search API alternatives.

Where Grounder fits

Grounder is a web search API and MCP server for AI agents: one search goes across 10 web search providers, results are deduplicated, and each is marked with its provider and whether it is licensed. It returns sources, not an answer. Grounder's benchmark, run by Grounder, searched 887 questions (table as of 20 October 2026 05:22 UTC):

RowSimpleQA correct given attempted (671 questions)SealQA correct given attempted (216 questions)
Grounder optimized14.3%12.1%
Grounder optimized, all sources97.9%36.6%
Perplexity96.1%36.8%
Exa88.6%32.1%
Tavily86.6%24.5%
Brave85.2%16.4%

Each provider's row is its default search. Figures are correct given attempted: the share of the questions a search answered that it got right, with a "don't know" counted as not attempted. Grounder optimized answers only from licensed sources, so it gets fewer answers right than the all-sources row, which searches every source. Grounder optimized is what a signed-up account gets by default; the all-sources row is the same routing with nothing filtered out. Both Grounder rows are routed as Grounder routes on 19 October 2026, and that routing was tuned on these same searches. Read against Brave: the all-sources row is ahead of Brave on both benchmarks, but the default row (14.3% and 12.1%) is far behind it, and Brave's own published rate limit (50 queries a second) is well above the 120 requests a minute per key here. Each question was searched once on every provider's default search (top 10 results, 60 seconds), answered by Z.ai's GLM-5.3-Flash and graded with OpenAI's SimpleQA grader, from 8 to 13 October 2026. Full method: /benchmarks. For a wider comparison, see the best search API for AI agents.

FAQ

Is there a Brave-compatible endpoint?

Yes: GET https://api.grounder.net/compat/brave/res/v1/web/search takes Brave's query parameters and returns Brave's web.results shape plus a grounder object on each result. It accepts an OAuth access token with the search scope; existing legacy search keys still work.

Which Brave parameters does it honor?

q (with site: and -site: operators), count (up to 100), freshness (pd, pw, pm, py) and search_lang. country, offset, safesearch, result_filter, extra_snippets and spellcheck are ignored.

What happens to Goggles, LLM Context and Answers?

They are not supported. The endpoint returns web results only, with no news, images, videos, suggest or summarizer either.

Is the Brave Search API still free?

Brave's pricing page lists $5 of free credit a month on the Search plan, about 1,000 requests at $5 per 1,000, and Brave's blog ties it to attributing Brave on your site. The page headlines up to $20 in free calls a month, which Brave's blog counts as $5 on each of four plans, and no longer lists the older Free plan; Brave's pages do not say what happens to subscribers on it.

Can I cache the results?

Check first. Brave's terms bar storing results without a storage-rights plan, and Grounder publishes no storage rights for the providers' results. Grounder keeps its own search records indefinitely; see /privacy.

Which Brave parameters map to Tavily, Exa or Perplexity?

q becomes query; count (maximum 20) becomes max_results (Tavily, 0 to 20), numResults (Exa, up to 100) or max_results (Perplexity, 1 to 20); search_lang becomes language (Tavily) or search_language_filter (Perplexity); freshness becomes time_range (Tavily), startPublishedDate (Exa) or search_recency_filter (Perplexity). Goggles and extra_snippets have no direct equivalent.

Next step

Your first 1,000 searches are free, up to 100 a day. No card needed. Connect an MCP client to https://api.grounder.net/mcp, or read the HTTP API docs to use OAuth.

Sources

  1. https://grounder.net/docs (20 October 2026)
  2. https://api-dashboard.search.brave.com/app/documentation/web-search/query (20 October 2026)
  3. https://brave.com/search/api/ (20 October 2026)
  4. https://brave.com/blog/most-powerful-search-api-for-ai/ (20 October 2026)
  5. https://docs.tavily.com/documentation/api-reference/endpoint/search (20 October 2026)
  6. https://exa.ai/docs/reference/search (20 October 2026)
  7. https://docs.perplexity.ai/docs/search/quickstart and https://docs.perplexity.ai/docs/search/filters/date-time-filters (20 October 2026)
  8. https://grounder.net/benchmarks and https://api.grounder.net/v1/demo/results (20 October 2026, as of 05:22 UTC)
  9. https://grounder.net/pricing (20 October 2026)
  10. https://arxiv.org/abs/2411.04368 and https://arxiv.org/abs/2506.01062 (20 October 2026)