POST /api/v1/forward/batches
Forward validates the input file and JSONL line format, then schedules execution automatically inside the off-peak window. When the batch finishes, output.jsonl and error.jsonl are produced for download.
| Header | Required | Description |
|---|
Authorization | Yes | Bearer <PAT or SAT> |
Content-Type | Yes | application/json |
Idempotency-Key | No | Optional idempotency key for unsafe requests. |
Creating a batch requires a JSONL input file uploaded through the CAS Files API to obtain a file_id.
JSONL format — one JSON object per line, one line per independent task:
{"custom_id": "task-001", "template_id": "tmpl_example001", "identity_id": "idn_example001", "body": {"input": "hello"}}
{"custom_id": "task-002", "template_id": "tmpl_example001", "identity_id": "idn_example001", "body": {"input": "write me a short poem about summer"}}
| Field | Type | Required | Description |
|---|
custom_id | string | Yes | Caller-defined identifier. Must be unique within a single batch and is used to map result lines. |
template_id | string | Yes | Forward Template ID that drives execution. |
identity_id | string | Yes | Forward Identity ID that provides the execution identity. |
body | object | Yes | Request body passed to Session. Its shape depends on the Template. Common shape: {"input": "user input"}. |
Upload the file:
curl -X POST 'https://api.qoder.com.cn/api/v1/cloud/files' \
-H "Authorization: Bearer $QODER_ACCESS_TOKEN" \
-F "file=@batch_input.jsonl" \
-F "purpose=session_resource"
purpose=session_resource is required for Batch input files. If this field is omitted, the Files API stores the file with user_upload; CAS does not allow server-side downloads of such files, and Create Batch returns 400 invalid_input_file.
The returned id is the input_file_id for Create Batch.
Body parameters
| Parameter | Type | Required | Description |
|---|
input_file_id | string | Yes | JSONL file ID uploaded via the Files API. |
completion_window | string | Yes | Completion window: 24h, 48h, or 72h. The batch moves to expired when the window elapses. |
metadata | object | No | Caller-supplied metadata. Up to 16 keys, any JSON value; the serialized object must be ≤ 2KB, each key ≤ 64 characters, and no NUL (U+0000) is allowed. |
Example request
curl -s -X POST 'https://api.qoder.com.cn/api/v1/forward/batches' \
-H "Authorization: Bearer $QODER_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: idem_batch_001" \
-d '{
"input_file_id": "file_input001",
"completion_window": "24h",
"metadata": {
"source": "data_pipeline",
"job_id": "12345"
}
}'
Example response
HTTP 200 OK
{
"id": "batch_example001",
"object": "batch",
"status": "validating",
"input_file_id": "file_input001",
"completion_window": "24h",
"created_at": "2026-07-07T07:25:01Z",
"expires_at": "2026-07-08T07:25:01Z",
"request_counts": {
"total": 0,
"pending": 0,
"running": 0,
"completed": 0,
"failed": 0,
"cancelled": 0,
"expired": 0
},
"usage": null
}
A newly created batch starts in validating and moves to queued once validation passes. output_file_id and error_file_id only appear after the batch reaches a terminal state and are omitted from the create response.
Response fields
| Field | Type | Description |
|---|
id | string | Batch ID with prefix batch_. |
object | string | Always batch. |
status | string | Batch status. See the status table below. |
input_file_id | string | Input JSONL file ID. |
completion_window | string | Completion window: 24h, 48h, or 72h. |
created_at | string | Creation time, RFC 3339. |
expires_at | string | Expiration time, created_at + completion_window. |
request_counts | object | Aggregate task counters. |
usage | object/null | null in the create response. In subsequent batch detail, list, and cancellation responses, returns aggregate Credit usage after at least one subtask has valid CAS Session usage. |
usage.total_credits | number | Sum of persisted subtask total_credits. The unit is CAS Credit, not tokens or currency. Explicit zero values are preserved. |
metadata | object | Caller-supplied metadata. |
Batch status
| Status | Description | Type |
|---|
validating | Validating the input file and JSONL lines. | Non-terminal |
queued | Validated. Waiting for the off-peak window. | Non-terminal |
processing | Executing tasks. | Non-terminal |
cancelling | Cancellation in progress. Waiting for running tasks to finish. | Non-terminal |
expiring | Expiration in progress. Waiting for running tasks to finish. | Non-terminal |
finalizing | Generating output files. | Non-terminal |
completed | All tasks executed. Output files generated. | Terminal |
failed | Input validation failed or unrecoverable system error. | Terminal |
cancelled | Cancelled by the user. | Terminal |
expired | The completion_window elapsed. | Terminal |
Request counts
| Field | Type | Description |
|---|
total | integer | Total lines, including lines that failed validation. |
pending | integer | Lines waiting to run. |
running | integer | Lines currently executing. |
completed | integer | Lines that finished successfully. |
failed | integer | Lines that failed permanently, including validation failures. |
cancelled | integer | Lines terminated by cancellation. |
expired | integer | Lines terminated by expiration. |
The invariant total = pending + running + completed + failed + cancelled + expired always holds.
Validation rules
Create Batch rejects the following errors upfront rather than enqueuing:
- JSON parse failure → line marked
failed
- Missing required field → line marked
failed
- Duplicate
custom_id → line marked failed
- Tool permission policy set to
always_ask or always_deny → line marked failed (unattended execution disallows these)
Validation failures on individual lines do not block other lines; they are written together to error.jsonl.
Error codes
| HTTP | Type | Code | Trigger |
|---|
| 400 | invalid_request_error | invalid_request | input_file_id missing, invalid completion_window, or metadata too large. |
| 400 | invalid_request_error | invalid_input_file | The input file cannot be downloaded by Batch. Upload it with purpose=session_resource. |
| 429 | rate_limit_error | rate_limit_exceeded | The user has reached the maximum number of unfinished batches. |
| 401 | authentication_error | authentication_required | PAT is invalid or expired. |
Notes
- A single batch supports up to 10,000 JSONL lines.
- Global concurrency is capped at 50 tasks.
- Scheduling runs inside the off-peak window (default 22:00–08:00, configurable server-side).
- After creating a batch, the client should poll
GET /api/v1/forward/batches/{batch_id} until a terminal state is reached.