> ## 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.

# Idempotence

> Dédupliquez les soumissions avec idempotencyKey, en notant que la soumission unitaire et le lot traitent les doublons différemment.

`idempotencyKey` est une chaîne facultative fournie par l'appelant qui rend une soumission dédupliquante. Envoyez deux
fois la même clé et la seconde soumission renvoie à la tâche créée par la première au lieu de mettre en file un nouveau travail.

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

Sans elle, il n'y a **aucune déduplication** : chaque soumission crée une nouvelle tâche. C'est un choix légitime pour
des requêtes ponctuelles, et le mauvais choix pour tout ce qu'un cron ou un worker qui réessaie pourrait soumettre deux fois.

<Tip>
  Une bonne clé se déduit de manière déterministe du travail lui-même, pas de la tentative. En composant les
  identifiants qui définissent l'unité de travail, par exemple `"{jobId}:{promptId}:{engine}"`, une nouvelle tentative
  reproduit naturellement la même clé.
</Tip>

## Unitaire et lot diffèrent volontairement

C'est le seul point où les deux endpoints divergent, et il piège souvent.

<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>

L'endpoint unitaire garde une sémantique de création explicite : vous avez demandé à créer une tâche, elle existe
déjà, c'est un conflit et vous devez le savoir.

L'endpoint de lot **absorbe les doublons comme des succès**. Son appelant est généralement un worker qui resoumet un
travail entier après un redémarrage, et faire échouer un lot de 500 éléments parce qu'une clé était déjà en file
réduirait à néant l'intérêt des clés d'idempotence. Le `results[i].task` renvoyé est la tâche *existante*, donc votre
correspondance des tâches reste valable.

## Rapprocher les résultats des soumissions

Deux repères indépendants, et il vous faut les deux :

<ResponseField name="results[].index" type="integer">
  Correspond 1:1 par position à votre tableau d'entrée. Utilisez-le pour rapprocher la réponse du lot des tâches envoyées.
</ResponseField>

<ResponseField name="task.idempotencyKey" type="string">
  Renvoyée telle quelle. Utilisez-la pour rapprocher le *webhook*, qui arrive quelques minutes plus tard, dans le
  désordre, sans référence à votre tableau d'origine.
</ResponseField>

<Note>
  Si vous n'avez pas fourni d'`idempotencyKey`, le champ est **omis** de l'objet tâche au lieu d'être renvoyé à `null`.
  En interne, la tâche utilise son propre uuid comme clé, unique par construction, et donc jamais dédupliquée.
</Note>

## Durée de vie des clés

Les clés des tâches conservées de façon permanente restent réservées après la fin, l'échec et la fenêtre publique de
polling de 24 heures. Un 404 au polling ne libère pas la clé. Utilisez la même clé pour les nouvelles tentatives
réseau d'une soumission, et une nouvelle clé d'exécution (par exemple avec un suffixe `:r1`) pour une exécution
distincte. Le format UUID n'est pas requis. Les enregistrements déjà déplacés vers l'historique hérité avant l'activation
de la rétention permanente ne réservent pas de clé rétroactivement.
