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

# Envie tarefas em massa: lotes e grades de localização

> Escolha entre o lote de 500 tarefas, o objeto de lote de 10.000 tarefas e a grade de localizações, depois envie e leia os resultados.

Três endpoints criam muitas tarefas em uma única requisição. Cada um cria tarefas comuns: polling, webhooks, créditos e limites do plano funcionam como em uma tarefa individual.

## Compare os três endpoints

| | `POST /v1/async/task/batch` | `POST /v1/batches` | `POST /v1/async/task/grid` |
| - | - | - | - |
| O que você envia | Um array JSON de requisições de tarefa | `{ items, webhook?, metadata?, idempotencyKey? }` | Uma requisição de tarefa mais `grid` |
| Máximo de tarefas | 500 | 10.000 | 81 (uma grade 9 × 9) |
| Corpo máximo | 8 MiB | 32 MiB | 1 MiB |
| Status de sucesso | `200` | `202` ao criar, `200` para um `idempotencyKey` repetido | `200` |
| Validação | Cada item por si; itens inválidos falham no lugar | Todos os itens primeiro; um item inválido rejeita o lote inteiro com `400` e nada é armazenado | O ponto central primeiro; se ele for recusado, a grade inteira é recusada |
| Acima do limite do plano | Os itens excedentes falham com `PLAN_CONCURRENCY_LIMIT`; você os reenvia | Os itens esperam no servidor e são liberados conforme abre espaço | Os pontos excedentes falham no lugar |
| Progresso | Consulte cada tarefa | Contagens de `GET /v1/batches/{id}` | `GET /v1/async/task/grid/{id}` |
| Sinal de conclusão | Um webhook por tarefa | Um webhook por tarefa, depois `batch.completed` | Um webhook por tarefa |

## Qual usar

* **Até 500 tarefas, e você cuida das novas tentativas:** `POST /v1/async/task/batch`. Você recebe todos os ids de tarefa na resposta.
* **Mais tarefas do que a concorrência do seu plano, ou um job diário de milhares:** `POST /v1/batches`. O servidor guarda os itens e os libera conforme o [limite do seu plano](/pt/concepts/credits-and-limits.md#concorrência-do-plano) e a fila de cada mecanismo permitem, então você não precisa repetir `429`s nem `503`s por conta própria.
* **Um prompt perguntado a partir de muitos pontos ao redor de um lugar:** `POST /v1/async/task/grid`.

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

Envie um array de até 500 requisições de tarefa ([referência](/pt/api-reference/create-task-batch.md)). Os mecanismos podem ser misturados.

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

Uma requisição bem formada retorna `200`. `results[i].index` corresponde à posição no seu array, e cada resultado tem `task` ou `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"
      }
    }
  ]
}
```

A requisição inteira é recusada, sem criar nenhuma tarefa, nestes casos:

| Status | Código | Quando |
| - | - | - |
| `400` | `VALIDATION_ERROR` | Não é JSON válido, não é array, está vazio ou passa de 500 itens |
| `413` | `PAYLOAD_TOO_LARGE` | Corpo acima de 8 MiB |
| `503` | `SERVER_OVERLOADED` | A admissão está saturada. Tente de novo após `Retry-After`. |
| `503` | `SERVER_OVERLOADED` | A fila global está cheia. Tente de novo após `Retry-After`. |

Um `idempotencyKey` repetido devolve a tarefa existente como sucesso. Veja [Idempotência](/pt/concepts/idempotency.md).

## `POST /v1/batches`

Envie até 10.000 itens ([referência](/pt/api-reference/create-batch.md)). Cada item aceita os campos de tarefa `taskType`, `payload`, `priority` e `idempotencyKey`, mais um `customId` opcional (até 128 caracteres) que é devolvido nos resultados. Defina `webhook.url` no lote, não nos itens.

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

A resposta é `202` com o lote. Os primeiros itens já foram enviados:

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

### Regras do envelope

| Campo | Regra |
| - | - |
| `items` | De 1 a 10.000 objetos |
| `webhook.url` | As mesmas [regras de URL](/pt/concepts/webhooks.md#regras-de-url) de uma tarefa. Vale para todos os itens. |
| `metadata` | Um objeto de no máximo 8 KB em JSON, devolvido sem alterações |
| `idempotencyKey` | De 1 a 256 caracteres. Uma repetição devolve o primeiro lote com `200`. |
| `idempotencyKey` do item | Precisa ser único dentro do lote |
| `webhook` do item | Rejeitado. Use o `webhook.url` do lote. |

### Validação tudo ou nada

Antes de qualquer coisa ser armazenada, cada item passa pelas mesmas verificações de uma tarefa individual: campos, escopo da chave, mecanismos privados, endpoints dedicados, região e `payload.location`. Se algum item falhar, a resposta é `400 VALIDATION_ERROR`, nada é armazenado e `details` lista até 50 itens com falha:

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

### Como os itens são executados

O lote libera itens como tarefas quando o limite do seu plano e a fila do mecanismo têm espaço. As contas se revezam, então um lote grande não segura um lote pequeno de outra conta. Cada item liberado passa pela mesma admissão de uma tarefa individual: faz uma reserva de créditos e conta para o limite diário de créditos da chave.

Quando um item é recusado, o código decide o que acontece:

| Código | Item |
| - | - |
| `PLAN_CONCURRENCY_LIMIT`, `KEY_DAILY_CREDIT_LIMIT`, `SERVER_OVERLOADED`, `DB_UNAVAILABLE`, `ENQUEUE_ERROR` | Fica `PENDING` e é tentado de novo depois |
| `QUEUE_BACKPRESSURE`, `ENGINE_UNAVAILABLE` | Fica `PENDING` e é tentado de novo depois |
| `API_KEY_INACTIVE` | `REJECTED`: a chave do lote foi revogada ou expirou, ou a subconta dela foi suspensa |
| Qualquer outro código, incluindo `INSUFFICIENT_CREDITS` | `REJECTED` |

O lote fica `COMPLETED` quando nenhum item está pendente e todas as tarefas terminaram. Com `webhook.url`, o servidor então publica o [evento `batch.completed`](/pt/concepts/webhooks#evento-de-conclusão-do-lote).

### Leia o progresso e os resultados

`GET /v1/batches/{id}` devolve o lote com `counts` por status de item: `pending`, `queued`, `processing`, `completed`, `failed`, `rejected`. Consultá-lo também faz os itens pendentes avançarem.

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

`GET /v1/batches/{id}/items` lista os itens na ordem de envio:

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

| Query | Descrição |
| - | - |
| `status` | Um de `pending`, `queued`, `processing`, `completed`, `failed`, `rejected` |
| `include=response` | Acrescenta a `response` ou o `error` de cada tarefa finalizada |
| `limit` | Padrão 100, máximo 1.000. Com `include=response`: padrão 20, máximo 100. |
| `cursor` | O `nextCursor` da página anterior |

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

Um item `REJECTED` traz `error: { code, message }`. Os corpos de resultado só são incluídos dentro da janela de polling de 24 horas de [Tarefas assíncronas](/pt/concepts/async-tasks.md#retenção). Veja também [Obter um lote](/pt/api-reference/get-batch.md) e [Listar itens do lote](/pt/api-reference/list-batch-items.md).

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

Faça um prompt a partir de cada ponto de uma grade quadrada em torno de um centro ([referência](/pt/api-reference/create-task-grid.md)). Cada ponto vira uma tarefa com esse ponto como `payload.location`, então o mecanismo precisa aceitar localização: `CHATGPT`, `GEMINI`, `GOOGLE`, `AIMODE` ou `GOOGLE_SERP`. Não envie `payload.location` você mesmo.

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

| Campo | Regra |
| - | - |
| `grid.size` | `3`, `5`, `7` ou `9` pontos por lado (de 9 a 81 tarefas) |
| `grid.radiusMeters` | De 100 a 50.000: a distância do centro ao meio de cada borda. Os pontos ficam a `2 × radius ÷ (size − 1)` de distância. |
| `grid.center` | Latitude e longitude em graus decimais. A grade precisa ficar abaixo de 89 graus de latitude. |
| `idempotencyKey` | Opcional, de 1 a 200 caracteres. Vira o id da grade. |
| `priority`, `webhook` | Aplicados a todos os pontos |

A linha 0 é a borda norte e a coluna 0, a borda oeste. A resposta devolve `grid` (com `id` e `spacingMeters`), um `summary` e `points` em ordem de linha, cada um com `row`, `col`, `location` e `task` ou `error`.

O ponto central é admitido primeiro, sozinho. Se ele for recusado (por exemplo, `422 LOCATION_UNSUPPORTED`, `403 KEY_SCOPE_DENIED`, `402 INSUFFICIENT_CREDITS` ou um plano cheio), esse erro é a resposta da grade inteira e nenhuma tarefa é criada. Os pontos depois do centro recusados por capacidade falham no lugar com `success: false`.

Leia uma grade com [`GET /v1/async/task/grid/{id}`](/pt/api-reference/get-task-grid). Adicione `?include=response` para os resultados das tarefas finalizadas. Pontos que nunca foram admitidos ficam ausentes, e o id de grade de outra conta retorna `404`. Reenviar a mesma grade com o mesmo id admite só os pontos que faltam; veja [Idempotência](/pt/concepts/idempotency.md#grades-de-localização).

## Próximos passos

> **[Idempotência](/pt/concepts/idempotency.md)**
>
> Como cada endpoint trata uma chave repetida.

> **[Créditos e limites](/pt/concepts/credits-and-limits.md)**
>
> Concorrência do plano e ritmo de envio.


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