BuildBatches

Batches

⚠️
Preview — this feature is being built; the design below is the spec.

A batch is a set of up to 50,000 requests that you submit in one go and collect later. Syntic runs them when capacity is free, finishes within 24 hours (usually much sooner), and charges 50% of the normal token price. Use it for work nobody is waiting on.

When to use it

  • Classifying, tagging or summarising a large backlog.
  • Running evaluations over a test set.
  • Generating product descriptions, translations or embeddings-style metadata overnight.

Do not use batches for anything a person is waiting to see.

How it works

Prepare a JSONL file

One request per line, each with your own custom_id.

Upload it and create the batch

Upload with the Files API (purpose: "batch"), then POST /v1/batches. Small batches can be sent inline instead.

Wait

Poll GET /v1/batches/{id} or register a webhook for batch.completed.

Download results

Fetch the results file. Lines come back in any order; match them by custom_id.

Endpoints

MethodPathPurpose
POST/v1/batchesCreate a batch.
GET/v1/batchesList batches, newest first (limit, after_id, before_id).
GET/v1/batches/{batch_id}Get status and counts.
POST/v1/batches/{batch_id}/cancelStop starting new requests.
GET/v1/files/{output_file_id}/contentDownload results.

Base URL https://app.syntic.ai/v1 (the paths above already include /v1), Authorization: Bearer sk_live_....

Input file

Each line is one JSON object:

{"custom_id": "ticket-1001", "endpoint": "/v1/chat/completions", "body": {"model": "Amara Quick", "max_tokens": 20, "messages": [{"role": "user", "content": "Label this ticket: My parcel never arrived."}]}}
{"custom_id": "ticket-1002", "endpoint": "/v1/chat/completions", "body": {"model": "Amara Quick", "max_tokens": 20, "messages": [{"role": "user", "content": "Label this ticket: How do I change my password?"}]}}
FieldDetails
custom_idYour id, 1 to 64 characters, unique within the batch.
endpoint/v1/chat/completions or /v1/messages.
bodyA normal request body. stream must be absent or false. Every feature works except server tools that need a live connection (MCP connector).

Create request

FieldTypeRequiredDetails
input_file_idstringOne of these twoA batch file.
requestsarrayOne of these twoUp to 1,000 inline lines in the same shape as the file.
completion_windowstringNoOnly "24h" today.
metadataobjectNoUp to 16 string pairs, returned unchanged.

The batch object

{
  "id": "batch_01JBXF3P8K",
  "object": "batch",
  "status": "in_progress",
  "input_file_id": "file_01JBXF1Z",
  "output_file_id": null,
  "error_file_id": null,
  "request_counts": { "total": 5000, "succeeded": 3120, "failed": 4, "canceled": 0 },
  "created_at": 1791820800,
  "started_at": 1791820860,
  "ends_by": 1791907200,
  "completed_at": null,
  "metadata": { "job": "october-tickets" }
}
statusMeaning
validatingChecking the file. Bad lines fail the whole batch here, with details in errors.
in_progressRunning.
cancelingCancel requested; running requests finish.
completedAll lines done. output_file_id is set.
expiredThe 24 hours ran out; finished lines are in the output, the rest are expired.
canceledCancelled; finished lines are in the output.
failedValidation failed. Nothing ran or was billed.

Results file

One line per request, any order:

{"custom_id": "ticket-1001", "result": {"type": "succeeded", "status_code": 200, "body": {"id": "chatcmpl-...", "choices": [{"index": 0, "message": {"role": "assistant", "content": "delivery"}, "finish_reason": "stop"}], "usage": {"prompt_tokens": 21, "completion_tokens": 2, "total_tokens": 23}}}}
{"custom_id": "ticket-1002", "result": {"type": "errored", "status_code": 400, "error": {"type": "invalid_request", "code": "max_tokens_too_large", "message": "...", "param": "max_tokens"}}}

result.type is succeeded, errored, canceled or expired. Only succeeded lines are billed. Results files expire 30 days after the batch ends.

Examples

# 1. Upload
curl https://app.syntic.ai/v1/files -H "Authorization: Bearer $SYNTIC_API_KEY" \
  -F purpose=batch -F file=@tickets.jsonl
 
# 2. Create
curl https://app.syntic.ai/v1/batches \
  -H "Authorization: Bearer $SYNTIC_API_KEY" -H "Content-Type: application/json" \
  -d '{"input_file_id":"file_01JBXF1Z","completion_window":"24h","metadata":{"job":"october-tickets"}}'
 
# 3. Check
curl https://app.syntic.ai/v1/batches/batch_01JBXF3P8K -H "Authorization: Bearer $SYNTIC_API_KEY"
 
# 4. Download
curl https://app.syntic.ai/v1/files/file_01JBXG7Q/content -H "Authorization: Bearer $SYNTIC_API_KEY" -o results.jsonl

Errors

Unified envelope for the batch endpoints. Per-request errors appear inside the results file.

StatuscodeCause
400invalid_batch_fileA line is not valid JSON or misses a field. message gives the line number.
400duplicate_custom_idTwo lines share a custom_id.
400streaming_not_allowedA body has stream: true.
400too_many_requests_in_batchMore than 50,000 lines or 500 MB.
404batch_not_foundUnknown id or another workspace’s batch.
409batch_not_cancelableAlready finished.
429batch_queue_fullToo many queued requests for your tier.

Limits and pricing

LimitValue
Requests per batch50,000
Input file500 MB
Queued requests per organisation500,000 (higher on upper tiers)
Window24 hours
Price50% of the standard input, cached input and output rates. Server-tool fees are not discounted.

Batch traffic does not count towards per-minute rate limits.

Build notes for the platform team

  • Tables: batches, batch_items (status, attempt, result offset). Workers pull items in off-peak capacity first.
  • Bill per succeeded item at the batch rate with usage.service_tier = "batch".
  • Fire batch.completed through the shared webhook system.
  • Depends on Files API and workspaces.
Was this page helpful?