Search Documentation
Search across all documentation pages
Python SDK

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 transcodely

Authenticate

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))
        break

Watch 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:

OptionDefaultNotes
api_key— required —Test or live API key
base_url"https://api.transcodely.com"Override for staging or self-hosted
timeout30.0Seconds; passed to httpx.Client
max_retries3Retries on network errors, 5xx, 429, 503 with jittered backoff
api_versioncalendar version baked at SDK build timeSent as Transcodely-Version
default_headersdict[str, str] — sent on every request
http_clientCustom httpx.Client (testing, custom transports)
loggerCallable 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).