Asynchronous requests
Hand off long-running work to cloro, get a task ID back immediately, and collect the result later by webhook or by polling.
Overview
An asynchronous request splits the work into two moves: you submit a job, and cloro processes it in the background while your code moves on. Rather than holding a connection open until the model finishes, the API acknowledges the submission right away and returns a taskId you can use to look the result up later.
This pattern suits workloads where blocking is expensive or impractical — serverless functions with tight execution budgets, high-volume submission where you don't want to wait on each call in turn, and pipelines that shouldn't depend on a single long-lived connection surviving. When you need to enqueue many jobs at once, the batch endpoint accepts up to 500 tasks in one call.
Request fields
| Field | Type | Description |
|---|---|---|
taskType | string | The provider or engine the job targets, for example CHATGPT. |
payload | object | The task's own input — includes the prompt to run and an optional country code that pins the request region. |
priority | integer | Optional queue priority from 1 (lowest, the default) to 10 (highest). Higher-priority jobs are scheduled ahead of lower ones. |
idempotencyKey | string | Optional account-unique string you generate to tag and de-duplicate a submission. Reusing a key that already exists returns a RESOURCE_ALREADY_EXISTS error. |
webhook | object | Optional delivery target. Set webhook.url and cloro POSTs the finished result there; omit it and you retrieve the result by polling instead. |
Response example
The submission call confirms the task was accepted and echoes its starting state, always QUEUED. Store the id to fetch the result later.
{
"success": true,
"task": {
"id": "b27a21e1-7c39-4aa2-a347-23e828c426f9",
"taskType": "CHATGPT",
"status": "QUEUED",
"priority": 5,
"createdAt": "2026-01-14T15:00:00.000Z",
"idempotencyKey": "your-custom-identifier-123"
},
"credits": {
"creditsToCharge": 10,
"creditsCharged": 0
}
}
Task states
A task moves through one of four states over its lifetime:
| Field | Type | Description |
|---|---|---|
QUEUED | state | Accepted and awaiting a worker. The scheduler picks jobs by priority, then first-in-first-out within a priority level. |
PROCESSING | state | A worker has claimed the task and the provider is generating the response. |
COMPLETED | state | The job finished and the final result is attached to the task record. |
FAILED | state | The job could not complete — commonly from provider errors, rate limits, or invalid input. |
Collecting the result
Webhooks (recommended). If the request carried a webhook.url, cloro sends an HTTP POST with the complete result the moment the task reaches a terminal state, so you never poll. See Webhooks for payload shape, retries, and signature verification.
Polling. Without a webhook, check the task yourself by issuing a GET to the status endpoint with your task ID. Once the job completes, the response body carries the full result.
Limits and retention
- Credit check. On submission cloro confirms your account holds enough credits to run the task before queueing it.
- Queue depth. An organization may hold up to 100,000 tasks in the queue at once. Exceeding that returns
429 Too Many Requests; contact [email protected] to raise the ceiling. - Concurrency. How many queued tasks run in parallel is governed by your plan's concurrency limit — the queue can be large, but throughput is capped by that number.
- Retention. Completed and failed tasks stay retrievable for 24 hours, after which the record and its result are deleted. Any HTML URLs in a result also expire 24 hours after they are generated.
Notes
Queued tasks cannot be cancelled once submitted — a job in QUEUED runs to a terminal state — so validate inputs before posting at scale. There is no de-duplication beyond the idempotencyKey, so generate keys from UUIDs or a user-id-plus-timestamp scheme to keep them unique. Questions? Reach us at [email protected].