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

# Soumettre des tâches en masse : lots et grilles de localisation

> Choisissez entre le lot de 500 tâches, l'objet lot de 10 000 tâches et la grille de localisation, puis soumettez et lisez les résultats.

Trois endpoints créent de nombreuses tâches en une seule requête. Chacun crée des tâches ordinaires : polling, webhooks, crédits et limites du plan sont les mêmes que pour une tâche unitaire.

## Comparer les trois endpoints

| | `POST /v1/async/task/batch` | `POST /v1/batches` | `POST /v1/async/task/grid` |
| - | - | - | - |
| Ce que vous envoyez | Un tableau JSON de requêtes de tâche | `{ items, webhook?, metadata?, idempotencyKey? }` | Une requête de tâche plus `grid` |
| Tâches max | 500 | 10 000 | 81 (une grille 9 × 9) |
| Corps max | 8 Mio | 32 Mio | 1 Mio |
| Statut de succès | `200` | `202` à la création, `200` pour un `idempotencyKey` répété | `200` |
| Validation | Chaque élément séparément ; les éléments invalides échouent sur place | Tous les éléments d'abord ; un seul élément invalide fait refuser tout le lot avec `400` et rien n'est stocké | Le point central d'abord ; s'il est refusé, toute la grille est refusée |
| Au-delà de la limite du plan | Les éléments en trop échouent avec `PLAN_CONCURRENCY_LIMIT` ; vous les resoumettez | Les éléments attendent sur le serveur et sont libérés à mesure que de la place se libère | Les points en trop échouent sur place |
| Suivi | Interroger chaque tâche | Compteurs de `GET /v1/batches/{id}` | `GET /v1/async/task/grid/{id}` |
| Signal de fin | Un webhook par tâche | Un webhook par tâche, puis `batch.completed` | Un webhook par tâche |

## Lequel utiliser

* **Jusqu'à 500 tâches, et vous gérez les nouvelles tentatives :** `POST /v1/async/task/batch`. Vous recevez l'id de chaque tâche dans la réponse.
* **Plus de tâches que la concurrence de votre plan, ou un job quotidien de plusieurs milliers :** `POST /v1/batches`. Le serveur conserve les éléments et les injecte au rythme permis par la [limite de votre plan](/fr/concepts/credits-and-limits.md#concurrence-du-plan) et la file de chaque moteur : vous n'avez pas à réessayer les `429` ni les `503` vous-même.
* **Un même prompt posé depuis de nombreux points autour d'un lieu :** `POST /v1/async/task/grid`.

## `POST /v1/async/task/batch`

Envoyez un tableau de jusqu'à 500 requêtes de tâche ([référence](/fr/api-reference/create-task-batch.md)). Les moteurs peuvent être mélangés.

```bash theme={"theme":"css-variables"}
curl -X POST https://api.querying.ai/v1/async/task/batch \
  -H "Authorization: Bearer $QUERYING_API_KEY" \
  -H "Content-Type: application/json" \
  -d '[
    { "taskType": "CHATGPT", "idempotencyKey": "job-42:p1:chatgpt", "payload": { "prompt": "best CRM for a small team", "country": "US" } },
    { "taskType": "GEMINI", "idempotencyKey": "job-42:p1:gemini", "payload": { "prompt": "best CRM for a small team", "country": "US" } }
  ]'
```

Une requête bien formée renvoie `200`. `results[i].index` correspond à la position dans votre tableau, et chaque résultat contient soit `task`, soit `error` :

```json theme={"theme":"css-variables"}
{
  "success": true,
  "summary": { "total": 2, "succeeded": 1, "failed": 1 },
  "results": [
    { "success": true, "index": 0, "task": { "id": "8f2c1e40-...", "status": "QUEUED", "...": "..." }, "credits": { "creditsToCharge": 0, "creditsCharged": 0 } },
    {
      "success": false,
      "index": 1,
      "error": {
        "code": "PLAN_CONCURRENCY_LIMIT",
        "message": "free plan allows 2 concurrent tasks; 2 already active",
        "details": { "plan": "free", "limit": 2, "source": "plan", "active": 2, "retryAfterSec": 5 },
        "timestamp": "2026-10-19T04:12:00.000Z"
      }
    }
  ]
}
```

La requête entière est refusée, sans création de tâche, dans ces cas :

| Statut | Code | Quand |
| - | - | - |
| `400` | `VALIDATION_ERROR` | JSON invalide, pas un tableau, tableau vide ou plus de 500 éléments |
| `413` | `PAYLOAD_TOO_LARGE` | Corps de plus de 8 Mio |
| `503` | `SERVER_OVERLOADED` | L'admission est saturée. Réessayez après `Retry-After`. |
| `503` | `SERVER_OVERLOADED` | La file globale est pleine. Réessayez après `Retry-After`. |

Un `idempotencyKey` répété renvoie la tâche existante comme un succès. Consultez [Idempotence](/fr/concepts/idempotency.md).

## `POST /v1/batches`

Envoyez jusqu'à 10 000 éléments ([référence](/fr/api-reference/create-batch.md)). Chaque élément accepte les champs de tâche `taskType`, `payload`, `priority` et `idempotencyKey`, plus un `customId` facultatif (jusqu'à 128 caractères) renvoyé dans les résultats. Définissez `webhook.url` sur le lot, pas sur les éléments.

```bash theme={"theme":"css-variables"}
curl -X POST https://api.querying.ai/v1/batches \
  -H "Authorization: Bearer $QUERYING_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "idempotencyKey": "daily-2026-10-19",
    "webhook": { "url": "https://hooks.example.com/querying" },
    "metadata": { "run": "daily" },
    "items": [
      { "customId": "crm-chatgpt-us", "taskType": "CHATGPT", "payload": { "prompt": "best CRM for a small team", "country": "US" } },
      { "customId": "crm-gemini-us", "taskType": "GEMINI", "payload": { "prompt": "best CRM for a small team", "country": "US" } }
    ]
  }'
```

La réponse est `202` avec le lot. Les premiers éléments sont déjà soumis :

```json theme={"theme":"css-variables"}
{
  "success": true,
  "batch": {
    "id": "3f6b2a10-...",
    "status": "OPEN",
    "total": 2,
    "counts": { "pending": 0, "queued": 2, "processing": 0, "completed": 0, "failed": 0, "rejected": 0 },
    "createdAt": "2026-10-19T09:00:00.000Z",
    "completedAt": null,
    "idempotencyKey": "daily-2026-10-19",
    "webhook": { "url": "https://hooks.example.com/querying" },
    "metadata": { "run": "daily" }
  }
}
```

### Règles de l'enveloppe

| Champ | Règle |
| - | - |
| `items` | 1 à 10 000 objets |
| `webhook.url` | Mêmes [règles d'URL](/fr/concepts/webhooks.md#règles-des-url) qu'une tâche. S'applique à chaque élément. |
| `metadata` | Un objet de 8 Ko au plus en JSON, renvoyé tel quel |
| `idempotencyKey` | 1 à 256 caractères. Une répétition renvoie le premier lot avec `200`. |
| `idempotencyKey` d'élément | Doit être unique dans le lot |
| `webhook` d'élément | Refusé. Utilisez le `webhook.url` du lot. |

### Validation tout ou rien

Chaque élément subit les mêmes contrôles qu'une tâche unitaire avant tout stockage : champs, moteurs autorisés de la clé, moteurs privés, endpoints dédiés, région et `payload.location`. Si un élément échoue, la réponse est `400 VALIDATION_ERROR`, rien n'est stocké, et `details` liste jusqu'à 50 éléments en échec :

```json theme={"theme":"css-variables"}
{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "1 of 2 items are invalid; the batch was not stored",
    "details": {
      "invalidItems": 1,
      "items": [
        { "index": 1, "code": "VALIDATION_ERROR", "message": "Request validation failed", "details": [{ "field": "payload.prompt", "message": "payload.prompt or payload.query is required" }] }
      ]
    },
    "timestamp": "2026-10-19T09:00:00.000Z"
  }
}
```

### Exécution des éléments

Le lot libère les éléments sous forme de tâches quand la limite de votre plan et la file du moteur ont de la place. Les comptes passent à tour de rôle : un gros lot ne bloque pas un petit lot d'un autre compte. Chaque élément libéré passe par la même admission qu'une tâche unitaire : il pose un blocage de crédits et compte dans la limite quotidienne de crédits de la clé.

Quand un élément est refusé, le code détermine la suite :

| Code | Élément |
| - | - |
| `PLAN_CONCURRENCY_LIMIT`, `KEY_DAILY_CREDIT_LIMIT`, `SERVER_OVERLOADED`, `DB_UNAVAILABLE`, `ENQUEUE_ERROR` | Reste `PENDING` et sera retenté plus tard |
| `QUEUE_BACKPRESSURE`, `ENGINE_UNAVAILABLE` | Reste `PENDING` et sera retenté plus tard |
| `API_KEY_INACTIVE` | `REJECTED` : la clé du lot a été révoquée ou a expiré, ou son sous-compte a été suspendu |
| Tout autre code, y compris `INSUFFICIENT_CREDITS` | `REJECTED` |

Le lot passe à `COMPLETED` quand aucun élément n'est en attente et que toutes les tâches sont terminées. Avec `webhook.url`, le serveur publie ensuite l'[événement `batch.completed`](/fr/concepts/webhooks#événement-de-fin-de-lot).

### Lire la progression et les résultats

`GET /v1/batches/{id}` renvoie le lot avec `counts` par statut d'élément : `pending`, `queued`, `processing`, `completed`, `failed`, `rejected`. L'interroger fait aussi avancer les éléments en attente.

```bash theme={"theme":"css-variables"}
curl https://api.querying.ai/v1/batches/3f6b2a10-... \
  -H "Authorization: Bearer $QUERYING_API_KEY"
```

`GET /v1/batches/{id}/items` liste les éléments dans l'ordre de soumission :

```bash theme={"theme":"css-variables"}
curl "https://api.querying.ai/v1/batches/3f6b2a10-.../items?status=completed&include=response&limit=20" \
  -H "Authorization: Bearer $QUERYING_API_KEY"
```

| Paramètre | Description |
| - | - |
| `status` | L'un de `pending`, `queued`, `processing`, `completed`, `failed`, `rejected` |
| `include=response` | Ajoute la `response` ou l'`error` de chaque tâche terminée |
| `limit` | 100 par défaut, 1 000 au maximum. Avec `include=response` : 20 par défaut, 100 au maximum. |
| `cursor` | Le `nextCursor` de la page précédente |

```json theme={"theme":"css-variables"}
{
  "success": true,
  "items": [
    {
      "index": 0,
      "customId": "crm-chatgpt-us",
      "taskType": "CHATGPT",
      "status": "COMPLETED",
      "taskId": "8f2c1e40-...",
      "completedAt": "2026-10-19T09:01:40.000Z",
      "response": { "text": "...", "sources": [] }
    }
  ],
  "nextCursor": null
}
```

Un élément `REJECTED` porte `error: { code, message }`. Les corps de résultat ne sont inclus que pendant la fenêtre de polling de 24 heures décrite dans [Tâches asynchrones](/fr/concepts/async-tasks.md#conservation). Consultez aussi [Obtenir un lot](/fr/api-reference/get-batch.md) et [Lister les éléments d'un lot](/fr/api-reference/list-batch-items.md).

## `POST /v1/async/task/grid`

Posez un même prompt depuis chaque point d'une grille carrée autour d'un centre ([référence](/fr/api-reference/create-task-grid.md)). Chaque point devient une tâche avec ce point comme `payload.location` : le moteur doit donc accepter une localisation : `CHATGPT`, `GEMINI`, `GOOGLE`, `AIMODE` ou `GOOGLE_SERP`. N'envoyez pas `payload.location` vous-même.

```bash theme={"theme":"css-variables"}
curl -X POST https://api.querying.ai/v1/async/task/grid \
  -H "Authorization: Bearer $QUERYING_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "taskType": "CHATGPT",
    "idempotencyKey": "soho-coffee-2026-10-19",
    "payload": { "prompt": "best coffee shops near me for working on a laptop", "country": "US" },
    "grid": { "center": { "latitude": 40.72288, "longitude": -73.99875 }, "size": 3, "radiusMeters": 1500 }
  }'
```

| Champ | Règle |
| - | - |
| `grid.size` | `3`, `5`, `7` ou `9` points par côté (9 à 81 tâches) |
| `grid.radiusMeters` | 100 à 50 000 : la distance du centre au milieu de chaque bord. Les points sont espacés de `2 × radius ÷ (size − 1)`. |
| `grid.center` | Latitude et longitude en degrés décimaux. La grille doit rester sous 89 degrés de latitude. |
| `idempotencyKey` | Facultatif, 1 à 200 caractères. Il devient l'id de la grille. |
| `priority`, `webhook` | Appliqués à chaque point |

La ligne 0 est le bord nord et la colonne 0 le bord ouest. La réponse renvoie `grid` (avec `id` et `spacingMeters`), un `summary` et les `points` dans l'ordre des lignes, chacun avec `row`, `col`, `location` et soit `task`, soit `error`.

Le point central est admis en premier, seul. S'il est refusé (par exemple `422 LOCATION_UNSUPPORTED`, `403 KEY_SCOPE_DENIED`, `402 INSUFFICIENT_CREDITS` ou un plan saturé), cette erreur devient la réponse pour toute la grille et aucune tâche n'est créée. Les points suivants refusés faute de capacité échouent sur place avec `success: false`.

Relisez une grille avec [`GET /v1/async/task/grid/{id}`](/fr/api-reference/get-task-grid). Ajoutez `?include=response` pour obtenir les résultats des tâches terminées. Les points jamais admis sont absents, et l'id de grille d'un autre compte renvoie `404`. Renvoyer la même grille sous le même id n'admet que les points manquants ; consultez [Idempotence](/fr/concepts/idempotency.md#grilles-de-localisation).

## Étapes suivantes

> **[Idempotence](/fr/concepts/idempotency.md)**
>
> Comment chaque endpoint traite une clé répétée.

> **[Crédits et limites](/fr/concepts/credits-and-limits.md)**
>
> Concurrence du plan et cadencement.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.