Python SDK
transcodely is the official Python SDK for the Transcodely API. It runs on Python 3.10+, uses httpx under the hood, and ships a hand-rolled JSON codec so requests and responses round-trip the API’s snake_case + lowercase-enum wire format transparently. The SDK is alpha (0.1.0) — breaking changes are possible on minor bumps until 1.0.0.
The 0.1.0 release is synchronous-only. An async client is planned for a future release; until it ships, drive concurrent calls with concurrent.futures or threads.
Install
pip install transcodely
# or
uv add transcodely
# or
poetry add transcodelyAuthenticate
The SDK takes the API key as an explicit constructor argument. The conventional environment variable is TRANSCODELY_API_KEY. Use the context-manager form so the underlying httpx.Client is closed cleanly on exit:
import os
from transcodely import Transcodely
with Transcodely(api_key=os.environ["TRANSCODELY_API_KEY"]) as client:
...If you need a long-lived client (e.g. a web server), construct it once at startup and call client.close() on shutdown. Test (ak_test_*) and live (ak_live_*) keys hit the same base URL — the environment is encoded in the prefix.
Create your first job
Resource methods live under attribute namespaces (client.jobs, client.videos, etc.) and accept keyword arguments matching the API’s snake_case JSON field names.
import os
from transcodely import Transcodely
with Transcodely(api_key=os.environ["TRANSCODELY_API_KEY"]) as client:
job = client.jobs.create(
input_url="https://storage.example.com/source.mp4",
output_origin_id="ori_x9y8z7w6v5",
outputs=[
{
"type": "hls",
"video": [
{"codec": "h264", "resolution": "1080p"},
{"codec": "h264", "resolution": "720p"},
],
}
],
)
print(job.id, job.status)The simplified-string form ("hls", "h264", "1080p") is what the API emits over the wire — the SDK round-trips it transparently to and from the proto enum integers.
Watch a job to completion
client.jobs.watch(job.id) returns an iterator that yields one event per state change, auto-reconnects on transient network failures, and filters HEARTBEAT events by default.
from transcodely.v1 import job_pb2
terminal = {
job_pb2.JOB_STATUS_COMPLETED,
job_pb2.JOB_STATUS_FAILED,
job_pb2.JOB_STATUS_CANCELED,
}
for event in client.jobs.watch(job.id):
print(event.event, event.job.status, event.job.progress)
if event.job.status in terminal:
print("terminal:", job_pb2.JobStatus.Name(event.job.status))
breakWatch is read-only and idempotent: every reconnect re-emits a SNAPSHOT event so the consumer never misses the current state. Wrap the loop in try / except KeyboardInterrupt if you want clean Ctrl-C handling.
List with auto-pagination
list methods return a Page you can read directly for one page, or call .auto_paging_iter() to walk every result.
# Single page
page = client.jobs.list(pagination={"limit": 50})
print(page.items, page.next_cursor)
# All items, automatically across pages
for job in client.jobs.list(pagination={"limit": 50}).auto_paging_iter():
print(job.id, job.status)auto_paging_iter stops when the API returns an empty next_cursor. See Pagination for cursor semantics.
Handle typed errors
Every exception inherits from TranscodelyError. Match on concrete classes with isinstance (or use except clauses directly):
import time
from transcodely import (
Transcodely,
TranscodelyError,
AuthenticationError,
NotFoundError,
RateLimitError,
InvalidRequestError,
)
try:
client.jobs.create(input_url="...", outputs=[])
except InvalidRequestError as err:
for v in err.errors:
print(f"{v.field}: {v.description}")
except RateLimitError as err:
time.sleep((err.retry_after_ms or 1000) / 1000)
except NotFoundError as err:
print(f"not found: {err}")
except AuthenticationError:
print("bad API key")
except TranscodelyError as err:
print(f"[{err.request_id}] {err.code}: {err}")Every error carries code, http_status, request_id, and raw (the original response body) for debugging. See Errors for the full hierarchy.
Override idempotency
client.jobs.create auto-generates a UUID v4 Idempotency-Key so retrying within the same process is safe. For cross-process safety (queue workers, cron jobs), pass your own key:
client.jobs.create(
input_url="...",
output_origin_id="ori_x9y8z7w6v5",
outputs=[...],
idempotency_key=f"transcode_asset_{asset_id}_v1",
)All other write methods ship an Idempotency-Key automatically. See Idempotency for replay semantics.
Request IDs
The most recent request ID is exposed for log correlation:
client.jobs.get("job_a1b2c3d4e5f6")
print(client.last_request_id) # "req_..."Errors also carry err.request_id directly.
Configuration
Pass any of these to the constructor:
| Option | Default | Notes |
|---|---|---|
api_key | — required — | Test or live API key |
base_url | "https://api.transcodely.com" | Override for staging or self-hosted |
timeout | 30.0 | Seconds; passed to httpx.Client |
max_retries | 3 | Retries on network errors, 5xx, 429, 503 with jittered backoff |
api_version | calendar version baked at SDK build time | Sent as Transcodely-Version |
default_headers | — | dict[str, str] — sent on every request |
http_client | — | Custom httpx.Client (testing, custom transports) |
logger | — | Callable receiving structured LogEvent objects |
client = Transcodely(
api_key=os.environ["TRANSCODELY_API_KEY"],
timeout=60.0,
max_retries=5,
default_headers={"X-Caller": "ingest-worker"},
logger=lambda event: print(event.kind, event.request_id, event.duration_ms),
)Where to go next
- API Reference — the full RPC surface.
- Webhook Integration — verify signed deliveries and handle events with
construct_event. - Errors — the typed error hierarchy in one place.
- Pagination — cursor model and auto-paging idioms.
- Idempotency — when and how to set your own key.
- SDK source on GitHub — full source and four runnable examples in
examples/(01_create_job.py,02_watch_job.py,03_pagination.py,04_error_handling.py).