PlayVideo SDK for Python
Official Python SDK for the PlayVideo API - Video hosting for developers.
Installation
pip install playvideo
Requirements: Python 3.10+
Quick Start
Synchronous Client
from playvideo import PlayVideo
client = PlayVideo("play_live_xxx")
# List collections
collections = client.collections.list()
# Upload a video
response = client.videos.upload(
"./video.mp4",
"my-collection",
on_progress=lambda p: print(f"{p.percent}%")
)
# Watch processing progress
for event in client.videos.watch_progress(response.video["id"]):
print(event.stage, event.message)
if event.stage == "completed":
print("Video ready:", event.playlist_url)
break
client.close()
Async Client
from playvideo import AsyncPlayVideo
import asyncio
async def main():
async with AsyncPlayVideo("play_live_xxx") as client:
# List collections
collections = await client.collections.list()
# Upload a video
response = await client.videos.upload("./video.mp4", "my-collection")
# Watch processing progress
async for event in client.videos.watch_progress(response.video["id"]):
print(event.stage)
if event.stage == "completed":
break
asyncio.run(main())
Resources
Collections
# List all collections
collections = client.collections.list()
# Create a collection
collection = client.collections.create("My Videos", description="Tutorial videos")
# Get a collection with videos
collection = client.collections.get("my-videos")
# Delete a collection
client.collections.delete("my-videos")
Videos
# List videos
videos = client.videos.list()
# Filter by collection or status
videos = client.videos.list(collection="my-collection", status="COMPLETED", limit=50)
# Get a video
video = client.videos.get("video-id")
# Upload with progress
def on_progress(progress):
print(f"{progress.percent}% ({progress.loaded}/{progress.total})")
response = client.videos.upload("./video.mp4", "my-collection", on_progress=on_progress)
# Delete a video
client.videos.delete("video-id")
# Get embed information
embed_info = client.videos.get_embed_info("video-id")
# Watch processing progress
for event in client.videos.watch_progress("video-id"):
match event.stage:
case "pending":
print("Waiting in queue...")
case "processing":
print("Transcoding...")
case "completed":
print("Done!", event.playlist_url)
case "failed":
print("Failed:", event.error)
Webhooks
# List webhooks
webhooks, available_events = client.webhooks.list()
# Create a webhook
webhook = client.webhooks.create(
url="https://example.com/webhook",
events=["video.completed", "video.failed"]
)
# Save webhook.secret - only shown once!
# Update a webhook
client.webhooks.update("webhook-id", events=["video.completed"], is_active=False)
# Test a webhook
result = client.webhooks.test("webhook-id")
# Delete a webhook
client.webhooks.delete("webhook-id")
Embed Settings
# Get embed settings
settings = client.embed.get_settings()
# Update embed settings
settings = client.embed.update_settings(
primary_color="#FF0000",
autoplay=True,
muted=True
)
# Generate signed embed URL
embed = client.embed.sign("video-id")
print(embed.embed_url)
print(embed.embed_code["responsive"])
API Keys
# List API keys
api_keys = client.api_keys.list()
# Create an API key
key = client.api_keys.create("My App")
# Save key.key - only shown once!
# Delete an API key
client.api_keys.delete("key-id")
Account
# Get account info
account = client.account.get()
# Update allowed domains
account = client.account.update(
allowed_domains=["example.com", "app.example.com"],
allow_localhost=True
)
Usage
# Get usage statistics
usage = client.usage.get()
print(f"Plan: {usage.plan}")
print(f"Videos: {usage.usage.videos_this_month}/{usage.usage.videos_limit}")
print(f"Storage: {usage.usage.storage_used_gb} GB")
Webhook Signature Verification
from playvideo.webhook import verify_signature, construct_event
from playvideo.errors import WebhookSignatureError
# Flask example
@app.route("/webhook", methods=["POST"])
def webhook():
payload = request.get_data()
signature = request.headers.get("X-PlayVideo-Signature")
timestamp = request.headers.get("X-PlayVideo-Timestamp")
try:
event = construct_event(payload, signature, timestamp, "whsec_xxx")
match event["event"]:
case "video.completed":
print("Video ready:", event["data"])
case "video.failed":
print("Video failed:", event["data"])
return "OK", 200
except WebhookSignatureError as e:
print("Invalid signature:", e)
return "Invalid signature", 400
Error Handling
from playvideo import PlayVideo
from playvideo.errors import (
PlayVideoError,
AuthenticationError,
NotFoundError,
RateLimitError,
ValidationError,
)
client = PlayVideo("play_live_xxx")
try:
client.videos.get("invalid-id")
except AuthenticationError:
print("Invalid API key")
except NotFoundError:
print("Video not found")
except RateLimitError as e:
print(f"Rate limited. Retry after {e.retry_after}s")
except ValidationError as e:
print(f"Invalid param: {e.param}")
except PlayVideoError as e:
print(f"API error: {e.message} (code: {e.code})")
Error Types
| Error | Status | Description |
|---|---|---|
AuthenticationError |
401 | Invalid or missing API key |
AuthorizationError |
403 | Insufficient permissions |
NotFoundError |
404 | Resource not found |
ValidationError |
400/422 | Invalid parameters |
ConflictError |
409 | Resource conflict |
RateLimitError |
429 | Too many requests |
ServerError |
5xx | Server error |
NetworkError |
- | Connection failed |
TimeoutError |
- | Request timed out |
WebhookSignatureError |
- | Invalid signature |
Configuration
client = PlayVideo(
"play_live_xxx",
# Custom base URL (for self-hosted)
base_url="https://api.yourdomain.com/api/v1",
# Request timeout in seconds (default: 30)
timeout=60.0,
)
Context Managers
Both sync and async clients support context managers:
# Sync
with PlayVideo("play_live_xxx") as client:
collections = client.collections.list()
# Async
async with AsyncPlayVideo("play_live_xxx") as client:
collections = await client.collections.list()
Type Hints
The SDK includes full type hints for all methods and data classes:
from playvideo import PlayVideo, Video, Collection, VideoStatus
client = PlayVideo("play_live_xxx")
video: Video = client.videos.get("id")
status: VideoStatus = video.status # Literal["PENDING", "PROCESSING", "COMPLETED", "FAILED"]
MCP Server
Use the PlayVideo MCP server to connect Claude/Desktop assistants to your account.
npm install -g @playvideo/playvideo-mcp
Repo: https://github.com/PlayVideo-dev/playvideo-mcp
Contributing
We welcome contributions! Please see CONTRIBUTING.md for guidelines.
License
MIT - see LICENSE for details.
Links
Metadata
Release files for playvideo-python 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| playvideo_python-1.0.0.tar.gz | 22.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| playvideo_python-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 44.3 kB
Release files / playvideo_python-1.0.0.tar.gz
| Download URL | playvideo_python-1.0.0.tar.gz |
|---|---|
| Size | 22.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1f64b394b65892413243d1984c862e1c79ff5eab48499e720dfcb77e07a0f58e
|
|
BLAKE2b-256 checksum How to use checksums |
3533b12172eeb9bae65daab3d53aae0fbc22c629dc21fbaa044c8521a239f666
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jan 15, 2026.
Transparency logRelease files / playvideo_python-1.0.0-py3-none-any.whl
| Download URL | playvideo_python-1.0.0-py3-none-any.whl |
|---|---|
| Size | 21.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
61bd5455f1dbc79e92df3c2fcf9c6720fe49dea16d57e9a8223ad72fe185ded4
|
|
BLAKE2b-256 checksum How to use checksums |
f030f6038841b65c43a789a87098088fbcec60309c950b2e8e8642edbda44aed
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jan 15, 2026.
Transparency log