Skip to navigation

Run a workflow

Start a workflow run, watch it finish, and download the audio — in Python or the CLI.

A run executes a workflow’s pipeline and produces audio. Start a run, poll until it’s done, then download the result.

Start and watch a run

import time
from onepin import OnepinClient
client = OnepinClient()
# `paused` is not terminal, but it is not progressing either — stop waiting on it.
SETTLED = ("completed", "failed", "cancelled", "paused")
run = client.workflows.runs.start(workflow_id).data
while run.status not in SETTLED:
time.sleep(3)
run = client.workflows.runs.status(workflow_id, run.id).data
print(run.status, f"{run.finished_steps or 0}/{run.total_steps or 0}")
if run.status != "completed":
raise RuntimeError(f"run {run.status}: {run.error}")

There are no completion webhooks yet — polling is the way. Short scripts finish in seconds.

Runs can pause

A run isn’t only heading for completed, failed, or cancelled. It can also park in paused — and not just because someone asked it to. Onepin pauses a run automatically rather than burning retries against a problem that won’t resolve on its own:

pause_reasonWhat happened
userSomeone called pause
provider_outageThe TTS provider is down
provider_rate_limitedThe provider is throttling
provider_billingA provider billing problem blocked the call
node_timeoutA node ran past its deadline

A paused run keeps everything it has already produced — the current wave of parallel work is allowed to finish before it parks, so nothing in flight is thrown away. pause_error carries the customer-facing explanation, and held_nodes lists the nodes it is parked in front of.

Resume it when the cause has cleared, or stop it for good:

client.workflows.resume_run(workflow_id, run.id) # picks up from the last completed wave
client.workflows.runs.cancel(workflow_id, run.id) # give up on it instead

Pausing and resuming need at least the editor role in the workspace.

Download the result

A completed run’s export is a ZIP of the audio files plus a manifest.csv. The download URL is pre-signed and valid for 15 minutes.

import httpx
dl = client.workflows.download_run(workflow_id, run.id).data
resp = httpx.get(dl.url)
resp.raise_for_status()
with open(dl.filename, "wb") as f:
f.write(resp.content)

Only completed runs are downloadable — active, failed, or cancelled runs return 409, and a run with no audio returns 404.

List workflows and run history

for wf in client.workflows.list(limit=50).data:
print(wf.id, wf.name)
for r in client.workflows.runs.list(workflow_id, limit=20).data:
print(r.id, r.status, r.created_at)