Typed Python client for the Brave Search API.
This package uses niquests for HTTP transport and pydantic models for
request validation and response parsing.
uv add brave-api-clientOr with pip:
pip install brave-api-clientPass your API key directly:
from brave_api.client import Brave
client = Brave(api_key="your-api-key")Or set BRAVE_API_KEY:
export BRAVE_API_KEY=your-api-keyBrave: synchronous clientAsyncBrave: asynchronous client
For Brave's official API docs and endpoint details, see:
from brave_api.client import Brave
from brave_api.web_search.models import WebSearchQueryParams
client = Brave(api_key="your-api-key")
response = client.web_search(WebSearchQueryParams(q="python web frameworks"))
data = response.parsed_data
if data.web:
for result in data.web.results:
print(result.title, result.url)import asyncio
from brave_api.client import AsyncBrave
from brave_api.web_search.models import WebSearchQueryParams
async def main() -> None:
client = AsyncBrave(api_key="your-api-key")
response = await client.web_search(WebSearchQueryParams(q="privacy search"))
data = response.parsed_data
if data.web:
for result in data.web.results:
print(result.title)
asyncio.run(main())All non-streaming methods return a Response[Model] wrapper, including methods
on AsyncBrave. Use response.parsed_data for the validated Pydantic model and
response.raw_response for the underlying niquests response.
AsyncBrave.summarizer_summary_streaming() returns
AsyncResponse[SummarizerStreamingEvent], and
Brave.summarizer_summary_streaming() returns
Response[SummarizerStreamingEvent]. Consume streaming events with
iter_lines_parsed().
Retries are enabled by default. Brave and AsyncBrave use RetryConfig()
unless you override it, so retryable errors automatically use
BraveRateLimitRetryStrategy.
The default configuration retries transient transport failures plus HTTP 429,
500, 502, 503, and 504.
from brave_api.client import Brave
client = Brave(api_key="your-api-key")That default client retries with Brave's documented X-RateLimit-Reset and
X-RateLimit-Remaining headers.
from brave_api.client import Brave
client = Brave(api_key="your-api-key", retry_config=None)from brave_api.client import Brave
from brave_api.retries import FixedDelayRetryStrategy, RetryConfig
client = Brave(
api_key="your-api-key",
retry_config=RetryConfig(
max_attempts=4,
strategy=FixedDelayRetryStrategy(delay_seconds=1.0),
),
)from brave_api.client import AsyncBrave
from brave_api.retries import ExponentialBackoffRetryStrategy, RetryConfig
client = AsyncBrave(
api_key="your-api-key",
retry_config=RetryConfig(
max_attempts=5,
strategy=ExponentialBackoffRetryStrategy(
base_delay_seconds=0.5,
max_delay_seconds=8.0,
),
),
)BraveRateLimitRetryStrategy uses Brave's X-RateLimit-Reset header and pairs
it with X-RateLimit-Remaining when available so retries wait for the
exhausted window to reopen. It falls back to Retry-After, then to another
strategy.
from brave_api.client import Brave
from brave_api.retries import (
BraveRateLimitRetryStrategy,
ExponentialBackoffRetryStrategy,
RetryConfig,
)
client = Brave(
api_key="your-api-key",
retry_config=RetryConfig(
max_attempts=3,
strategy=BraveRateLimitRetryStrategy(
fallback_strategy=ExponentialBackoffRetryStrategy(
base_delay_seconds=1.0,
max_delay_seconds=10.0,
)
),
),
)RetryAfterRetryStrategy is still available when you want to prioritize the
standard Retry-After header instead of Brave's rate-limit headers.
All methods below are available on both Brave and AsyncBrave. Async methods
use the same names and are awaited.
| API group | Brave endpoint(s) | Client methods | Request model(s) | Return type |
|---|---|---|---|---|
| Web search | /res/v1/web/search |
web_search() |
WebSearchQueryParams |
Response[WebSearchApiResponse] |
| Rich search | /res/v1/web/rich |
rich_search() |
RichSearchQueryParams |
Response[RichSearchApiResponse] |
| Image search | /res/v1/images/search |
image_search() |
ImageSearchAPIParams |
Response[ImageSearchApiResponse] |
| News search | /res/v1/news/search |
news_search() |
NewsSearchQueryParams |
Response[NewsSearchApiResponse] |
| Video search | /res/v1/videos/search |
video_search() |
VideoSearchQueryParams |
Response[VideoSearchApiResponse] |
| Spellcheck | /res/v1/spellcheck/search |
spellcheck() |
SpellcheckQueryParams |
Response[SpellcheckApiResponse] |
| Suggest | /res/v1/suggest/search |
suggest() |
SuggestSearchQueryParams |
Response[SuggestSearchApiResponse] |
| Place search | /res/v1/local/place_search |
place_search() |
PlaceSearchQueryParams |
Response[PlaceSearchApiResponse] |
| Local points of interest | /res/v1/local/pois |
local_pois() |
LocalSearchQueryParams |
Response[LocalPoiSearchApiResponse] |
| Local descriptions | /res/v1/local/descriptions |
local_descriptions() |
LocalDescriptionsQueryParams |
Response[LocalDescriptionsSearchApiResponse] |
| LLM context | /res/v1/llm/context |
llm_context() |
LLMContextQueryParams |
Response[LLMContextApiResponse] |
| Answers | /res/v1/chat/completions |
answers() |
AnswersRequest |
Response[AnswersApiResponse] |
| Answers streaming | /res/v1/chat/completions |
answers_streaming() |
AnswersRequest |
Response[AnswersStreamingEvent] on Brave; AsyncResponse[AnswersStreamingEvent] on AsyncBrave |
| Summarizer search | /res/v1/summarizer/search |
summarizer_search() |
SummarizerQueryParams |
Response[SummarizerSearchApiResponse] |
| Summarizer summary | /res/v1/summarizer/summary |
summarizer_summary() |
SummarizerQueryParams |
Response[SummarizerSummaryApiResponse] |
| Summarizer title | /res/v1/summarizer/title |
summarizer_title() |
SummarizerQueryParams |
Response[SummarizerTitleApiResponse] |
| Summarizer enrichments | /res/v1/summarizer/enrichments |
summarizer_enrichments() |
SummarizerQueryParams |
Response[SummarizerEnrichmentsApiResponse] |
| Summarizer followups | /res/v1/summarizer/followups |
summarizer_followups() |
SummarizerQueryParams |
Response[SummarizerFollowupsApiResponse] |
| Summarizer entity info | /res/v1/summarizer/entity_info |
summarizer_entity_info() |
SummarizerEntityInfoQueryParams |
Response[SummarizerEntityInfoApiResponse] |
| Summarizer streaming | /res/v1/summarizer/summary_streaming |
summarizer_summary_streaming() |
SummarizerQueryParams |
Response[SummarizerStreamingEvent] on Brave; AsyncResponse[SummarizerStreamingEvent] on AsyncBrave |
The web search client is the main entry point for Brave Search. It returns a typed response that can include web results and additional sections such as news, videos, locations, discussions, infoboxes, and summarizer metadata.
These endpoints expose Brave's vertical-specific search APIs with typed request and response models for media and content-focused workflows.
These APIs support search UX features such as autocomplete, typo correction, and query refinement.
The local APIs cover both discovery and enrichment for places and points of
interest. A common flow is to use place_search() to find locations, then
fetch follow-up POI details or descriptions with local_pois() and
local_descriptions().
The package includes dedicated models for Brave's LLM grounding APIs.
llm_context() returns extracted grounding content for your own LLM workflows,
while answers() and answers_streaming() expose the OpenAI-compatible
chat-completions endpoint backed by Brave Search.
The package includes typed support for Brave's summarizer-related endpoints, including summary retrieval, streaming output, enrichments, followups, titles, and entity information.