Tasks & Events
Track task status, reconcile from the durable event log, apply idempotency keys, and stay within rate limits.
Every accepted send creates a task. This page covers the operational contract that sits underneath every send: task status, the durable event log, idempotency, and rate limits.
Tasks
Every send returns a task_id in its 202 response. Use it to check progress or cancel a run in progress.
Get a task
GET /v1/projects/{project_id}/tasks/{task_id}{
"id": "b3f1c9a2-4e5d-4f6a-8b7c-9d0e1f2a3b4c",
"project_id": "prj_6efcfced-a176-4e4c-a989-9767c16fddf7",
"conversation_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"adw_id": "abc12345",
"agent_id": "a1b2c3d4-...",
"status": "completed",
"created_at": "2026-07-01T12:00:00Z",
"started_at": "2026-07-01T12:00:01Z",
"finished_at": "2026-07-01T12:00:14Z"
}| Status | Meaning |
|---|---|
queued | Accepted, not yet started. |
running | The agent is actively processing the message. |
waiting_input | Task is paused pending additional input. |
completed | Finished successfully; the reply has been delivered/queued for delivery. |
failed | Finished with an error; see error (present only when set). |
canceled | Canceled via the cancel endpoint before finishing. |
timed_out | Did not finish within the allowed processing time. |
List tasks for a conversation
GET /v1/projects/{project_id}/conversations/{conversation_id}/tasksReturns {"tasks": [...]}, newest first, with task objects in the same shape as above. ?limit= defaults to 50 (max 200).
Cancel a running task
POST /v1/projects/{project_id}/tasks/{task_id}/cancel- Success:
200with the updated task object (status: "canceled"). 409if the task has already finished (completed,failed,canceled, ortimed_out).
Event Log and Reconciliation
Every task change (task.created, task.running, task.completed, task.failed, task.canceled, ...) is recorded in a durable, per-project event log, and so is every assistant reply sent to a webhook (message.assistant, written only when the conversation or project has a response webhook). Webhooks are a convenience layer over this log, not the source of truth.
GET /v1/projects/{project_id}/api/events?since_id=&limit={
"events": [
{
"id": "01J8X9K3QYRZTS9V0N7M6P5C2A",
"type": "message.assistant",
"sequence": 42,
"payload": { "conversation_id": "telegram-123456789", "message": { "content": "..." } }
}
],
"has_more": false
}idis a ULID, sortable by creation order.typevalues includemessage.assistant,task.created,task.completed, and other lifecycle events.sequenceis a per-conversation monotonically increasing counter.
Webhooks are a convenience over this log. After downtime or a missed delivery, catch up by polling /api/events from your last processed event id.
Idempotency
Send an idempotency key
Include an Idempotency-Key header with any caller-generated unique string, or rely on external_message_id in the request body, which also works as an implicit idempotency key when no Idempotency-Key header is sent.
curl -X POST 'https://charlie-back.cloud-station.io/v1/projects/PROJECT_ID/conversations/my-conversation-1/messages' \
-H 'Content-Type: application/json' \
-H 'x-api-key: YOUR_API_KEY' \
-H 'x-client-id: YOUR_CLIENT_ID' \
-H 'Idempotency-Key: telegram:123456789:42' \
-d '{
"message": "Can you help me choose the right plan?"
}'Replays return the original response
Replaying the same key returns the original 202 response byte-identically and never runs the agent a second time.
In-flight duplicates get a 409
If the original request for that key is still in flight (processing), a duplicate send returns 409.
Keys expire after 24 hours
After 24 hours, a previously used key is treated as new.
Retrying consumers — Telegram, n8n, Zapier, and any other at-least-once delivery system — must send an idempotency key. Without one, a retried delivery can create a duplicate agent run.
Rate Limits
- Default
20sends/minute per conversation. - Default
120sends/minute per project. - Over the limit:
429with aRetry-Afterheader in seconds.
Back off and honor Retry-After rather than retrying immediately.
Next Steps
Agents API Webhooks
Receive asynchronous agent replies using response_webhook callbacks, with the full delivery, retry, and signature verification contract.
Agent Controls
Read a conversation's state, switch its model, tune compaction, restrict its tools, fork it, toggle its extensions, run durable tasks, and share state between your project's agents.