bria-client is Bria's official Python SDK. It wraps the v2 REST API with a synchronous and an asynchronous client, handles the async job lifecycle (submit, poll, webhooks), retries transient failures, and converts local images to API inputs for you.
- Source and issues: github.com/Bria-AI/bria-client (MIT)
- Python 3.10 or newer
- Covers every v2 endpoint. Legacy
/v1endpoints are not reachable through the SDK; call them over HTTP.
pip install bria-client
export BRIA_API_TOKEN="<your-bria-api-token>"The client reads BRIA_API_TOKEN from the environment. You can also pass api_token= to the constructor, or override it per call with api_token= on any method. Get a token from the Bria Console.
from bria_client import BriaSyncClient
from bria_client.toolkit import Image
client = BriaSyncClient()
response = client.run(
endpoint="image/edit/remove_background",
payload={"image": Image("https://labs-assets.bria.ai/sandbox-example-inputs/remove_background_example.jpg").as_bria_api_input},
)
print(response.status) # COMPLETED
print(response.result.image_url) # URL of the cutoutendpoint is the v2 path without the /v2/ prefix, exactly as it appears in the API reference: image/generate, image/edit/remove_background, video/edit/remove_background, and so on.
| Client | Use when |
|---|---|
BriaSyncClient | Scripts, notebooks, CLIs, traditional web frameworks |
BriaAsyncClient | asyncio applications and high-concurrency pipelines |
Both expose the same methods; the async client awaits them. Both work as context managers (with / async with) so connections are closed cleanly.
import asyncio
from bria_client import BriaAsyncClient
async def main():
async with BriaAsyncClient() as client:
response = await client.run(
endpoint="image/generate",
payload={"prompt": "a matte black travel mug on a white seamless backdrop"},
)
print(response.result.image_url)
asyncio.run(main())Bria's v2 endpoints are asynchronous by default. The SDK gives you three ways to work with that:
| Method | What it does | Returns |
|---|---|---|
client.run(endpoint, payload) | Sends the request with sync: true and blocks until the result is ready. Simplest for interactive use. | BriaResponse with result |
client.submit(endpoint, payload, webhook_url=None) | Sends the request with sync: false and returns immediately. | BriaResponse with request_id and status_url |
client.poll(response_or_request_id, interval=1, timeout=60) | Polls the status endpoint until the job finishes. Raises TimeoutError when the timeout elapses. | BriaResponse with result |
Do not put sync in your payload; run and submit set it for you and raise if you pass it.
# Submit now, collect later
job = client.submit(endpoint="video/segment/mask_by_prompt", payload={"video": video_url, "prompt": "the red car"})
print("submitted:", job.request_id)
final = client.poll(job, interval=2, timeout=600)
print(final.result.video_url)client.status(request_id) returns just the current status string (IN_PROGRESS, COMPLETED, ERROR, UNKNOWN) if you manage polling yourself.
Every method returns a BriaResponse:
| Field | Description |
|---|---|
request_id | Job identifier; also the deduplication key for webhooks |
status | IN_PROGRESS, COMPLETED, ERROR or UNKNOWN |
result | Endpoint result. Access fields as attributes: result.image_url, result.video_url, result.seed, result.structured_prompt |
error | code, message, details when the request failed |
status_url | Polling URL for async jobs |
Pass raise_for_status=True to turn API errors into a BriaException instead of inspecting response.error:
from bria_client.toolkit import BriaException
try:
response = client.run(endpoint="image/generate", payload={"prompt": "..."}, raise_for_status=True)
print(response.result.image_url)
except TimeoutError:
print("timed out waiting for the result")
except BriaException as e:
print("Bria API error:", e)Transient HTTP failures are retried automatically (3 attempts with exponential backoff). Pass retry= to the constructor to change that.
Image from bria_client.toolkit turns any of these into the string the API expects, either the URL as-is or a raw base64 payload without the data: prefix:
from bria_client.toolkit import Image
from PIL import Image as PILImage
import numpy as np
Image("https://example.com/photo.jpg").as_bria_api_input # public URL, passed through
Image("./photo.png").as_bria_api_input # local path, encoded to base64
Image(PILImage.open("photo.png")).as_bria_api_input # PIL image
Image(np.zeros((512, 512, 3), dtype="uint8")).as_bria_api_input # numpy arrayThe client also strips None values from payloads, so optional parameters can be left as None without being sent.
Instead of polling, ask Bria to POST the result to your server when the job completes. webhook_url is a keyword argument of submit, not part of the payload:
job = client.submit(
endpoint="image/generate",
payload={"prompt": "a serene mountain landscape at dawn"},
webhook_url="https://your-app.example.com/api/bria/webhook",
)Verify every delivery with the bundled HMAC-SHA256 helper before acting on it:
import os
from bria_client.toolkit import verify_webhook_signature
def handle(request): # any framework: use the raw body bytes and the three Bria-Webhook-* headers
ok = verify_webhook_signature(
payload=request.body,
webhook_id=request.headers["Bria-Webhook-Id"],
timestamp=request.headers["Bria-Webhook-Timestamp"],
signature_header=request.headers["Bria-Webhook-Signature"],
api_token=os.environ["BRIA_API_TOKEN"],
)
if not ok:
return 401
...See webhooks for the delivery contract, retries and a complete FastAPI receiver.
Video endpoints take a hosted URL. client.upload() wraps the Video Upload Service: it requests a presigned upload, uploads the file, and returns a URL that stays valid for about 24 hours.
file_url = client.upload("path/to/video.mp4", media_type="video/mp4")
job = client.submit(endpoint="video/edit/remove_background", payload={"video": file_url})
result = client.poll(job, timeout=600)
print(result.result.video_url)Treat the returned URL as a secret: anyone holding it can download the file.
Submit everything first, then poll:
from bria_client import BriaSyncClient
from bria_client.toolkit import Image
client = BriaSyncClient()
paths = ["sku-1.jpg", "sku-2.jpg", "sku-3.jpg"]
jobs = [
client.submit(endpoint="image/edit/remove_background", payload={"image": Image(p).as_bria_api_input})
for p in paths
]
results = [client.poll(job, timeout=120) for job in jobs]
for path, r in zip(paths, results):
print(path, r.result.image_url)With BriaAsyncClient, use asyncio.gather over client.run(...) calls for the same effect with a single event loop. Stay within your plan's rate limits.
| Setting | Constructor argument | Environment variable | Default |
|---|---|---|---|
| API token | api_token | BRIA_API_TOKEN | required |
| Base URL | base_url | BRIA_BASE_URL | https://engine.prod.bria-api.com |
| Retries | retry (an httpx_retries.Retry) | 3 attempts, backoff factor 2 |
Contributions and bug reports are welcome on GitHub; the repository README covers the development setup.