Convilyn developers

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:

  1. files.upload got a presigned upload URL from the API, streamed the file, and registered the upload with the backend.
  2. convert.create_and_wait started a document conversion job and polled until it finished (or failed).
  3. convert.download_to fetched 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

ActionFreePro / 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 AsyncConvilyn if 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() and next_delay().
  • Bring-your-own transport: every resource accepts an HTTPClient via 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.