SAPI Python SDK


1.0 | Introduction

The SAPI Python SDK is an official Blue Billywig package for the Server API (SAPI). It provides a synchronous HTTP client covering entity CRUD operations, TUS-based file uploads to S3, and a rich set of analytics helpers for retrieving and combining video statistics.

GitHub repository: bluebillywig/bb-sapi-python-sdk

2.0 | Requirements

3.0 | Installation

pip install bb-sapi-python-sdk

4.0 | Authentication

The SDK uses HOTP-based RPC token authentication. You need the shared secret from your Blue Billywig publication (see API key management).

The shared secret shown in your account settings has the format {id}-{hex_secret}, for example 490-55c491d354cfefb9b4d26cf22fbdd0a1. Pass this full value as the shared_secret parameter.

from bb_sapi import SapiClient

client = SapiClient(
    base_url="https://mypublication.bbvms.com",
    shared_secret="490-55c491d354cfefb9b4d26cf22fbdd0a1",
)

Never hard-code credentials in version-controlled files. Use environment variables instead:
export SAPI_BASE_URL=https://mypublication.bbvms.com
export SAPI_SHARED_SECRET=490-55c491d354cfefb9b4d26cf22fbdd0a1

The token is time-based with a 120-second validity window. Ensure your server clock is synchronized with NTP.

5.0 | Quick start

5.1 | Entity operations

# Get a mediaclip
clip = client.get("mediaclip", "12345")

# List published clips
clips = client.list("mediaclip", limit=20, sort="createddate DESC",
                    filters={"status": "published"})

# Create
new_clip = client.create("mediaclip", {"title": "My Video", "status": "draft"})

# Update
client.update("mediaclip", "12345", {"title": "Updated Title"})

# Delete (soft)
client.delete("mediaclip", "12345")

# Delete permanently
client.delete("mediaclip", "12345", purge=True)

The generic methods accept any entity type name as a string: mediaclip, playlist, channel, playout, subtitle.

5.2 | Upload a video and create a mediaclip

result = client.create_mediaclip(
    "/path/to/video.mp4",
    title="My Video",
    status="draft",
    on_progress=lambda done, total: print(f"{done / total * 100:.0f}%"),
)
print(result.mediaclip_id)

To upload a file without creating a new mediaclip entity (for example, to attach a subtitle or replace a creative), use upload_file() instead:

result = client.upload_file("/path/to/subtitle.srt", mediaclip_id="12345")

5.3 | Analytics

The Python SDK includes convenience helpers for common analytics queries.

# Top 10 videos for a date range
top = client.analytics.top_videos("2026-01-01", "2026-03-31", limit=10)
for v in top:
    print(v["id"], v["views"])

# Unique viewers for a specific video
unique = client.analytics.unique_viewers(
    "mediaclip", "2026-01-01", "2026-03-31", entity_id="12345"
)

# How far viewers watched — viewcount reach at various thresholds
reach = client.analytics.viewcount_reach("12345", "2026-01-01", "2026-03-31")
# Returns: {20: 1200, 40: 900, 60: 700, 80: 400, 95: 150}
# Read as: 1200 sessions reached at least 20% of the video, etc.

# Ad impressions and VAST quartiles per video
ad = client.analytics.ad_stats_per_video("12345", "2026-01-01", "2026-03-31")
print(ad["impressions"])          # total ad impressions (lineitemInits)
print(ad["vastQuartiles"]["50"])  # sessions where the ad reached 50%

6.0 | Full documentation

The GitHub README contains the complete analytics API reference, TUS upload flow details, LineItem version history, and all entity operation options: github.com/bluebillywig/bb-sapi-python-sdk

Was this article helpful?

Related Articles

Contact Support
Can't find the answer you're looking for?
Contact Support