Unofficial Python SDK for the OPUS workflow automation platform
Project description
opus-aaico
Unofficial Python SDK for the OPUS workflow automation platform by AAICO.
Overview
opus-aaico provides a type-safe, production-ready interface to the OPUS REST API. It covers all 64 API endpoints across 8 resource modules, with both synchronous and asynchronous clients.
Key capabilities:
- Full API coverage -- all OPUS endpoints wrapped in typed Python methods
- Sync and async --
OpusClientfor scripts,AsyncOpusClientfor high-throughput services - High-level orchestration --
workflows.run()handles the entire job lifecycle in one call - Type safety -- Pydantic v2 models for all requests and responses
- Resilient -- automatic retry with exponential backoff on transient failures
- Minimal footprint -- only two runtime dependencies (
httpx,pydantic)
Installation
pip install opus-aaico
Requires Python 3.9 or later.
Quick Start
from opus_aaico import OpusClient
client = OpusClient(api_key="your-api-key")
# Run a workflow end-to-end: initiate, execute, poll, and return results
result = client.workflows.run(
workflow_id="wf-123",
payload={"query": {"value": "Analyze this document", "type": "str"}},
)
print(result.status) # "COMPLETED"
print(result.outputs) # Workflow output variables
print(result.execution_time) # Seconds elapsed
Authentication
from opus_aaico import OpusClient
# Option 1: Pass directly
client = OpusClient(api_key="sk-...")
# Option 2: With workspace context
client = OpusClient(
api_key="sk-...",
workspace_id="ws-...",
)
# Option 3: From environment variables
# Set OPUS_API_KEY, OPUS_WORKSPACE_ID (optional), OPUS_BASE_URL (optional)
client = OpusClient()
| Environment Variable | Purpose |
|---|---|
OPUS_API_KEY |
API key (required if not passed to constructor) |
OPUS_WORKSPACE_ID |
Default workspace ID |
OPUS_BASE_URL |
Override base URL for staging or self-hosted instances |
Resources
The client organizes the API into resource namespaces:
| Resource | Description | Key Methods |
|---|---|---|
client.workflows |
Workflow management and orchestration | get, list, generate, run, share, send_email |
client.jobs |
Job lifecycle | initiate, execute, get_status, get_results, poll, search |
client.files |
File upload, download, and search | upload, download, search, generate, multipart_upload |
client.reviews |
Human review and task management | initiate, list, get, pick, submit_result, submit_output |
client.api_keys |
API key management | create, list, rotate, revoke, delete |
client.credits |
Credit balance and usage tracking | get_balance, get_usage, record_usage |
client.policies |
Organizational policy management | upload, list, get, get_summary, set_active |
client.users |
User and project lookups | list, list_projects, get_projects |
Usage Examples
Run a Workflow
from opus_aaico import OpusClient
client = OpusClient(api_key="sk-...")
# High-level: one call handles initiate -> execute -> poll -> results
result = client.workflows.run(
workflow_id="wf-123",
payload={
"query": {"value": "Summarize this report", "type": "str"},
"document": {"value": "https://files.opus.com/doc.pdf", "type": "file"},
},
title="Q1 Report Analysis",
poll_interval=2.0, # seconds between status checks
timeout=300, # max wait time in seconds
)
print(result.status)
print(result.job_id)
print(result.outputs)
print(result.execution_time)
Upload a File
# Upload a local file (handles presigned URL flow automatically)
file_url = client.files.upload("./report.pdf")
# Use it in a workflow
result = client.workflows.run(
workflow_id="wf-123",
payload={
"document": {"value": file_url, "type": "file"},
},
)
Low-Level Job Control
# Step-by-step control when you need it
job = client.jobs.initiate(
workflow_id="wf-123",
title="My Job",
description="Processing data",
)
client.jobs.execute(
job_execution_id=job.job_execution_id,
payload={"query": {"value": "Analyze", "type": "str"}},
)
# Poll until complete
status = client.jobs.poll(job.job_execution_id, timeout=120)
if status.status.value == "COMPLETED":
results = client.jobs.get_results(job.job_execution_id)
audit = client.jobs.get_audit(job.job_execution_id)
Search and List
# Search jobs
jobs = client.jobs.search(
workflow_id="wf-123",
status=["COMPLETED", "FAILED"],
start_date="2026-01-01",
max_results=50,
)
# List workflows
workflows = client.workflows.list(
query="onboarding",
active=True,
)
Async Usage
import asyncio
from opus_aaico import AsyncOpusClient
async def main():
async with AsyncOpusClient(api_key="sk-...") as client:
# Run multiple workflows concurrently
tasks = [
client.workflows.run(
workflow_id="wf-123",
payload={"query": {"value": f"Task {i}", "type": "str"}},
)
for i in range(5)
]
results = await asyncio.gather(*tasks)
for r in results:
print(f"{r.job_id}: {r.status}")
asyncio.run(main())
Error Handling
All errors inherit from OpusError. Catch specific exceptions or the base class:
from opus_aaico import (
OpusClient,
AuthenticationError,
NotFoundError,
RateLimitError,
ValidationError,
PermissionDeniedError,
OpusError,
)
try:
result = client.workflows.run("wf-123", payload={...})
except AuthenticationError:
# 401 -- invalid API key
pass
except NotFoundError:
# 404 -- workflow does not exist
pass
except RateLimitError as e:
# 429 -- retry after e.retry_after seconds
pass
except ValidationError:
# 400 -- invalid request parameters
pass
except PermissionDeniedError:
# 403 -- insufficient permissions
pass
except OpusError as e:
# Any other API error
print(f"{e.message} (status={e.status_code})")
Error hierarchy:
OpusError
├── AuthenticationError (401)
├── PermissionDeniedError (403)
├── NotFoundError (404)
├── ValidationError (400)
├── RateLimitError (429) -- includes retry_after
├── APIError (5xx)
├── TimeoutError (request or polling timeout)
└── ConnectionError (network failure)
The SDK automatically retries on 429 and 5xx errors with exponential backoff (up to 3 retries by default).
Configuration
client = OpusClient(
api_key="sk-...", # required (or set OPUS_API_KEY)
workspace_id="ws-...", # optional default workspace
base_url="https://operator.opus.com", # override for staging
timeout=30.0, # request timeout in seconds
max_retries=3, # retries on transient failures
)
Both OpusClient and AsyncOpusClient support context managers for proper connection cleanup:
with OpusClient(api_key="sk-...") as client:
result = client.workflows.run("wf-123", payload={...})
Architecture
src/opus_aaico/
├── __init__.py # Public API: OpusClient, AsyncOpusClient, errors
├── _client.py # HTTP layer: auth, retry, request handling
├── _sync.py # OpusClient (synchronous)
├── _async.py # AsyncOpusClient (asynchronous)
├── _exceptions.py # Typed error hierarchy
├── _constants.py # Base URL, defaults, version
├── _cli.py # CLI entry point (opus-aaico command)
├── resources/ # One module per API resource
│ ├── workflows.py # Workflow CRUD + run() orchestrator
│ ├── jobs.py # Job lifecycle + polling
│ ├── files.py # File upload/download + multipart
│ ├── reviews.py # Human review management
│ ├── api_keys.py # API key CRUD
│ ├── credits.py # Credit tracking
│ ├── policies.py # Policy management
│ └── users.py # User and project lookups
├── types/ # Pydantic v2 models for all DTOs
│ ├── enums.py # JobStatus, ReviewType, etc.
│ ├── shared.py # Base model, UserDetails, etc.
│ ├── workflows.py # Workflow, WorkflowRunResult, etc.
│ ├── jobs.py # JobAudit, JobSearchItem, etc.
│ └── ... # One file per resource
└── _utils/
├── polling.py # Exponential backoff polling
└── files.py # Presigned URL upload helpers
Design principles:
- Resource-based namespacing following the OpenAI/Stripe SDK pattern
- Async-first internals with sync wrapper using httpx's dual transport
- camelCase to snake_case conversion handled automatically by Pydantic aliases
- Minimal dependencies -- only
httpxandpydanticat runtime
Development
See CONTRIBUTING.md for setup instructions and development workflow.
Changelog
See CHANGELOG.md for release history.
License
MIT License. See LICENSE for details.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file opus_aaico-0.4.0.tar.gz.
File metadata
- Download URL: opus_aaico-0.4.0.tar.gz
- Upload date:
- Size: 41.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7edfe21a7d65669472d1994e37df2df16f0024ad1f809c35630460b11b73f0f5
|
|
| MD5 |
8e28c0267cfd596b54c61a71a10fc0b3
|
|
| BLAKE2b-256 |
58da2b98f3bc767e392868acd60255317c1e673d67649bd20a336fab47b06c4e
|
File details
Details for the file opus_aaico-0.4.0-py3-none-any.whl.
File metadata
- Download URL: opus_aaico-0.4.0-py3-none-any.whl
- Upload date:
- Size: 35.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
492e5a9c71682b7ca1f11fc61b729698e67972a0542cf82afafe9ca5ec764b8f
|
|
| MD5 |
cb532d8c1a9c290ec545db9ed0c0d52f
|
|
| BLAKE2b-256 |
38879083e313b5946f8b36c165f06cee538aef4cbd91fbba42d78ff94fae5d0c
|