A fully typed Python REST API client for the BirdEye reputation management platform.
pip install birdeye-pyuv add birdeye-pyRequirements: Python 3.10+
import os
import birdeye
client = birdeye.BirdEye(api_key=os.environ["BIRDEYE_API_KEY"])
# Fetch a business
business = client.business.get(business_id="123456")
print(business.name, business.city, business.state)
# Fetch reviews
result = client.reviews.get_reviews(business_id="123456", count=25)
for review in result.items:
print(review)
# Get a review summary
summary = client.reviews.get_summary(business_id="123456")
client.close()Use the client as a context manager to ensure the underlying HTTP connection is always closed:
import os
import birdeye
with birdeye.BirdEye(api_key=os.environ["BIRDEYE_API_KEY"]) as client:
business = client.business.get(business_id="123456")
print(business.name)Every resource is also available as a fully asynchronous client via AsyncBirdEye:
import asyncio
import os
import birdeye
async def main() -> None:
async with birdeye.AsyncBirdEye(api_key=os.environ["BIRDEYE_API_KEY"]) as client:
business = await client.business.get(business_id="123456")
print(business.name, business.city, business.state)
result = await client.reviews.get_reviews(business_id="123456", count=25)
for review in result.items:
print(review)
asyncio.run(main())The AsyncBirdEye client exposes the same 26 resource categories with identical method signatures — all methods are async def and must be awaited.
All 153 endpoints are organized into 26 resource categories, accessible as attributes on the client.
| Attribute | Endpoints | Example methods |
|---|---|---|
client.aggregation |
4 | get_reviews, get_rating |
client.business |
13 | get, create, update, delete, search, get_children |
client.campaign |
2 | send, get_status |
client.competitor |
10 | get_competitor_businesses, get_competitor_child_businesses |
client.competitor_ai |
2 | get_insights, get_summary |
client.contact |
11 | save, get, delete, list_contacts, get_opt_out_feed |
client.contact_v2 |
5 | save, get, delete, list |
client.conversation |
1 | get_conversations |
client.custom_fields |
7 | create, get, update, delete, list |
client.employee |
1 | get_employees |
client.faq |
1 | get_faqs |
client.gmb_products |
8 | create, get, update, delete, list |
client.google_qna |
9 | create_question, create_answer, update_question, delete_question |
client.google_services |
6 | get_services, update_services |
client.insight_ai |
2 | get_insights, get_summary |
client.integration |
1 | get_integrations |
client.listing |
15 | fix, get_status, get_insights, get_gmb_attributes |
client.media |
4 | upload, get, delete, list |
client.report |
17 | get_dashboard, get_reviews_over_time, get_email_analytics |
client.reviews |
9 | get_reviews, get_summary, reply, create_tags, assign_tags |
client.social |
6 | schedule_post, edit_scheduled_post, delete_post, track_post |
client.subscription |
2 | create, delete |
client.survey |
6 | send, get, list, delete |
client.ticketing |
4 | create, get, update, list |
client.user |
5 | create, get, update, delete, forgot_password |
client.webhook |
2 | create, delete |
Log in to your BirdEye account, navigate to Admin > Integrations > API, and generate an API key.
Pass the key directly at client construction:
client = birdeye.BirdEye(api_key="your-api-key")The recommended pattern is to read the key from an environment variable so it is never hard-coded in source:
import os
import birdeye
client = birdeye.BirdEye(api_key=os.environ["BIRDEYE_API_KEY"])All exceptions inherit from BirdEyeError. API-level errors carry the HTTP status code and BirdEye error code.
BirdEyeError
└── APIError status_code, error_code, message
├── AuthenticationError error code 88 — invalid or missing API key
├── RateLimitError HTTP 429, error code 89 — includes retry_after (float | None)
├── NotFoundError HTTP 404
└── ValidationError HTTP 400
import os
import birdeye
from birdeye import (
AuthenticationError,
NotFoundError,
RateLimitError,
ValidationError,
APIError,
BirdEyeError,
)
client = birdeye.BirdEye(api_key=os.environ["BIRDEYE_API_KEY"])
try:
business = client.business.get(business_id="does-not-exist")
except AuthenticationError:
print("Invalid API key.")
except NotFoundError:
print("Business not found.")
except RateLimitError as exc:
retry_in = exc.retry_after
print(f"Rate limited. Retry after {retry_in}s.")
except ValidationError as exc:
print(f"Bad request: {exc.message}")
except APIError as exc:
print(f"API error {exc.status_code}/{exc.error_code}: {exc.message}")
except BirdEyeError as exc:
print(f"Unexpected error: {exc}")The client automatically retries on transient network errors and 429 responses using exponential backoff (see Configuration to adjust max_retries).
Endpoints that return paginated data expose sindex / count parameters. The response includes total_count so you can loop manually:
import os
import birdeye
client = birdeye.BirdEye(api_key=os.environ["BIRDEYE_API_KEY"])
page_size = 50
start = 0
while True:
result = client.reviews.get_reviews(
business_id="123456",
sindex=start,
count=page_size,
)
for review in result.items:
print(review)
start += len(result.items)
if start >= result.total_count:
breakResources that support it return a PageIterator (sync) or AsyncPageIterator (async). These iterators fetch subsequent pages automatically as you iterate:
# Synchronous auto-pagination
from birdeye._pagination import PageIterator
pages: PageIterator = client.reviews.iter_reviews(business_id="123456")
for review in pages:
print(review)# Asynchronous auto-pagination
from birdeye._pagination import AsyncPageIterator
async for review in client.reviews.iter_reviews(business_id="123456"):
print(review)The iterator respects a hard cap of 100,000 items per traversal to prevent runaway pagination.
All configuration is passed as keyword arguments to the client constructor. Both BirdEye and AsyncBirdEye accept the same options.
import birdeye
client = birdeye.BirdEye(
api_key="your-api-key",
# Override the base URL (e.g. for a proxy or staging environment).
# Default: "https://api.birdeye.com/resources"
base_url="https://api.birdeye.com/resources",
# Per-request timeout in seconds. Default: 30.0
timeout=60.0,
# Number of automatic retries on transient errors. Default: 2
max_retries=3,
# Additional HTTP headers sent with every request.
default_headers={"X-My-Header": "value"},
)| Parameter | Type | Default | Description |
|---|---|---|---|
api_key |
str |
— | BirdEye API key (required) |
base_url |
str |
https://api.birdeye.com/resources |
API base URL |
timeout |
float |
30.0 |
Per-request timeout in seconds |
max_retries |
int |
2 |
Retry attempts with exponential backoff |
default_headers |
dict[str, str] | None |
None |
Headers merged into every request |
git clone https://github.com/michellepellon/birdeye-py.git
cd birdeye.py
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e ".[dev]"Or with uv:
git clone https://github.com/michellepellon/birdeye-py.git
cd birdeye.py
uv sync --extra devpytestWith coverage:
pytest --cov=birdeye --cov-report=term-missingThe test suite contains 490 tests and achieves 99% line coverage using respx for HTTP mocking.
ruff check src tests
ruff format --check src testsTo auto-fix:
ruff check --fix src tests
ruff format src testspyrightThe codebase targets strict Pyright mode (typeCheckingMode = "strict").
MIT License. Copyright (c) Michelle Pellon.
See LICENSE for the full text.