Skip to main content

Install

pip install lavendly
from lavendly import Lavendly
import os

vs = Lavendly(api_key=os.environ["LAVENDLY_API_KEY"])

A render in 10 lines

wf = vs.workflows.create(
    name="Fox in a bookshop",
    shots=[{"prompt": "a sleepy fox in a bookshop discovering an old map",
            "duration": 5}],
)

video = vs.renders.run(wf.id)   # creates a render and polls to done
print(video.url)

Narrated short with music

wf = vs.workflows.create(
    name="Barista at dawn",
    shots=[{"prompt": "a barista pulling an espresso shot at dawn",
            "duration": 6}],
)

vs.audio.attach_track(
    wf.id, "shot_1",
    kind="voiceover",
    script="Forty seconds. The whole café holds its breath.",
    subtitle_style="tiktok",
    idempotency_key=f"vo-{wf.id}",
)

vs.audio.attach_track(
    wf.id, "shot_1",
    kind="music",
    mood="warm low jazz piano",
    ducking=True,
    volume=0.4,
    idempotency_key=f"music-{wf.id}",
)

vs.audio.set_clip_native_audio(
    wf.id, "shot_1",
    mode="mix", volume=0.6,
)

video = vs.renders.run(wf.id, idempotency_key=f"render-{wf.id}")
print(video.url)

Async variant

For a concurrent agent, the SDK ships an AsyncLavendly:
import asyncio
from lavendly import AsyncLavendly

async def render_one(brief):
    async with AsyncLavendly(api_key=os.environ["LAVENDLY_API_KEY"]) as lavendly:
        wf = await vs.workflows.create(name=brief["name"], shots=brief["shots"])
        return await vs.renders.run(wf.id)

results = await asyncio.gather(*(render_one(b) for b in briefs))

Polling manually

job = vs.renders.create(wf.id, idempotency_key=f"render-{wf.id}")

while True:
    status = vs.renders.get(wf.id, job.job_id)
    print(f"{status.status}, {int(status.progress * 100)}%")
    if status.status == "done":
        return status.result.video_url
    if status.status == "failed":
        raise RuntimeError(status.error)
    time.sleep(4)

Budget discipline

ledger = vs.ledger.get()
if ledger.available < 20:
    raise RuntimeError(f"Budget too low: {ledger.available} credits")

usage = vs.usage.monthly()
if usage.fraction_used > 0.85:
    print("Monthly budget over 85%, pausing")
    return

Error handling

Every SDK exception carries the API error envelope:
from lavendly import LavendlyError

try:
    vs.workflows.create(name="huge", shots=big_list)
except LavendlyError as err:
    print(err.code)     # 'workflow_too_large'
    print(err.message)  # human-readable
    print(err.status)   # 413
See Errors for the full code list.

Driving the agent skills from Python

If you’re embedding Lavendly in an agent runtime and want the skill files inline:
from lavendly.skills import load_skill

skill_text = load_skill("storyteller")     # returns the markdown body
system_prompt = base_prompt + "\n\n" + skill_text
The lavendly.skills module ships the first-party skill bodies so you don’t have to vendor markdown by hand.