AnswerLine Sign in Start free

Async tasks and batches

Task lifecycle

StatusMeaning
QUEUEDWaiting for a concurrency slot. Not charged; can be cleared.
PROCESSINGRunning. Transient failures are retried automatically within five minutes of the first start.
COMPLETEDresponse holds the engine's result. Charged.
FAILEDresponse holds the error. Not charged.

task.latencyMs runs from the first start to the final outcome, excluding the time queued.

Creating a task

POST /v1/async/task takes the engine's request as payload and answers at once with the task. Invalid bodies get 422. priority orders your own queue: higher runs first, equal priorities in submission order, and other accounts are unaffected.

FieldTypeDescription
taskType * "AIMODE" | "GOOGLE" | "GOOGLE_NEWS" | "GEMINI" | "CHATGPT" | "COPILOT" | "PERPLEXITY" | "GROK" The AI provider to use for this task.
payload * object Provider-specific request payload. Must include at least `prompt` (or `query` for Google Search).
priority integer Task priority level (1-10). Higher numbers are processed first. Defaults to 1.
idempotencyKey string Unique string to prevent duplicate task creation. Must be unique across your account.
webhook object Webhook configuration for task completion notification.
webhook.url * string URL to receive the webhook POST request when the task completes.

Batches

POST /v1/async/task/batch takes 1 to 500 tasks. Each is validated and admitted on its own, and results answers each by its index in input order. Only an overflowing queue rejects the whole batch (429 QUEUE_LIMIT_EXCEEDED). The SDKs refuse a batch outside that size before sending it.

curl

curl -X POST "https://api.answerline.dev/v1/async/task/batch" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '[{"taskType":"CHATGPT","payload":{"prompt":"Best CRM for small agencies","country":"US"},"idempotencyKey":"crm-0-US-2026-09-15"},{"taskType":"CHATGPT","payload":{"prompt":"Best CRM for small agencies","country":"GB"},"priority":5,"idempotencyKey":"crm-0-GB-2026-09-15"}]'

TypeScript

const prompts = ["Best CRM for small agencies", "Best CRM for real estate teams"];
const tasks = prompts.flatMap((prompt, i) =>
  ["US", "GB"].map((country) => ({
    taskType: "CHATGPT" as const,
    payload: { prompt, country },
    idempotencyKey: `crm-${i}-${country}-2026-09-15`,
  })),
);

const batch = await client.createBatch(tasks);
for (const item of batch.results) {
  if (!item.success) console.warn(tasks[item.index].idempotencyKey, item.error.code);
}

Python

prompts = ["Best CRM for small agencies", "Best CRM for real estate teams"]
tasks = [
    {"taskType": "CHATGPT", "payload": {"prompt": p, "country": c}, "idempotencyKey": f"crm-{i}-{c}-2026-09-15"}
    for i, p in enumerate(prompts)
    for c in ("US", "GB")
]

batch = client.create_batch(tasks)
failed = [r for r in batch["results"] if not r["success"]]

Response

{
  "success": true,
  "summary": {
    "total": 2,
    "succeeded": 1,
    "failed": 1
  },
  "results": [
    {
      "success": true,
      "index": 0,
      "task": {
        "id": "b27a21e1-7c39-4aa2-a347-23e828c426f9",
        "taskType": "CHATGPT",
        "status": "QUEUED",
        "priority": 1,
        "createdAt": "2026-09-15T09:00:00.000Z",
        "latencyMs": null,
        "idempotencyKey": "crm-0-US-2026-09-15"
      },
      "credits": {
        "creditsToCharge": 5,
        "creditsCharged": null
      }
    },
    {
      "success": false,
      "index": 1,
      "error": {
        "code": "RESOURCE_ALREADY_EXISTS",
        "message": "…",
        "timestamp": "2026-09-15T09:00:00.000Z"
      }
    }
  ]
}

Item errors are VALIDATION_ERROR, RESOURCE_ALREADY_EXISTS and INSUFFICIENT_CREDITS.

Getting results

GET /v1/async/task/{id} returns task, credits and, once the task has finished, response. waitForTask / wait_for_task poll it with jittered backoff from 500 ms up to 10 seconds between polls (intervalMs / interval) for up to 10 minutes (timeoutMs / timeout). For many tasks, add a webhook instead and let results come to you; see webhooks.

Idempotency keys

An idempotencyKey is unique across your account. Creating a task with a key in use answers 409 RESOURCE_CONFLICT, or RESOURCE_ALREADY_EXISTS for a batch item, and creates nothing. Derive keys from what the task means, such as prompt, market and day, never at random per attempt: then retrying a submission after a timeout can never run a task twice.

Managing the queue

GET /v1/async/status reports queuedTasks, processingTasks, queued counts per priority and concurrency in use. DELETE /v1/async/queue deletes every task still QUEUED, which were never charged, leaves running and finished tasks alone, and returns how many it removed; it is safe to repeat.

curl

curl -X GET "https://api.answerline.dev/v1/async/status" \
  -H "Authorization: Bearer $API_KEY"

curl -X DELETE "https://api.answerline.dev/v1/async/queue" \
  -H "Authorization: Bearer $API_KEY"

TypeScript

const status = await client.asyncStatus();
const { cleared } = await client.clearQueue();

Python

status = client.async_status()
cleared = client.clear_queue()["cleared"]

Sync or async

A synchronous call is one request that waits up to five minutes, costs the synchronous surcharge and needs a free concurrency slot. A task costs the base price, waits for a slot instead of failing, and can be batched. Use synchronous calls for interactive work and tasks for anything scheduled or large.