Python SDK
Official Python SDK for CueAPI: install, client init, cues, executions, outcomes, webhook verification, and typed errors.
The official Python SDK for CueAPI. Schedule cues, report execution outcomes with evidence, and verify webhook signatures.
Install
pip install cueapi-sdkRequires Python 3.9+. Source: github.com/cueapi/cueapi-python.
Quick start
from cueapi import CueAPI
client = CueAPI("cue_sk_your_key")
cue = client.cues.create(
name="daily-report",
cron="0 9 * * *",
callback="https://my-app.com/webhook",
)
print(cue.id, cue.next_run_at)The client implements the context-manager protocol, so the underlying HTTP connection cleans up automatically:
with CueAPI("cue_sk_your_key") as client:
for cue in client.cues.list().cues:
print(cue.name)Client
CueAPI(api_key, *, base_url=..., timeout=...)
| Argument | Default | Description |
|---|---|---|
api_key | — (required) | Your API key (starts with cue_sk_). |
base_url | https://api.cueapi.ai | Override for self-hosted or staging environments. |
timeout | 30.0 | Request timeout in seconds. |
Methods: client.close() to release the HTTP pool. Resources: client.cues, client.executions.
client.cues
create(name, *, cron=None, at=None, ...)
Create a recurring or one-time cue. Provide either cron or at (not both).
# Recurring
cue = client.cues.create(
name="daily-sync",
cron="0 9 * * *",
timezone="America/Los_Angeles",
callback="https://api.example.com/sync",
)
# One-time
cue = client.cues.create(
name="reminder",
at="2026-05-01T14:00:00Z",
callback="https://api.example.com/notify",
)
# Worker transport (no callback URL needed)
cue = client.cues.create(
name="agent-task",
cron="0 * * * *",
transport="worker",
payload={"task": "summarize-inbox"},
)
# With on-failure escalation
cue = client.cues.create(
name="critical-job",
cron="*/5 * * * *",
callback="https://api.example.com/run",
on_failure={"after_attempts": 3, "notify": "[email protected]"},
)| Kwarg | Type | Description |
|---|---|---|
name | str | Required. Cue name. |
cron | str | Cron expression (use this or at). |
at | str | datetime | ISO timestamp for one-time cues. |
timezone | str | IANA timezone. Default "UTC". |
callback | str | Webhook URL. Omit for worker transport. |
callback_method | str | HTTP method. Default "POST". |
callback_headers | dict | Extra headers for webhook delivery. |
transport | str | "webhook" (default) or "worker". |
payload | dict | JSON delivered with each execution. |
description | str | Optional description. |
retry | dict | {max_attempts, backoff_minutes}. |
on_failure | dict | Escalation config (e.g. {after_attempts, notify}). |
list(*, limit=20, offset=0, status=None) -> CueList
Paginated listing. status filters to "active" or "paused".
get(cue_id) -> Cue
Fetch a single cue.
update(cue_id, *, name=None, cron=None, at=None, callback=None, payload=None, status=None, retry=None, on_failure=None, timezone=None, description=None) -> Cue
Patch a cue. Only provided fields are updated.
pause(cue_id) -> Cue / resume(cue_id) -> Cue
Convenience wrappers for update(cue_id, status=...).
delete(cue_id) -> None
Permanently delete a cue.
client.executions
report_outcome(execution_id, *, success, ...)
Write-once outcome report for an execution. Reporting twice raises an error server-side.
client.executions.report_outcome(
execution_id="exec_a1b2c3",
success=True,
summary="Generated 47 leads",
external_id="lead-batch-2026-04-19", # link to your system
result_ref="batch-id:7842", # short opaque reference
result_url="https://my-app.com/batches/7842",
result_type="lead-batch",
artifacts=[{"name": "leads.csv", "url": "https://..."}],
metadata={"agent": "lead-finder-v3"},
)| Kwarg | Type | Description |
|---|---|---|
execution_id | str | Required. The execution to report on. |
success | bool | Required. Was the execution successful? |
result | str | Free-form result text (truncated to 2000 chars when used via handle()). |
error | str | Free-form error text on failure. |
summary | str | Short human-readable summary. |
external_id | str | ID in your system for linking. |
result_ref | str | Short opaque reference (added in SDK 0.1.4). |
result_url | str | URL where the artifact lives. |
result_type | str | Tag for the result type ("report", "lead-batch", etc.). |
artifacts | list[dict] | Attached artifacts ([{name, url, ...}]). |
metadata | dict | Free-form metadata blob. |
The fields external_id, result_url, result_ref, result_type, summary, and artifacts together form the evidence surface used by verification modes.
handle(execution_id, payload=None) -> ExecutionContext
Context manager that auto-reports outcome based on whether the block exits cleanly.
with client.executions.handle(exec_id) as ctx:
result = do_work(ctx.payload)
ctx.result = f"Processed {result.count} records"
ctx.evidence = {"external_id": result.batch_id, "result_url": result.url}
# Clean exit -> POST success=True with result + evidence
# Exception -> POST success=False with stringified exceptionThe ctx.evidence dict is unpacked into report_outcome() kwargs on success.
list(*, cue_id=None, status=None, outcome_state=None, triggered_by=None, limit=20, offset=0) -> dict
List executions with optional filters.
get(execution_id) -> dict
Fetch a single execution.
heartbeat(execution_id) -> dict
Extend the worker's claim lease on a long-running execution. Worker transport only.
mark_verification_pending(execution_id) -> dict
Mark the outcome as pending verification (used when verification is async).
mark_verified(execution_id, *, valid=True, reason=None) -> dict
Complete verification on a previously-reported outcome.
Webhook signature verification
from cueapi import verify_webhook
# In your webhook handler
is_valid = verify_webhook(
payload=request.body,
signature=request.headers["X-CueAPI-Signature"],
timestamp=request.headers["X-CueAPI-Timestamp"],
secret="whsec_your_secret", # from /v1/auth/webhook-secret
tolerance=300, # max age in seconds
)
if not is_valid:
return Response(status=401)verify_webhook accepts the payload as bytes, str, or dict. It re-serializes JSON with sorted keys before comparing the HMAC-SHA256 digest, matching the server's signing convention.
Exceptions
All exceptions inherit from CueAPIError.
| Exception | Status | When |
|---|---|---|
AuthenticationError | 401 | Invalid API key. |
CueLimitExceededError | 403 | Plan limit hit (cues or executions). |
CueNotFoundError | 404 | Cue or execution doesn't exist. |
RateLimitError | 429 | Sliding-window rate limit exceeded. Has retry_after attr. |
InvalidScheduleError | 400 / 422 | Validation error (typically schedule). |
CueAPIServerError | 5xx | Server-side error. |
CueAPIError | other | Catch-all. |
from cueapi import CueAPI
from cueapi.exceptions import RateLimitError, CueNotFoundError
client = CueAPI("cue_sk_your_key")
try:
client.cues.get("cue_does_not_exist")
except CueNotFoundError:
print("not found")
except RateLimitError as e:
print(f"slow down — retry after {e.retry_after}s")Source
- PyPI: cueapi-sdk
- GitHub: cueapi/cueapi-python
- TypeScript SDK: see @cueapi/client