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

# 批量提交任务：批次与位置网格

> 在 500 任务批量请求、10,000 任务批次对象和位置网格之间做出选择，然后提交并读取结果。

有三个端点可以在一个请求中创建大量任务。每个端点创建的都是普通任务：轮询、webhook、积分和套餐限制与单个任务相同。

## 三个端点对比

| | `POST /v1/async/task/batch` | `POST /v1/batches` | `POST /v1/async/task/grid` |
| - | - | - | - |
| 发送内容 | 任务请求的 JSON 数组 | `{ items, webhook?, metadata?, idempotencyKey? }` | 一个任务请求加 `grid` |
| 最大任务数 | 500 | 10,000 | 81（9 × 9 网格） |
| 最大正文 | 8 MiB | 32 MiB | 1 MiB |
| 成功状态 | `200` | 创建时 `202`，`idempotencyKey` 重复时 `200` | `200` |
| 校验 | 逐项单独校验；无效项目就地失败 | 先校验所有项目；任一项目无效即以 `400` 拒绝整个批次，不存储任何内容 | 先校验中心点；中心点被拒则整个网格被拒 |
| 超出套餐限制时 | 多出的项目以 `PLAN_CONCURRENCY_LIMIT` 失败，需要你重新提交 | 项目在服务器端等待，有空位时释放 | 多出的点位就地失败 |
| 进度 | 逐个轮询任务 | `GET /v1/batches/{id}` 计数 | `GET /v1/async/task/grid/{id}` |
| 完成信号 | 每个任务一个 webhook | 每个任务一个 webhook，然后是 `batch.completed` | 每个任务一个 webhook |

## 选择哪一个

* **不超过 500 个任务，且你自己处理重试：**`POST /v1/async/task/batch`。响应中包含所有任务 id。
* **任务数超过套餐并发，或每天运行数千个任务的作业：**`POST /v1/batches`。服务器保存项目，并在[套餐限制](/zh/concepts/credits-and-limits.md#套餐并发)和各引擎队列允许时逐步送入，你无需自己重试 `429` 或 `503`。
* **从某地周围的多个点位提同一个提示词：**`POST /v1/async/task/grid`。

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

发送最多 500 个任务请求组成的数组（[参考](/zh/api-reference/create-task-batch.md)）。可以混用引擎。

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

格式正确的请求返回 `200`。`results[i].index` 对应你数组中的位置，每个结果包含 `task` 或 `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"
      }
    }
  ]
}
```

以下情况会拒绝整个请求，不创建任何任务：

| 状态 | 错误码 | 情形 |
| - | - | - |
| `400` | `VALIDATION_ERROR` | 不是有效 JSON、不是数组、为空，或超过 500 项 |
| `413` | `PAYLOAD_TOO_LARGE` | 正文超过 8 MiB |
| `503` | `SERVER_OVERLOADED` | 准入已饱和。请在 `Retry-After` 之后重试。 |
| `503` | `SERVER_OVERLOADED` | 全局队列已满。请在 `Retry-After` 之后重试。 |

重复的 `idempotencyKey` 会以成功形式返回已存在的任务。参见[幂等性](/zh/concepts/idempotency.md)。

## `POST /v1/batches`

发送最多 10,000 个项目（[参考](/zh/api-reference/create-batch.md)）。每个项目接受任务字段 `taskType`、`payload`、`priority` 和 `idempotencyKey`，以及可选的 `customId`（最多 128 个字符），它会在结果中原样返回。`webhook.url` 设在批次上，而不是项目上。

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

响应为 `202`，返回批次。最初的项目已经提交：

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

### 信封规则

| 字段 | 规则 |
| - | - |
| `items` | 1 到 10,000 个对象 |
| `webhook.url` | 与任务相同的 [URL 规则](/zh/concepts/webhooks.md#url-规则)。适用于每个项目。 |
| `metadata` | 序列化为 JSON 后不超过 8 KB 的对象，原样返回 |
| `idempotencyKey` | 1 到 256 个字符。重复时以 `200` 返回第一个批次。 |
| 项目 `idempotencyKey` | 在批次内必须唯一 |
| 项目 `webhook` | 会被拒绝。请使用批次的 `webhook.url`。 |

### 全有或全无的校验

在存储任何内容之前，每个项目都会经过与单个任务相同的检查：字段、密钥范围、私有引擎、专用端点、地区和 `payload.location`。任一项目失败，响应即为 `400 VALIDATION_ERROR`，不存储任何内容，`details` 最多列出 50 个失败项目：

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

### 项目如何运行

当套餐限制和引擎队列有空位时，批次会把项目作为任务释放。各账户轮流进行，因此一个大批次不会阻塞其他账户的小批次。每个释放的项目都经过与单个任务相同的准入流程：冻结积分，并计入密钥的每日积分上限。

项目被拒绝时，由错误码决定后续处理：

| 错误码 | 项目 |
| - | - |
| `PLAN_CONCURRENCY_LIMIT`、`KEY_DAILY_CREDIT_LIMIT`、`SERVER_OVERLOADED`、`DB_UNAVAILABLE`、`ENQUEUE_ERROR` | 保持 `PENDING`，稍后再试 |
| `QUEUE_BACKPRESSURE`、`ENGINE_UNAVAILABLE` | 保持 `PENDING`，稍后再试 |
| `API_KEY_INACTIVE` | `REJECTED`：批次的密钥已吊销或过期，或其子账户已被停用 |
| 其他任何错误码，包括 `INSUFFICIENT_CREDITS` | `REJECTED` |

没有待处理项目且所有任务都结束后，批次变为 `COMPLETED`。设置了 `webhook.url` 时，服务器随后发送 [`batch.completed` 事件](/zh/concepts/webhooks#批次完成事件)。

### 读取进度与结果

`GET /v1/batches/{id}` 返回批次及按项目状态统计的 `counts`：`pending`、`queued`、`processing`、`completed`、`failed`、`rejected`。轮询它也会推动待处理项目继续前进。

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

`GET /v1/batches/{id}/items` 按提交顺序列出项目：

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

| 查询参数 | 说明 |
| - | - |
| `status` | `pending`、`queued`、`processing`、`completed`、`failed`、`rejected` 之一 |
| `include=response` | 附加每个已结束任务的 `response` 或 `error` |
| `limit` | 默认 100，最大 1,000。使用 `include=response` 时默认 20，最大 100。 |
| `cursor` | 上一页的 `nextCursor` |

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

`REJECTED` 项目带有 `error: { code, message }`。结果正文只在[异步任务](/zh/concepts/async-tasks.md#保留期)的 24 小时轮询窗口内返回。另请参阅[获取批次](/zh/api-reference/get-batch.md)和[列出批次项目](/zh/api-reference/list-batch-items.md)。

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

从中心周围方形网格的每个点位提同一个提示词（[参考](/zh/api-reference/create-task-grid.md)）。每个点位成为一个以该点为 `payload.location` 的任务，因此引擎必须支持位置：`CHATGPT`、`GEMINI`、`GOOGLE`、`AIMODE` 或 `GOOGLE_SERP`。不要自己发送 `payload.location`。

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

| 字段 | 规则 |
| - | - |
| `grid.size` | 每边 `3`、`5`、`7` 或 `9` 个点位（9 到 81 个任务） |
| `grid.radiusMeters` | 100 到 50,000：从中心到每条边中点的距离。点位间距为 `2 × radius ÷ (size − 1)`。 |
| `grid.center` | 十进制度数表示的纬度和经度。网格必须保持在纬度 89 度以下。 |
| `idempotencyKey` | 可选，1 到 200 个字符。它会成为网格 id。 |
| `priority`、`webhook` | 应用于每个点位 |

第 0 行是北边，第 0 列是西边。响应返回 `grid`（含 `id` 和 `spacingMeters`）、`summary`，以及按行排序的 `points`，每个点位包含 `row`、`col`、`location`，以及 `task` 或 `error` 之一。

中心点会最先、单独被准入。如果它被拒绝（例如 `422 LOCATION_UNSUPPORTED`、`403 KEY_SCOPE_DENIED`、`402 INSUFFICIENT_CREDITS` 或套餐已满），该错误就是整个网格的响应，不创建任何任务。中心点之后因容量被拒的点位会以 `success: false` 就地失败。

用 [`GET /v1/async/task/grid/{id}`](/zh/api-reference/get-task-grid) 读取网格。加上 `?include=response` 可获取已结束任务的结果。从未被准入的点位不会出现，其他账户的网格 id 返回 `404`。以同一 id 重新发送同一网格只会准入缺失的点位；参见[幂等性](/zh/concepts/idempotency.md#位置网格)。

## 下一步

> **[幂等性](/zh/concepts/idempotency.md)**
>
> 各端点如何处理重复的键。

> **[积分与限制](/zh/concepts/credits-and-limits.md)**
>
> 套餐并发与提交节奏。


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