Python SDK

Use synchronous or asynchronous Python clients to validate videos, manage projects, and export files.

indream-client 1.1.0 supports Python 3.10 or later. It includes synchronous and asynchronous clients, typed responses, uploads, export polling and cancellation, and webhook verification.

Install

python -m pip install indream-client==1.1.0
curl --fail --output editor-state.json https://docs.indream.ai/examples/editor-state.json

Validate and export

Save this as quick_start.py beside the downloaded sample. Replace the API-key placeholder and run it on your server.

quick_start.py
import json
from pathlib import Path

from indream import IndreamClient

editor_state = json.loads(Path("editor-state.json").read_text())
with IndreamClient(api_key="<YOUR_API_KEY>") as client:
    validation = client.editor.validate(editor_state)
    if not validation.valid:
        raise ValueError(validation.errors)

    created = client.exports.create({
        "editorState": editor_state,
        "stateSchemaVersion": "v1",
        "ratio": "16:9",
        "scale": 1,
        "fps": 30,
        "format": "mp4",
        "filename": "hello-indream.mp4",
    })
    print("Export:", created.task_id)
    completed = client.exports.wait(created.task_id, timeout=600, poll_interval=2)
    print(completed.status, completed.output_url)
python quick_start.py

Download the file from the completed task's output_url and save a copy if you need to retain it. Exports explains task states, output settings, and cancellation.

JSON request fields keep their API names, such as stateSchemaVersion. Typed Python response attributes use snake case, such as task_id, filename, export_phase, and billed_standard_seconds.

Use the asynchronous client

import asyncio
import json
from pathlib import Path

from indream import AsyncIndreamClient

async def main() -> None:
    editor_state = json.loads(Path("editor-state.json").read_text())
    async with AsyncIndreamClient(api_key="<YOUR_API_KEY>") as client:
        created = await client.exports.create({
            "editorState": editor_state,
            "stateSchemaVersion": "v1",
            "ratio": "16:9",
            "scale": 1,
            "fps": 30,
            "format": "mp4",
        })
        completed = await client.exports.wait(created.task_id, timeout=600)
        print(completed.output_url)

asyncio.run(main())

Use the context managers to close the client's connections even when a request fails.

Save a project and upload a file

The following calls assume client is open and editor_state contains the sample:

project = client.projects.create({
    "title": "Product introduction",
    "editorState": editor_state,
    "stateSchemaVersion": "v1",
})
asset = client.uploads.upload(
    Path("hero.png").read_bytes(),
    filename="hero.png",
    content_type="image/png",
    project_id=project.project_id,
)
print(asset.asset_id)

To save a changed draft, call client.projects.sync(project.project_id, {"editorState": editor_state, "stateSchemaVersion": "v1"}). To export the saved draft, call client.projects.create_export(project.project_id, output_settings).

An uploaded asset needs a corresponding asset and item in editor state before it appears in the video. See Assets.

Track and cancel work

client.exports.get(task_id) returns the current task. client.exports.list(page_size=20) returns items and next_page_cursor. Pass that cursor as page_cursor to continue.

client.exports.wait returns a completed task. Failure or cancellation raises APIError with TASK_TERMINAL_FAILURE. A wait timeout raises TimeoutError and leaves the server task running. To cancel it, call client.exports.cancel(task_id).

Handle request errors

Catch APIError or its subclasses AuthError, ValidationError, and RateLimitError. Inspect the problem's error code before choosing a recovery action. An API-key usage cap is not temporary throttling.

Set timeout for individual HTTP requests and max_retries for eligible transient failures. The client does not automatically repeat uploads or arbitrary writes. For an export that may be retried, pass a stable idempotency_key and keep its payload unchanged.

See Errors and retries for quota, validation, and permission failures.

Verify a webhook

Use verify_export_webhook_request with the exact raw body and received headers, then validate the parsed JSON with ExportWebhookEvent:

import json
from indream import verify_export_webhook_request
from indream.types import ExportWebhookEvent

def parse_event(raw_body: str, headers: dict[str, str], webhook_secret: str):
    if not verify_export_webhook_request(
        webhook_secret=webhook_secret,
        raw_body=raw_body,
        headers=headers,
        max_skew_seconds=300,
    ):
        raise ValueError("Invalid webhook signature.")
    return ExportWebhookEvent.model_validate(json.loads(raw_body))

Read Webhooks for event types and durable delivery handling.

Source and issues: indream-client-python on GitHub. Package: indream-client on PyPI.

Last updated on

On this page