SDK quickstart
From pip install to a converted file in under five minutes. By the end you'll have run the same workflow from both Python and the shell, plus pre-flighted your plan + quota for any future calls.
1. Install
pip install convilyn
A single install gives you the Python library and the convilyn binary — no separate package, no extras needed.
Requires Python 3.10 or later. Type hints ship with the wheel (PEP 561), so mypy / pyright / pylance pick them up automatically.
2. Get an API key
Sign up, then create an API key from your Settings → API page (login required — the page also manages billing and quota). The key starts with ck_ and is shown only once. Export it so the SDK and CLI both pick it up:
export CONVILYN_API_KEY=ck_...
The CLI also accepts an explicit --api-key flag, but the environment variable is the recommended default — it works for both Python scripts and one-off shell commands.
3. Verify your setup
Run the doctor command first to catch any environment issues before hitting the API:
$ convilyn doctor
↑ [OK] Python: 3.11.9
↑ [OK] convilyn SDK: 1.0.0
↑ [OK] httpx: 0.28.1
↑ [OK] pydantic: 2.13.4
↑ [OK] click: 8.3.1
↑ [OK] CONVILYN_API_KEY: ck_xx…XXXX
↑ [OK] CONVILYN_BASE_URL: https://api.convilyn.com (default)
All checks passed.
Add --ping to also probe the backend's health endpoint and (when your key is set) surface your current billing tier:
$ convilyn doctor --ping
… [OK] Backend health: 200 OK
↑ [OK] Account tier: tier=free
4. Convert a file (Python)
The five-line hello-world:
from convilyn import Convilyn
client = Convilyn()
file = client.files.upload("report.docx")
job = client.convert.create_and_wait(file=file, target_format="pdf")
client.convert.download_to(job, to="report.pdf")
What just happened:
files.uploadgot a presigned upload URL from the API, streamed the file, and registered the upload with the backend.convert.create_and_waitstarted a document conversion job and polled until it finished (or failed).convert.download_tofetched the presigned download URL from the completed job and wrote the bytes to disk.
If any step fails (auth, transport, conversion error) you get a typed exception: AuthError, APIError, RetryExhaustedError, JobFailedError, JobTimeoutError. Catch the base ConvilynError to handle them all uniformly.
5. Convert a file (CLI)
The same workflow as a single command:
$ convilyn convert report.docx --to pdf
↑ Uploading report.docx (32.4 KiB)
▶ Creating conversion → pdf
… Converting… 100%
↓ Downloaded report.pdf
✓ report.pdf (28.1 KiB)
Pipe-friendly mode for shell pipelines and AI agents:
$ convilyn convert report.docx --to pdf --json | jq .
{
"command": "convert",
"file_id": "file_abc",
"job_id": "job_xyz",
"status": "completed",
"output_path": "report.pdf",
"output_size_bytes": 28798,
"elapsed_seconds": 3.4
}
Safe preview before spending an API call:
$ convilyn convert report.docx --to pdf --dry-run
↑ [dry-run] Would upload: report.docx
▶ [dry-run] Would POST /api/v1/jobs
↓ [dry-run] Would download to: report.pdf
[dry-run] No API calls made.
6. Call any endpoint (escape hatch)
The CLI ships a gh-style api sub-command for endpoints the SDK has not wrapped yet. Same auth, retry, and idempotency behaviour as the high-level commands.
# Inspect a job:
convilyn api GET /api/v1/jobs/job_xyz --json | jq .
# Hit an arbitrary endpoint:
convilyn api POST /api/v1/some/new/endpoint --data '{"x": 1}'
# Pipe a body in from a file or stdin:
convilyn api POST /api/v1/echo --input body.json
echo '{"x": 1}' | convilyn api POST /api/v1/echo --input -
Pair with --include to see the status line and headers (curl -i style), or -o file to write the body to disk silently.
7. Run an agentic workflow (Goal Lane)
The Goal Lane runs agentic workflows — the backend assembles a multi-step plan, calls MCP tools, and may stop to ask the user for clarification mid-flight. The surface mirrors the conversion API but adds HITL (fill_slot / confirm) and a WebSocket event stream.
client = Convilyn()
job = client.goals.run(workflow_id="doc_analyzer", files=["file_abc"])
while job.needs_input:
slot = job.pending_slots[0]
answer = input(f"{slot.question}: ")
job = client.goals.fill_slot(job.job_spec_id, slot_id=slot.slot_id, value=answer)
job = client.goals.confirm(job.job_spec_id)
job = client.goals.wait(job.job_spec_id)
print("final status:", job.status)
Live progress via WebSocket events (async only):
import asyncio
from convilyn import AsyncConvilyn
async def main():
async with AsyncConvilyn(ws_url="wss://ws.convilyn.com") as client:
job = await client.goals.start(workflow_id="doc_analyzer", files=["file_abc"])
async for ev in client.goals.events(job.job_spec_id):
print(ev.type, ev.data)
if ev.is_terminal:
break
asyncio.run(main())
Or from the shell as NDJSON:
$ JOB_ID=$(convilyn goals start --workflow-id doc_analyzer --files file_abc --json | jq -r '.job_spec_id')
$ convilyn goals events "$JOB_ID" --json | jq -c
$ convilyn goals fill-slot "$JOB_ID" --slot-id topic --value '"AI safety"'
$ convilyn goals status "$JOB_ID" --watch
8. Check your plan + quota before running (client.account)
Some Convilyn endpoints (fork a public workflow, publish your own, run an expensive goal-lane workflow) require a paid plan (Pro or Business). The SDK surfaces the platform's tier and quota model so you can pre-flight a call without parsing raw HTTP errors.
What tier am I on?
plan = client.account.get_plan()
print(plan.tier) # "free" | "pro"
Will this workflow fit my quota?
estimate = client.account.get_quota(
tools=["pdf-mcp:extract_text", "openai-mcp:summarise"],
max_iterations=25,
)
print(estimate.estimated_usd, estimate.quota_check.state)
# 0.0034 "ok" ← ready to run
# 0.5200 "soft_limit" ← pro caller is over the soft cap
# 0.5200 "quota_exceeded" ← free tier; running this would fail with QuotaExceededError
estimate.quota_check.upgrade_url points at the in-app pricing CTA when the verdict isn't "ok".
Typed errors when a paywall fires
from convilyn import APIError, PlanRequiredError, QuotaExceededError
try:
client.workflows.fork(source_spec_id="doc_analyzer")
except PlanRequiredError as exc:
print(f"upgrade required: {exc.upgrade_url}")
except QuotaExceededError as exc:
print(f"used {exc.estimated_micro_u}/{exc.threshold_micro_u} micro-U")
except APIError:
raise # transient or unknown — let the caller decide
Both billing exceptions subclass APIError, so existing except APIError: blocks keep working — opt into the typed handler only when you want to distinguish a paywall from a transient backend failure.
Same thing from the shell
$ convilyn account plan --json | jq -r .tier
free
$ convilyn account quota --tool pdf-mcp:extract_text --max-iter 25 --json | jq '.state'
"ok"
Both sub-commands exit 1 on PlanRequiredError or QuotaExceededError (the caller needs to act on billing, not retry the API). Transport / 5xx errors exit 2 as usual.
Free vs paid plans — at a glance
| Action | Free | Pro / Business |
|---|---|---|
client.convert (Turbo Lane) | ✅ within cap | ✅ within cap |
client.goals (Goal Lane run) | ✅ within cap | ✅ higher cap |
client.workflows.fork (private copy of a public workflow) | ❌ PlanRequiredError | ✅ |
client.workflows.publish (make your workflow public) | ❌ PlanRequiredError | ✅ |
9. Going further
- Async API: use
AsyncConvilynif you're inside an event loop; every method has an async counterpart with the same signature. - Custom retry policy: pass
retry_policy=to the constructor to replace the default exponential backoff. The protocol is two methods:should_retry()andnext_delay(). - Bring-your-own transport: every resource accepts an
HTTPClientvia the constructor so you can inject mock transports for testing. - Authoring your own workflows / tool servers: install the author SDK —
pip install convilyn-sdk— the package ships its own deployment guide covering the three supported targets (containerized Lambda, Fargate, and any HTTPS-reachable VM).
Common questions
Which formats are supported? Document conversion between DOCX / PDF / PPTX / TXT / HTML / Markdown / RTF / ODT today. Additional processor types (image conversion, OCR, media processing, PDF operations, compression) ship as additional SDK methods in subsequent releases.
What if a job takes more than five minutes?
The default convert.create_and_wait timeout is five minutes; override with timeout=.... After timeout the job is still alive on the backend — call client.convert.retrieve(job.job_id) to fetch its current state.
How do I get HTTP traces for debugging?
Set CONVILYN_DEBUG=1 to surface full repr / stacktraces from CLI errors. The SDK uses httpx underneath, so standard httpx debug hooks work via the underlying client.
What's the difference between convilyn and convilyn-sdk packages?
convilyn is the consumer SDK (what you call the API with). convilyn-sdk is the author SDK (what third parties use to BUILD tool servers + workflow specs FOR Convilyn). They're separate packages so the consumer SDK stays lightweight; the author SDK pulls in server-side dependencies that consumers don't need. The author SDK ships a convilyn-author CLI binary; the consumer SDK ships convilyn.