curl --request POST \
--url https://api.cloro.dev/v1/async/task/batch \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
[
{
"taskType": "CHATGPT",
"priority": 5,
"idempotencyKey": "batch-chatgpt-001",
"webhook": {
"url": "https://your-app.com/webhook-handler"
},
"payload": {
"prompt": "What do you know about Acme Corp?",
"country": "US"
}
},
{
"taskType": "PERPLEXITY",
"priority": 3,
"idempotencyKey": "batch-perplexity-001",
"payload": {
"prompt": "Latest news about Acme Corp",
"country": "US"
}
}
]
'import requests
url = "https://api.cloro.dev/v1/async/task/batch"
payload = [
{
"taskType": "CHATGPT",
"priority": 5,
"idempotencyKey": "batch-chatgpt-001",
"webhook": { "url": "https://your-app.com/webhook-handler" },
"payload": {
"prompt": "What do you know about Acme Corp?",
"country": "US"
}
},
{
"taskType": "PERPLEXITY",
"priority": 3,
"idempotencyKey": "batch-perplexity-001",
"payload": {
"prompt": "Latest news about Acme Corp",
"country": "US"
}
}
]
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify([
{
taskType: 'CHATGPT',
priority: 5,
idempotencyKey: 'batch-chatgpt-001',
webhook: {url: 'https://your-app.com/webhook-handler'},
payload: {prompt: 'What do you know about Acme Corp?', country: 'US'}
},
{
taskType: 'PERPLEXITY',
priority: 3,
idempotencyKey: 'batch-perplexity-001',
payload: {prompt: 'Latest news about Acme Corp', country: 'US'}
}
])
};
fetch('https://api.cloro.dev/v1/async/task/batch', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.cloro.dev/v1/async/task/batch",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
[
'taskType' => 'CHATGPT',
'priority' => 5,
'idempotencyKey' => 'batch-chatgpt-001',
'webhook' => [
'url' => 'https://your-app.com/webhook-handler'
],
'payload' => [
'prompt' => 'What do you know about Acme Corp?',
'country' => 'US'
]
],
[
'taskType' => 'PERPLEXITY',
'priority' => 3,
'idempotencyKey' => 'batch-perplexity-001',
'payload' => [
'prompt' => 'Latest news about Acme Corp',
'country' => 'US'
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.cloro.dev/v1/async/task/batch"
payload := strings.NewReader("[\n {\n \"taskType\": \"CHATGPT\",\n \"priority\": 5,\n \"idempotencyKey\": \"batch-chatgpt-001\",\n \"webhook\": {\n \"url\": \"https://your-app.com/webhook-handler\"\n },\n \"payload\": {\n \"prompt\": \"What do you know about Acme Corp?\",\n \"country\": \"US\"\n }\n },\n {\n \"taskType\": \"PERPLEXITY\",\n \"priority\": 3,\n \"idempotencyKey\": \"batch-perplexity-001\",\n \"payload\": {\n \"prompt\": \"Latest news about Acme Corp\",\n \"country\": \"US\"\n }\n }\n]")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.cloro.dev/v1/async/task/batch")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("[\n {\n \"taskType\": \"CHATGPT\",\n \"priority\": 5,\n \"idempotencyKey\": \"batch-chatgpt-001\",\n \"webhook\": {\n \"url\": \"https://your-app.com/webhook-handler\"\n },\n \"payload\": {\n \"prompt\": \"What do you know about Acme Corp?\",\n \"country\": \"US\"\n }\n },\n {\n \"taskType\": \"PERPLEXITY\",\n \"priority\": 3,\n \"idempotencyKey\": \"batch-perplexity-001\",\n \"payload\": {\n \"prompt\": \"Latest news about Acme Corp\",\n \"country\": \"US\"\n }\n }\n]")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.cloro.dev/v1/async/task/batch")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "[\n {\n \"taskType\": \"CHATGPT\",\n \"priority\": 5,\n \"idempotencyKey\": \"batch-chatgpt-001\",\n \"webhook\": {\n \"url\": \"https://your-app.com/webhook-handler\"\n },\n \"payload\": {\n \"prompt\": \"What do you know about Acme Corp?\",\n \"country\": \"US\"\n }\n },\n {\n \"taskType\": \"PERPLEXITY\",\n \"priority\": 3,\n \"idempotencyKey\": \"batch-perplexity-001\",\n \"payload\": {\n \"prompt\": \"Latest news about Acme Corp\",\n \"country\": \"US\"\n }\n }\n]"
response = http.request(request)
puts response.read_body{
"success": true,
"summary": {
"total": 3,
"succeeded": 2,
"failed": 1
},
"results": [
{
"success": true,
"index": 0,
"task": {
"id": "b27a21e1-7c39-4aa2-a347-23e828c426f9",
"taskType": "CHATGPT",
"status": "QUEUED",
"priority": 1,
"createdAt": "2026-04-09T15:00:00.000Z",
"idempotencyKey": "batch-chatgpt-001"
},
"credits": {
"creditsToCharge": 10,
"creditsCharged": null
}
}
]
}{
"error": {
"code": "MISSING_API_KEY",
"message": "Missing or invalid API key",
"timestamp": "2025-01-15T12:00:00.000Z"
}
}{
"success": false,
"error": "Request validation failed",
"details": [
{
"field": "prompt",
"message": "Prompt cannot be empty"
}
]
}{
"success": false,
"error": {
"code": "QUEUE_LIMIT_EXCEEDED",
"message": "Batch would exceed queue capacity",
"timestamp": "2026-04-09T15:00:00.000Z",
"details": {
"queuedCount": 99950,
"batchSize": 100,
"maxQueueSize": 100000,
"remainingCapacity": 50
}
}
}{
"success": false,
"error": "Maximum retries exceeded"
}Create batch tasks
Submit up to 500 async tasks in one request. Each task is validated independently, so one invalid task does not block the rest. Returns per-task results.
curl --request POST \
--url https://api.cloro.dev/v1/async/task/batch \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
[
{
"taskType": "CHATGPT",
"priority": 5,
"idempotencyKey": "batch-chatgpt-001",
"webhook": {
"url": "https://your-app.com/webhook-handler"
},
"payload": {
"prompt": "What do you know about Acme Corp?",
"country": "US"
}
},
{
"taskType": "PERPLEXITY",
"priority": 3,
"idempotencyKey": "batch-perplexity-001",
"payload": {
"prompt": "Latest news about Acme Corp",
"country": "US"
}
}
]
'import requests
url = "https://api.cloro.dev/v1/async/task/batch"
payload = [
{
"taskType": "CHATGPT",
"priority": 5,
"idempotencyKey": "batch-chatgpt-001",
"webhook": { "url": "https://your-app.com/webhook-handler" },
"payload": {
"prompt": "What do you know about Acme Corp?",
"country": "US"
}
},
{
"taskType": "PERPLEXITY",
"priority": 3,
"idempotencyKey": "batch-perplexity-001",
"payload": {
"prompt": "Latest news about Acme Corp",
"country": "US"
}
}
]
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify([
{
taskType: 'CHATGPT',
priority: 5,
idempotencyKey: 'batch-chatgpt-001',
webhook: {url: 'https://your-app.com/webhook-handler'},
payload: {prompt: 'What do you know about Acme Corp?', country: 'US'}
},
{
taskType: 'PERPLEXITY',
priority: 3,
idempotencyKey: 'batch-perplexity-001',
payload: {prompt: 'Latest news about Acme Corp', country: 'US'}
}
])
};
fetch('https://api.cloro.dev/v1/async/task/batch', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.cloro.dev/v1/async/task/batch",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
[
'taskType' => 'CHATGPT',
'priority' => 5,
'idempotencyKey' => 'batch-chatgpt-001',
'webhook' => [
'url' => 'https://your-app.com/webhook-handler'
],
'payload' => [
'prompt' => 'What do you know about Acme Corp?',
'country' => 'US'
]
],
[
'taskType' => 'PERPLEXITY',
'priority' => 3,
'idempotencyKey' => 'batch-perplexity-001',
'payload' => [
'prompt' => 'Latest news about Acme Corp',
'country' => 'US'
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.cloro.dev/v1/async/task/batch"
payload := strings.NewReader("[\n {\n \"taskType\": \"CHATGPT\",\n \"priority\": 5,\n \"idempotencyKey\": \"batch-chatgpt-001\",\n \"webhook\": {\n \"url\": \"https://your-app.com/webhook-handler\"\n },\n \"payload\": {\n \"prompt\": \"What do you know about Acme Corp?\",\n \"country\": \"US\"\n }\n },\n {\n \"taskType\": \"PERPLEXITY\",\n \"priority\": 3,\n \"idempotencyKey\": \"batch-perplexity-001\",\n \"payload\": {\n \"prompt\": \"Latest news about Acme Corp\",\n \"country\": \"US\"\n }\n }\n]")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.cloro.dev/v1/async/task/batch")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("[\n {\n \"taskType\": \"CHATGPT\",\n \"priority\": 5,\n \"idempotencyKey\": \"batch-chatgpt-001\",\n \"webhook\": {\n \"url\": \"https://your-app.com/webhook-handler\"\n },\n \"payload\": {\n \"prompt\": \"What do you know about Acme Corp?\",\n \"country\": \"US\"\n }\n },\n {\n \"taskType\": \"PERPLEXITY\",\n \"priority\": 3,\n \"idempotencyKey\": \"batch-perplexity-001\",\n \"payload\": {\n \"prompt\": \"Latest news about Acme Corp\",\n \"country\": \"US\"\n }\n }\n]")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.cloro.dev/v1/async/task/batch")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "[\n {\n \"taskType\": \"CHATGPT\",\n \"priority\": 5,\n \"idempotencyKey\": \"batch-chatgpt-001\",\n \"webhook\": {\n \"url\": \"https://your-app.com/webhook-handler\"\n },\n \"payload\": {\n \"prompt\": \"What do you know about Acme Corp?\",\n \"country\": \"US\"\n }\n },\n {\n \"taskType\": \"PERPLEXITY\",\n \"priority\": 3,\n \"idempotencyKey\": \"batch-perplexity-001\",\n \"payload\": {\n \"prompt\": \"Latest news about Acme Corp\",\n \"country\": \"US\"\n }\n }\n]"
response = http.request(request)
puts response.read_body{
"success": true,
"summary": {
"total": 3,
"succeeded": 2,
"failed": 1
},
"results": [
{
"success": true,
"index": 0,
"task": {
"id": "b27a21e1-7c39-4aa2-a347-23e828c426f9",
"taskType": "CHATGPT",
"status": "QUEUED",
"priority": 1,
"createdAt": "2026-04-09T15:00:00.000Z",
"idempotencyKey": "batch-chatgpt-001"
},
"credits": {
"creditsToCharge": 10,
"creditsCharged": null
}
}
]
}{
"error": {
"code": "MISSING_API_KEY",
"message": "Missing or invalid API key",
"timestamp": "2025-01-15T12:00:00.000Z"
}
}{
"success": false,
"error": "Request validation failed",
"details": [
{
"field": "prompt",
"message": "Prompt cannot be empty"
}
]
}{
"success": false,
"error": {
"code": "QUEUE_LIMIT_EXCEEDED",
"message": "Batch would exceed queue capacity",
"timestamp": "2026-04-09T15:00:00.000Z",
"details": {
"queuedCount": 99950,
"batchSize": 100,
"maxQueueSize": 100000,
"remainingCapacity": 50
}
}
}{
"success": false,
"error": "Maximum retries exceeded"
}Overview
The batch endpoint lets you submit multiple async tasks in a single HTTP request, reducing overhead for high-volume workloads. Instead of making one API call per task, you can send up to 500 tasks at once. Key behaviors:- Partial success: Each task is validated independently. One invalid task does not block others from being created.
- Per-task results: The response includes a
resultsarray with success or failure details for each task, preserving the original input order byindex. - All-or-nothing queue check: Before processing individual tasks, the endpoint verifies that your queue has enough capacity for the entire batch. If it doesn’t, the whole batch is rejected with a
429error. - Per-task webhook delivery: each task fires its own webhook notification as soon as it completes — you don’t wait for the full batch to finish. Webhooks arrive in completion order, not submission order.
taskType, payload, and optionally priority, idempotencyKey, and webhook.
Request constraints
| Constraint | Value |
|---|---|
| Minimum tasks per request | 1 |
| Maximum tasks per request | 500 |
| Queue capacity check | All-or-nothing. The batch is rejected if it would exceed your organization’s 100,000 task queue limit |
422 Unprocessable Entity error before any task-level processing begins.Per-task error codes
When a task fails validation within a batch, its result includes one of these error codes:| Code | Description |
|---|---|
VALIDATION_ERROR | The task failed schema validation. details includes field-level errors. |
RESOURCE_ALREADY_EXISTS | The idempotencyKey was already used (either in a previous request or earlier in the same batch). |
INSUFFICIENT_CREDITS | Not enough credits remaining for this task. Credits are tracked per task within the batch. |
Example usage
Submit a batch of tasks
curl -X POST "https://api.cloro.dev/v1/async/task/batch" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '[
{
"taskType": "CHATGPT",
"priority": 5,
"idempotencyKey": "batch-chatgpt-001",
"webhook": {
"url": "https://your-app.com/webhook-handler"
},
"payload": {
"prompt": "What do you know about Acme Corp?",
"country": "US"
}
},
{
"taskType": "PERPLEXITY",
"priority": 3,
"idempotencyKey": "batch-perplexity-001",
"payload": {
"prompt": "Latest news about Acme Corp",
"country": "US"
}
},
{
"taskType": "GEMINI",
"payload": {
"prompt": "Summarize Acme Corp recent announcements"
}
}
]'
import axios from 'axios';
const apiKey = 'YOUR_API_KEY';
const url = 'https://api.cloro.dev/v1/async/task/batch';
const tasks = [
{
taskType: 'CHATGPT',
priority: 5,
idempotencyKey: 'batch-chatgpt-001',
webhook: { url: 'https://your-app.com/webhook-handler' },
payload: { prompt: 'What do you know about Acme Corp?', country: 'US' },
},
{
taskType: 'PERPLEXITY',
priority: 3,
idempotencyKey: 'batch-perplexity-001',
payload: { prompt: 'Latest news about Acme Corp', country: 'US' },
},
{
taskType: 'GEMINI',
payload: { prompt: 'Summarize Acme Corp recent announcements' },
},
];
try {
const response = await axios.post(url, tasks, {
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
});
const { summary, results } = response.data;
console.log(`Batch complete: ${summary.succeeded} succeeded, ${summary.failed} failed`);
for (const result of results) {
if (result.success) {
console.log(`Task ${result.index}: ${result.task.id} (${result.task.taskType})`);
} else {
console.error(`Task ${result.index} failed: ${result.error.code} - ${result.error.message}`);
}
}
} catch (error) {
console.error('Batch request failed:', error.response?.data || error.message);
}
import requests
api_key = 'YOUR_API_KEY'
url = 'https://api.cloro.dev/v1/async/task/batch'
tasks = [
{
"taskType": "CHATGPT",
"priority": 5,
"idempotencyKey": "batch-chatgpt-001",
"webhook": {"url": "https://your-app.com/webhook-handler"},
"payload": {"prompt": "What do you know about Acme Corp?", "country": "US"},
},
{
"taskType": "PERPLEXITY",
"priority": 3,
"idempotencyKey": "batch-perplexity-001",
"payload": {"prompt": "Latest news about Acme Corp", "country": "US"},
},
{
"taskType": "GEMINI",
"payload": {"prompt": "Summarize Acme Corp recent announcements"},
},
]
response = requests.post(
url,
json=tasks,
headers={
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json",
},
)
data = response.json()
summary = data["summary"]
print(f"Batch complete: {summary['succeeded']} succeeded, {summary['failed']} failed")
for result in data["results"]:
if result["success"]:
task = result["task"]
print(f"Task {result['index']}: {task['id']} ({task['taskType']})")
else:
error = result["error"]
print(f"Task {result['index']} failed: {error['code']} - {error['message']}")
Response with partial success
When some tasks succeed and others fail, the response includes results for every task:{
"success": true,
"summary": {
"total": 3,
"succeeded": 2,
"failed": 1
},
"results": [
{
"success": true,
"index": 0,
"task": {
"id": "b27a21e1-7c39-4aa2-a347-23e828c426f9",
"taskType": "CHATGPT",
"status": "QUEUED",
"priority": 5,
"createdAt": "2026-04-09T15:00:00.000Z",
"idempotencyKey": "batch-chatgpt-001"
},
"credits": {
"creditsToCharge": 10,
"creditsCharged": null
}
},
{
"success": true,
"index": 1,
"task": {
"id": "c38b32f2-8d40-5bb3-b458-34f939d537e0",
"taskType": "PERPLEXITY",
"status": "QUEUED",
"priority": 3,
"createdAt": "2026-04-09T15:00:00.000Z",
"idempotencyKey": "batch-perplexity-001"
},
"credits": {
"creditsToCharge": 5,
"creditsCharged": null
}
},
{
"success": false,
"index": 2,
"error": {
"code": "INSUFFICIENT_CREDITS",
"message": "Not enough credits remaining",
"timestamp": "2026-04-09T15:00:00.000Z"
}
}
]
}
Use cases
Bulk monitoring across providers
Submit tasks to multiple AI providers simultaneously to compare responses:const providers = ['CHATGPT', 'PERPLEXITY', 'GEMINI', 'COPILOT'];
const prompt = 'What do you know about Acme Corp?';
const tasks = providers.map((taskType, i) => ({
taskType,
idempotencyKey: `compare-${Date.now()}-${i}`,
webhook: { url: 'https://your-app.com/webhook-handler' },
payload: { prompt, country: 'US' },
}));
const response = await axios.post('https://api.cloro.dev/v1/async/task/batch', tasks, {
headers: { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json' },
});
Scheduled batch jobs
Process a list of queries in one request instead of submitting them one at a time:from datetime import date
queries = [
"What is Acme Corp's market position?",
"Who are Acme Corp's main competitors?",
"What are Acme Corp's latest product launches?",
]
tasks = [
{
"taskType": "CHATGPT",
"priority": 3,
"idempotencyKey": f"daily-batch-{date.today()}-{i}",
"webhook": {"url": "https://your-app.com/webhook-handler"},
"payload": {"prompt": query, "country": "US"},
}
for i, query in enumerate(queries)
]
response = requests.post(
"https://api.cloro.dev/v1/async/task/batch",
json=tasks,
headers={"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"},
)
Handling partial failures
Check results and retry only the failed tasks:const { summary, results } = response.data;
if (summary.failed > 0) {
const failedTasks = results
.filter(r => !r.success)
.map(r => ({
...originalTasks[r.index],
idempotencyKey: `${originalTasks[r.index].idempotencyKey}-retry`,
}));
// Retry failed tasks (with new idempotency keys)
const retryResponse = await axios.post(url, failedTasks, { headers });
}
Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Body
1 - 500 elementsThe AI provider to use for this task.
AIMODE, GOOGLE, GOOGLE_NEWS, GEMINI, CHATGPT, COPILOT, PERPLEXITY, GROK "CHATGPT"
Provider-specific request payload. Must include at least prompt (or query for Google Search).
{
"prompt": "What do you know about Acme Corp?",
"country": "US"
}
Task priority level (1-10). Higher numbers are processed first. Defaults to 1.
1 <= x <= 105
Unique string to prevent duplicate task creation. Must be unique across your account.
"batch-chatgpt-001"
Webhook configuration for task completion notification.
Show child attributes
Show child attributes
Response
Batch processed. Check the summary and individual results for per-task success or failure.
Always true for a successfully processed batch (individual tasks may still fail).
true
Aggregate counts for the batch.
Show child attributes
Show child attributes
Per-task results preserving the original input order by index.
- Option 1
- Option 2
Show child attributes
Show child attributes
Was this page helpful?