> ## Documentation Index
> Fetch the complete documentation index at: https://docs.querying.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Idempotency

> Deduplicate submissions with idempotencyKey — and note that single and batch treat duplicates differently.

`idempotencyKey` is an optional caller-supplied string that makes a submission
deduplicating. Send the same key twice and the second submission resolves to the task the
first one created rather than queuing new work.

```json theme={null}
{
  "taskType": "GEMINI",
  "idempotencyKey": "job-42:prompt-7:gemini",
  "payload": { "prompt": "best wireless earbuds 2026" }
}
```

Omit it and you get **no deduplication** — every submission creates a new task. That is a
legitimate choice for one-off queries; it is the wrong choice for anything a cron or a
retrying worker might submit twice.

<Tip>
  A good key is deterministic from the work itself, not from the attempt. Composing the
  identifiers that define the unit of work — `"{jobId}:{promptId}:{engine}"` — means a
  retry naturally reproduces the same key.
</Tip>

## Single and batch differ on purpose

This is the one place the two endpoints diverge, and it trips people up.

<CodeGroup>
  ```json Single — duplicate is an error theme={null}
  POST /v1/async/task
  → 409 Conflict

  {
    "success": false,
    "error": {
      "code": "RESOURCE_ALREADY_EXISTS",
      "message": "Task already exists.",
      "timestamp": "2026-07-09T04:12:00.000Z"
    }
  }
  ```

  ```json Batch — duplicate is a success theme={null}
  POST /v1/async/task/batch
  → 200 OK

  {
    "success": true,
    "summary": { "total": 1, "succeeded": 1, "failed": 0 },
    "results": [
      {
        "success": true,
        "index": 0,
        "task": { "id": "8f2c1e40-...", "status": "QUEUED", "...": "..." }
      }
    ]
  }
  ```
</CodeGroup>

The single-task endpoint keeps explicit-create semantics: you asked to create a task, the
task already exists, that is a conflict and you should know.

The batch endpoint **absorbs duplicates as success**. Its caller is typically a worker
resubmitting a whole job after a restart, and flipping a 500-item batch to failed because
one key was already queued would defeat the point of having idempotency keys. The
`results[i].task` you get back is the *existing* task, so your task mapping still resolves.

## Matching results back to submissions

Two independent handles, and you want both:

<ResponseField name="results[].index" type="integer">
  Positionally 1:1 with your input array. Use it to correlate the batch response with the
  tasks you sent.
</ResponseField>

<ResponseField name="task.idempotencyKey" type="string">
  Echoed back verbatim. Use it to correlate the *webhook* — which arrives minutes later,
  out of order, with no reference to your original array.
</ResponseField>

<Note>
  If you did not supply an `idempotencyKey`, the field is **omitted** from the task object
  rather than returned as `null`. Internally the task falls back to its own uuid as a key,
  which is unique by construction and therefore never dedupes.
</Note>
