An asynchronous client for the Brightcove API.
Project description
brightcove_async
brightcove_async is an asynchronous Python client for the Brightcove video platform APIs. It wraps Brightcove's REST endpoints in asyncio-friendly service classes, handles OAuth2 token management for you, and validates every request and response against Pydantic models.
Features
- Async-first API built on
aiohttp. - OAuth2 client-credentials auth with automatic token caching and refresh.
- Pydantic models for request bodies, query parameters, and responses, giving you validation and editor autocompletion.
- Per-service rate limiting via
aiolimiter. - Automatic retries for transient failures (connection drops,
401,429) withtenacity, includingRetry-Aftersupport on rate-limited responses. - Brightcove HTTP errors mapped to a typed exception hierarchy.
- Coverage for the CMS, Analytics, Audience, Syndication, Dynamic Ingest, and Ingest Profiles APIs.
Installation
pip install brightcove_async
Requires Python 3.13 or newer.
Authentication
The client authenticates with OAuth2 client credentials. Create an API authentication credential in Brightcove Studio, then provide the client ID and secret through environment variables:
export CLIENT_ID="your_client_id"
export CLIENT_SECRET="your_client_secret"
initialise_brightcove_client() reads these by default. To pass credentials explicitly instead, construct a BrightcoveOAuthCreds:
import brightcove_async
from brightcove_async.settings import BrightcoveOAuthCreds
client = brightcove_async.initialise_brightcove_client(
oauth_creds=BrightcoveOAuthCreds(
client_id="your_client_id",
client_secret="your_client_secret",
),
)
Tokens are fetched on first use and reused until they expire, so you don't manage them yourself.
Quick start
Always use the client as an async context manager. The HTTP session and OAuth client are created on entry and cleaned up on exit.
import asyncio
import brightcove_async
from brightcove_async.schemas.cms_model import (
CreateVideoRequestBodyFields,
State,
)
async def main() -> None:
client = brightcove_async.initialise_brightcove_client()
async with client as bc:
video = await bc.cms.create_video(
account_id="12345",
video_data=CreateVideoRequestBodyFields(
name="test",
State=State.ACTIVE,
),
)
print(video.model_dump())
if __name__ == "__main__":
asyncio.run(main())
Services are exposed as properties on the client (bc.cms, bc.analytics, bc.audience, bc.syndication, bc.dynamic_ingest, bc.ingest_profiles) and are created lazily on first access.
Usage
CMS
from brightcove_async.schemas.params import GetVideosQueryParams
async with client as bc:
# A single page of videos
videos = await bc.cms.get_videos(
account_id="12345",
params=GetVideosQueryParams(limit=20, sort="-created_at"),
)
# Every video for an account, fetched page by page concurrently
all_videos = await bc.cms.get_videos_for_account(
account_id="12345",
page_size=100,
)
video = await bc.cms.get_video_by_id(account_id="12345", video_id="6789")
sources = await bc.cms.get_video_sources(account_id="12345", video_id="6789")
Analytics
from brightcove_async.schemas.params import GetAnalyticsReportParams
async with client as bc:
report = await bc.analytics.get_analytics_report(
params=GetAnalyticsReportParams(
accounts="12345",
dimensions="video",
from_="2026-01-01",
to="2026-01-31",
),
)
print(report.model_dump())
Audience
from brightcove_async.schemas.params import GetLeadsParams, GetViewEventsParams
async with client as bc:
leads = await bc.audience.get_leads(
account_id="12345",
params=GetLeadsParams(limit=10, sort="created_at"),
)
view_events = await bc.audience.get_view_events(
account_id="12345",
params=GetViewEventsParams(limit=10),
)
Dynamic Ingest
from brightcove_async.schemas.dynamic_ingest_model import IngestMediaAssetbody
async with client as bc:
result = await bc.dynamic_ingest.ingest_videos_and_assets(
account_id="12345",
video_id="6789",
video_or_asset_data=IngestMediaAssetbody(
master={"url": "https://example.com/master.mp4"},
),
)
Bringing your own session
By default the client opens and closes its own aiohttp.ClientSession. To share a session you manage elsewhere, pass it to BrightcoveClient directly; in that case the client leaves the session open when the context manager exits.
import aiohttp
from brightcove_async.client import BrightcoveClient
from brightcove_async.oauth.oauth import OAuthClient
from brightcove_async.registry import build_service_registry
from brightcove_async.settings import BrightcoveBaseAPIConfig
async with aiohttp.ClientSession() as session:
client = BrightcoveClient(
services_registry=build_service_registry(BrightcoveBaseAPIConfig()),
client_id="your_client_id",
client_secret="your_client_secret",
oauth_cls=OAuthClient,
session=session,
)
async with client as bc:
videos = await bc.cms.get_videos(account_id="12345")
Error handling
HTTP errors are translated into a typed exception hierarchy rooted at BrightcoveError. Catch the base class to handle any API failure, or a specific subclass for finer control.
from brightcove_async.exceptions import (
BrightcoveError,
BrightcoveResourceNotFoundError,
BrightcoveTooManyRequestsError,
)
async with client as bc:
try:
video = await bc.cms.get_video_by_id(account_id="12345", video_id="000")
except BrightcoveResourceNotFoundError:
... # 404
except BrightcoveTooManyRequestsError as exc:
print(exc.retry_after) # seconds, when the server sends Retry-After
except BrightcoveError as exc:
print(exc.status_code, exc.endpoint, exc.details)
Status codes map to exceptions as follows:
| Status | Exception |
|---|---|
| 400 | BrightcoveBadValueError |
| 401 | BrightcoveAuthError |
| 403 | BrightcoveForbiddenError |
| 404 | BrightcoveResourceNotFoundError |
| 405 | BrightcoveMethodNotAllowedError |
| 409 | BrightcoveConflictError |
| 429 | BrightcoveTooManyRequestsError |
| 5xx / unknown | BrightcoveUnknownError |
Connection failures raise BrightcoveConnectionError. Transient errors (BrightcoveConnectionError, BrightcoveAuthError, BrightcoveTooManyRequestsError) are retried automatically before propagating.
Rate limiting
Each service has its own request-per-second budget enforced by an AsyncLimiter. The CMS and Ingest Profiles services default to 4 requests per second; the rest default to 10. The limits live in registry.py and can be tuned per service.
API coverage
| Service | Methods |
|---|---|
cms |
get_videos, create_video, get_videos_for_account, get_video_count, get_video_fields, get_video_by_id, get_video_sources, get_video_images, get_video_variants, get_video_variant, get_video_audio_tracks, get_video_audio_track, get_digital_master_info, get_playlists_for_video, get_status_of_ingest_jobs, get_ingest_job_status, list_channels, get_channel_details, list_channel_affiliates, list_contracts, get_contract, list_shares |
analytics |
get_account_engagement, get_player_engagement, get_video_engagement, get_analytics_report, get_available_date_range, get_alltime_video_views |
audience |
get_leads, get_view_events |
syndication |
get_all_syndications, get_syndication, create_syndication, update_syndication, patch_syndication, delete_syndication, get_template, upload_template |
dynamic_ingest |
ingest_videos_and_assets, get_temporary_s3_urls |
ingest_profiles |
get_ingest_profiles |
Development
This project uses uv for dependency management and task running.
uv sync # create the environment
uv run pytest # run the test suite
uv run ruff check --fix # lint
uv run ruff format # format
uv run ty check # type check
uv run pre-commit run --all-files
Documentation
Contributing
Pull requests are welcome. Please open an issue to discuss a feature or bug fix before submitting a PR, and include tests for any behavior change.
License
MIT License. See LICENSE.txt.
Disclaimer
This project is not affiliated with or endorsed by Brightcove Inc.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file brightcove_async-0.6.0.tar.gz.
File metadata
- Download URL: brightcove_async-0.6.0.tar.gz
- Upload date:
- Size: 52.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7822a4cf5fa5b4daa63177f880fdabf5853578da72f1759e1491e8a2c25cafc5
|
|
| MD5 |
627ed92fe6c8a212d9ef8091e3aaa773
|
|
| BLAKE2b-256 |
382dde5fcc39915bb1f33630c31dea0a5bfa59cdf4ee8d545735a7c6568ec5f8
|
Provenance
The following attestation bundles were made for brightcove_async-0.6.0.tar.gz:
Publisher:
package-publish.yml on Winne004/brightcove_async
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
brightcove_async-0.6.0.tar.gz -
Subject digest:
7822a4cf5fa5b4daa63177f880fdabf5853578da72f1759e1491e8a2c25cafc5 - Sigstore transparency entry: 1818173600
- Sigstore integration time:
-
Permalink:
Winne004/brightcove_async@42baffd53924b73776c00625fcbe15e54daf4f09 -
Branch / Tag:
refs/tags/v0.6.0 - Owner: https://github.com/Winne004
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
package-publish.yml@42baffd53924b73776c00625fcbe15e54daf4f09 -
Trigger Event:
release
-
Statement type:
File details
Details for the file brightcove_async-0.6.0-py3-none-any.whl.
File metadata
- Download URL: brightcove_async-0.6.0-py3-none-any.whl
- Upload date:
- Size: 41.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9a3604fa23a3a630f163d8fcba08e31cd05c3f574860d8a5e13ce16b67e15361
|
|
| MD5 |
068637bcd745595d3b8c86e3b7d54024
|
|
| BLAKE2b-256 |
763dc65348def4aaff8565766c43add04d9624f86b6348185ecb1c4d9b4a07aa
|
Provenance
The following attestation bundles were made for brightcove_async-0.6.0-py3-none-any.whl:
Publisher:
package-publish.yml on Winne004/brightcove_async
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
brightcove_async-0.6.0-py3-none-any.whl -
Subject digest:
9a3604fa23a3a630f163d8fcba08e31cd05c3f574860d8a5e13ce16b67e15361 - Sigstore transparency entry: 1818173688
- Sigstore integration time:
-
Permalink:
Winne004/brightcove_async@42baffd53924b73776c00625fcbe15e54daf4f09 -
Branch / Tag:
refs/tags/v0.6.0 - Owner: https://github.com/Winne004
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
package-publish.yml@42baffd53924b73776c00625fcbe15e54daf4f09 -
Trigger Event:
release
-
Statement type: