|
| 1 | +# CueAPI Python SDK |
| 2 | + |
| 3 | +The official Python SDK for [CueAPI](https://cueapi.ai) — scheduling infrastructure for agents. |
| 4 | + |
| 5 | +## Install |
| 6 | + |
| 7 | +```bash |
| 8 | +pip install cueapi-sdk |
| 9 | +``` |
| 10 | + |
| 11 | +## Quickstart |
| 12 | + |
| 13 | +```python |
| 14 | +from cueapi import CueAPI |
| 15 | + |
| 16 | +client = CueAPI("cue_sk_your_key") |
| 17 | +cue = client.cues.create( |
| 18 | + name="daily-report", |
| 19 | + cron="0 9 * * *", |
| 20 | + callback="https://my-app.com/webhook", |
| 21 | + payload={"task": "generate_report"}, |
| 22 | +) |
| 23 | +print(f"Next run: {cue.next_run}") |
| 24 | +``` |
| 25 | + |
| 26 | +## Why CueAPI? |
| 27 | + |
| 28 | +- **Replace fragile cron jobs** — managed scheduling with automatic retries, execution logs, and failure alerts. No servers to maintain. |
| 29 | +- **Built for AI agents** — schedule agent tasks, coordinate multi-agent pipelines, and retry failed workflows with exponential backoff. |
| 30 | +- **Two transport modes** — webhook delivery to your public URL, or worker pull for agents behind firewalls. |
| 31 | + |
| 32 | +## Transport Modes |
| 33 | + |
| 34 | +### Webhook |
| 35 | + |
| 36 | +CueAPI POSTs a signed payload to your callback URL when a cue fires: |
| 37 | + |
| 38 | +```python |
| 39 | +cue = client.cues.create( |
| 40 | + name="webhook-task", |
| 41 | + cron="0 9 * * *", |
| 42 | + callback="https://my-app.com/webhook", |
| 43 | + payload={"action": "sync"}, |
| 44 | +) |
| 45 | +``` |
| 46 | + |
| 47 | +### Worker |
| 48 | + |
| 49 | +Your local daemon polls CueAPI for executions. No public URL needed: |
| 50 | + |
| 51 | +```python |
| 52 | +cue = client.cues.create( |
| 53 | + name="worker-task", |
| 54 | + cron="0 */6 * * *", |
| 55 | + transport="worker", |
| 56 | + payload={"pipeline": "etl"}, |
| 57 | +) |
| 58 | +``` |
| 59 | + |
| 60 | +Install the worker: `pip install cueapi-worker` |
| 61 | + |
| 62 | +## Method Reference |
| 63 | + |
| 64 | +### `CueAPI(api_key, *, base_url, timeout)` |
| 65 | + |
| 66 | +Create a client. `api_key` starts with `cue_sk_`. |
| 67 | + |
| 68 | +### `client.cues.create(...)` |
| 69 | + |
| 70 | +| Parameter | Type | Description | |
| 71 | +|---|---|---| |
| 72 | +| `name` | `str` | **Required.** Unique name for the cue. | |
| 73 | +| `cron` | `str` | Cron expression for recurring schedules. | |
| 74 | +| `at` | `str \| datetime` | ISO 8601 datetime for one-time schedules. | |
| 75 | +| `timezone` | `str` | IANA timezone (default `"UTC"`). | |
| 76 | +| `callback` | `str` | Webhook URL for execution delivery. | |
| 77 | +| `transport` | `str` | `"webhook"` (default) or `"worker"`. | |
| 78 | +| `payload` | `dict` | JSON payload included in each execution. | |
| 79 | +| `description` | `str` | Optional description. | |
| 80 | +| `retry` | `dict` | `{"max_attempts": 3, "backoff_minutes": [1, 5, 15]}` | |
| 81 | +| `on_failure` | `dict` | `{"email": true, "webhook": null, "pause": false}` | |
| 82 | + |
| 83 | +Returns a `Cue` object. |
| 84 | + |
| 85 | +### `client.cues.list(*, limit, offset, status)` |
| 86 | + |
| 87 | +Returns a `CueList` with `.cues`, `.total`, `.limit`, `.offset`. |
| 88 | + |
| 89 | +### `client.cues.get(cue_id)` |
| 90 | + |
| 91 | +Returns a `Cue` object. |
| 92 | + |
| 93 | +### `client.cues.update(cue_id, **fields)` |
| 94 | + |
| 95 | +Update any field. Only provided fields are changed. |
| 96 | + |
| 97 | +### `client.cues.pause(cue_id)` |
| 98 | + |
| 99 | +Pause a cue. Returns the updated `Cue`. |
| 100 | + |
| 101 | +### `client.cues.resume(cue_id)` |
| 102 | + |
| 103 | +Resume a paused cue. Returns the updated `Cue`. |
| 104 | + |
| 105 | +### `client.cues.delete(cue_id)` |
| 106 | + |
| 107 | +Delete a cue. Returns `None`. |
| 108 | + |
| 109 | +## Webhook Verification |
| 110 | + |
| 111 | +Verify incoming webhook signatures in your handler: |
| 112 | + |
| 113 | +```python |
| 114 | +from cueapi import verify_webhook |
| 115 | + |
| 116 | +is_valid = verify_webhook( |
| 117 | + payload=request.body, |
| 118 | + signature=request.headers["X-CueAPI-Signature"], |
| 119 | + timestamp=request.headers["X-CueAPI-Timestamp"], |
| 120 | + secret="whsec_your_secret", |
| 121 | +) |
| 122 | +``` |
| 123 | + |
| 124 | +## Error Handling |
| 125 | + |
| 126 | +```python |
| 127 | +from cueapi import CueAPI, AuthenticationError, RateLimitError, CueNotFoundError |
| 128 | + |
| 129 | +try: |
| 130 | + cue = client.cues.get("cue_abc123") |
| 131 | +except CueNotFoundError: |
| 132 | + print("Cue not found") |
| 133 | +except AuthenticationError: |
| 134 | + print("Invalid API key") |
| 135 | +except RateLimitError as e: |
| 136 | + print(f"Rate limited. Retry after {e.retry_after}s") |
| 137 | +``` |
| 138 | + |
| 139 | +| Exception | HTTP Status | When | |
| 140 | +|---|---|---| |
| 141 | +| `AuthenticationError` | 401 | Invalid or missing API key | |
| 142 | +| `CueLimitExceededError` | 403 | Plan cue limit reached | |
| 143 | +| `CueNotFoundError` | 404 | Cue ID doesn't exist | |
| 144 | +| `InvalidScheduleError` | 400/422 | Bad cron expression or request body | |
| 145 | +| `RateLimitError` | 429 | Too many requests | |
| 146 | +| `CueAPIServerError` | 5xx | Server error | |
| 147 | + |
| 148 | +## Links |
| 149 | + |
| 150 | +- [Documentation](https://docs.cueapi.ai) |
| 151 | +- [API Reference](https://docs.cueapi.ai/api-reference/overview/) |
| 152 | +- [Dashboard](https://dashboard.cueapi.ai) |
| 153 | +- [CueAPI](https://cueapi.ai) |
0 commit comments