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

# Tasks in großen Mengen einreichen: Batches und Standort-Raster

> Wählen Sie zwischen dem Batch mit 500 Tasks, dem Batch-Objekt mit 10.000 Tasks und dem Standort-Raster, und reichen Sie dann ein und lesen Sie die Ergebnisse.

Drei Endpunkte erstellen viele Tasks in einer Anfrage. Jeder erstellt gewöhnliche Tasks: Polling, Webhooks, Credits und Tariflimits sind dieselben wie bei einem einzelnen Task.

## Die drei Endpunkte im Vergleich

| | `POST /v1/async/task/batch` | `POST /v1/batches` | `POST /v1/async/task/grid` |
| - | - | - | - |
| Was Sie senden | Ein JSON-Array von Task-Anfragen | `{ items, webhook?, metadata?, idempotencyKey? }` | Eine Task-Anfrage plus `grid` |
| Max. Tasks | 500 | 10.000 | 81 (ein 9 × 9-Raster) |
| Max. Body | 8 MiB | 32 MiB | 1 MiB |
| Erfolgsstatus | `200` | `202` erstellt, `200` bei wiederholtem `idempotencyKey` | `200` |
| Validierung | Jeder Eintrag einzeln; fehlerhafte Einträge scheitern an ihrer Stelle | Zuerst alle Einträge; ein fehlerhafter Eintrag lehnt den ganzen Batch mit `400` ab, und nichts wird gespeichert | Zuerst der Mittelpunkt; wird er abgelehnt, wird das ganze Raster abgelehnt |
| Über Ihrem Tariflimit | Überzählige Einträge scheitern mit `PLAN_CONCURRENCY_LIMIT`; Sie reichen sie erneut ein | Einträge warten auf dem Server und werden freigegeben, sobald Platz frei wird | Überzählige Punkte scheitern an ihrer Stelle |
| Fortschritt | Jeden Task pollen | Zähler von `GET /v1/batches/{id}` | `GET /v1/async/task/grid/{id}` |
| Abschlusssignal | Ein Webhook pro Task | Ein Webhook pro Task, danach `batch.completed` | Ein Webhook pro Task |

## Welchen Sie verwenden

* **Bis zu 500 Tasks, und Sie kümmern sich um Wiederholungen:** `POST /v1/async/task/batch`. Sie erhalten jede Task-id in der Antwort.
* **Mehr Tasks als die Parallelität Ihres Tarifs, oder ein täglicher Job mit Tausenden:** `POST /v1/batches`. Der Server hält die Einträge und speist sie ein, soweit Ihr [Tariflimit](/de/concepts/credits-and-limits.md#parallelität-des-tarifs) und die Warteschlange jeder Engine es zulassen, sodass Sie `429` und `503` nicht selbst wiederholen.
* **Ein Prompt, gestellt von vielen Punkten rund um einen Ort:** `POST /v1/async/task/grid`.

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

Senden Sie ein Array mit bis zu 500 Task-Anfragen ([Referenz](/de/api-reference/create-task-batch.md)). Engines lassen sich mischen.

```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" } }
  ]'
```

Eine wohlgeformte Anfrage liefert `200`. `results[i].index` entspricht der Position in Ihrem Array, und jedes Ergebnis hat entweder `task` oder `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"
      }
    }
  ]
}
```

In diesen Fällen wird die ganze Anfrage abgelehnt, und kein Task wird erstellt:

| Status | Code | Wann |
| - | - | - |
| `400` | `VALIDATION_ERROR` | Kein gültiges JSON, kein Array, leer oder mehr als 500 Einträge |
| `413` | `PAYLOAD_TOO_LARGE` | Body größer als 8 MiB |
| `503` | `SERVER_OVERLOADED` | Die Annahme ist ausgelastet. Wiederholen Sie nach `Retry-After`. |
| `503` | `SERVER_OVERLOADED` | Die globale Warteschlange ist voll. Wiederholen Sie nach `Retry-After`. |

Ein wiederholter `idempotencyKey` liefert den bestehenden Task als Erfolg. Siehe [Idempotenz](/de/concepts/idempotency.md).

## `POST /v1/batches`

Senden Sie bis zu 10.000 Einträge ([Referenz](/de/api-reference/create-batch.md)). Jeder Eintrag nimmt die Task-Felder `taskType`, `payload`, `priority` und `idempotencyKey` sowie eine optionale `customId` (bis zu 128 Zeichen), die in den Ergebnissen zurückgegeben wird. Setzen Sie `webhook.url` am Batch, nicht an den Einträgen.

```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" } }
    ]
  }'
```

Die Antwort ist `202` mit dem Batch. Die ersten Einträge sind bereits eingereicht:

```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" }
  }
}
```

### Regeln für den Umschlag

| Feld | Regel |
| - | - |
| `items` | 1 bis 10.000 Objekte |
| `webhook.url` | Dieselben [URL-Regeln](/de/concepts/webhooks.md#url-regeln) wie bei einem Task. Gilt für jeden Eintrag. |
| `metadata` | Ein Objekt von höchstens 8 KB als JSON, unverändert zurückgegeben |
| `idempotencyKey` | 1 bis 256 Zeichen. Eine Wiederholung liefert den ersten Batch mit `200`. |
| `idempotencyKey` eines Eintrags | Muss innerhalb des Batches eindeutig sein |
| `webhook` eines Eintrags | Wird abgelehnt. Verwenden Sie die `webhook.url` des Batches. |

### Alles-oder-nichts-Validierung

Jeder Eintrag durchläuft dieselben Prüfungen wie ein einzelner Task, bevor etwas gespeichert wird: Felder, Schlüsselbereich, private Engines, dedizierte Endpunkte, Region und `payload.location`. Scheitert ein Eintrag, lautet die Antwort `400 VALIDATION_ERROR`, nichts wird gespeichert, und `details` listet bis zu 50 fehlerhafte Einträge:

```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"
  }
}
```

### Wie Einträge laufen

Der Batch gibt Einträge als Tasks frei, wenn Ihr Tariflimit und die Warteschlange der Engine Platz haben. Konten wechseln sich ab, sodass ein großer Batch einen kleinen Batch eines anderen Kontos nicht aufhält. Jeder freigegebene Eintrag durchläuft dieselbe Annahme wie ein einzelner Task: Er reserviert Credits und zählt zum täglichen Credit-Limit des Schlüssels.

Wird ein Eintrag abgelehnt, entscheidet der Code, was passiert:

| Code | Eintrag |
| - | - |
| `PLAN_CONCURRENCY_LIMIT`, `KEY_DAILY_CREDIT_LIMIT`, `SERVER_OVERLOADED`, `DB_UNAVAILABLE`, `ENQUEUE_ERROR` | Bleibt `PENDING` und wird später erneut versucht |
| `QUEUE_BACKPRESSURE`, `ENGINE_UNAVAILABLE` | Bleibt `PENDING` und wird später erneut versucht |
| `API_KEY_INACTIVE` | `REJECTED`: Der Schlüssel des Batches wurde widerrufen oder ist abgelaufen, oder sein Unterkonto wurde gesperrt |
| Jeder andere Code, einschließlich `INSUFFICIENT_CREDITS` | `REJECTED` |

Der Batch wird `COMPLETED`, wenn kein Eintrag mehr aussteht und jeder Task fertig ist. Mit `webhook.url` sendet der Server dann das [`batch.completed`-Ereignis](/de/concepts/webhooks#batch-abschlussereignis).

### Fortschritt und Ergebnisse lesen

`GET /v1/batches/{id}` liefert den Batch mit `counts` nach Eintragsstatus: `pending`, `queued`, `processing`, `completed`, `failed`, `rejected`. Das Pollen bringt außerdem ausstehende Einträge voran.

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

`GET /v1/batches/{id}/items` listet die Einträge in Einreichungsreihenfolge:

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

| Abfrageparameter | Beschreibung |
| - | - |
| `status` | Einer von `pending`, `queued`, `processing`, `completed`, `failed`, `rejected` |
| `include=response` | Ergänzt `response` oder `error` jedes fertigen Tasks |
| `limit` | Standard 100, maximal 1.000. Mit `include=response`: Standard 20, maximal 100. |
| `cursor` | Der `nextCursor` der vorherigen Seite |

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

Ein `REJECTED`-Eintrag trägt `error: { code, message }`. Ergebnis-Bodies sind nur innerhalb des 24-stündigen Polling-Fensters aus [Asynchrone Tasks](/de/concepts/async-tasks.md#aufbewahrung) enthalten. Siehe auch [Batch abrufen](/de/api-reference/get-batch.md) und [Batch-Einträge auflisten](/de/api-reference/list-batch-items.md).

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

Stellen Sie einen Prompt von jedem Punkt eines quadratischen Rasters um einen Mittelpunkt ([Referenz](/de/api-reference/create-task-grid.md)). Jeder Punkt wird zu einem Task mit diesem Punkt als `payload.location`; die Engine muss also einen Standort akzeptieren: `CHATGPT`, `GEMINI`, `GOOGLE`, `AIMODE` oder `GOOGLE_SERP`. Senden Sie `payload.location` nicht selbst.

```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 }
  }'
```

| Feld | Regel |
| - | - |
| `grid.size` | `3`, `5`, `7` oder `9` Punkte pro Seite (9 bis 81 Tasks) |
| `grid.radiusMeters` | 100 bis 50.000: der Abstand vom Mittelpunkt zur Mitte jeder Kante. Die Punkte liegen `2 × radius ÷ (size − 1)` auseinander. |
| `grid.center` | Breiten- und Längengrad in Dezimalgrad. Das Raster muss unterhalb von 89 Grad Breite bleiben. |
| `idempotencyKey` | Optional, 1 bis 200 Zeichen. Wird zur Raster-id. |
| `priority`, `webhook` | Gelten für jeden Punkt |

Zeile 0 ist die Nordkante, Spalte 0 die Westkante. Die Antwort liefert `grid` (mit `id` und `spacingMeters`), eine `summary` und `points` in Zeilenreihenfolge, jeweils mit `row`, `col`, `location` und entweder `task` oder `error`.

Der Mittelpunkt wird zuerst und allein angenommen. Wird er abgelehnt (zum Beispiel `422 LOCATION_UNSUPPORTED`, `403 KEY_SCOPE_DENIED`, `402 INSUFFICIENT_CREDITS` oder ein ausgeschöpfter Tarif), ist dieser Fehler die Antwort für das ganze Raster, und kein Task wird erstellt. Punkte nach dem Mittelpunkt, die aus Kapazitätsgründen abgelehnt werden, scheitern an ihrer Stelle mit `success: false`.

Lesen Sie ein Raster mit [`GET /v1/async/task/grid/{id}`](/de/api-reference/get-task-grid) zurück. Fügen Sie `?include=response` für die Ergebnisse fertiger Tasks hinzu. Nie angenommene Punkte fehlen, und die Raster-id eines anderen Kontos liefert `404`. Wird dasselbe Raster unter derselben id erneut gesendet, werden nur die fehlenden Punkte angenommen; siehe [Idempotenz](/de/concepts/idempotency.md#standort-raster).

## Nächste Schritte

> **[Idempotenz](/de/concepts/idempotency.md)**
>
> Wie jeder Endpunkt einen wiederholten Schlüssel behandelt.

> **[Credits und Limits](/de/concepts/credits-and-limits.md)**
>
> Parallelität des Tarifs und Taktung.


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