Batch
Submit many videos in one request and track them as a unit.
A batch runs the same capabilities across many videos and reports progress as a unit. Batches can also answer aggregate questions spanning every video in the set.
Batch size is plan-gated: Free has no batch access (BATCH_NOT_ALLOWED, 403). Starter allows 10 videos per batch,
Pro 25, Scale 50.
POST /v1/batch
Request body
Provide urls, uploads, or both — at least one source in total.
| Prop | Type | Description |
|---|---|---|
| urls | string[] | Video URLs. Max 50, and no more than your plan allows across urls + uploads combined. |
| uploads | UploadRef[] | Uploaded files as { key, filename, duration_seconds? }, using keys from POST /v1/uploads/presign. |
| capabilities | string[] | One or more of: transcription, summary, brands, metadata. Applied to every video in the batch. |
| queries | string[] | Per-video custom questions. Max 500 chars each. |
| aggregate | { enabled, queries? } | Cross-video questions answered once for the whole batch. Capped by your plan's max_aggregate_queries_per_batch (0 on Free and Starter). |
| webhook_url | string | HTTPS URL for batch.completed and batch.paused delivery. Starter and above. |
| return_proof | boolean | Include visual evidence, as on single jobs. Defaults to true. |
| dry_run | boolean | Return the per-job and total cost estimate with HTTP 200 and create nothing. Defaults to false. |
| max_credits | integer | Reject with BUDGET_EXCEEDED (402) if the total estimate exceeds this cap. |
curl -X POST https://api.netraflow.com/v1/batch \
-H "Content-Type: application/json" \
-H "X-Api-Key: sk_live_your_key_here" \
-d '{
"urls": [
"https://www.youtube.com/watch?v=example1",
"https://www.tiktok.com/@user/video/example2"
],
"capabilities": ["brands"],
"brands": ["Nike"],
"aggregate": { "enabled": true, "queries": ["Which brand appears most often?"] }
}'{
"data": {
"batch_id": "bat_abc123",
"status": "processing",
"total_credits_estimated": 52,
"balance": 400,
"would_exceed_balance": false,
"jobs": [
{
"job_id": "job_aaa",
"url": "https://www.youtube.com/watch?v=example1",
"platform": "youtube",
"duration_seconds": null,
"credits_estimated": 26,
"status": "pending",
"note": "duration_unresolved"
},
{
"job_id": "job_bbb",
"url": "https://www.tiktok.com/@user/video/example2",
"platform": "tiktok",
"duration_seconds": null,
"credits_estimated": 26,
"status": "pending"
}
]
},
"meta": { "request_id": "req_xyz789" }
}would_exceed_balance is a warning, not a rejection — the batch is still created. Jobs that can't be afforded once their real duration is known move to held and the batch reports paused. Use dry_run: true to price a batch without creating it (the response omits batch_id and per-job job_id/status).
GET /v1/batch/:id
curl https://api.netraflow.com/v1/batch/bat_abc123 \
-H "X-Api-Key: sk_live_your_key_here"{
"data": {
"batch_id": "bat_abc123",
"status": "paused",
"total_jobs": 10,
"completed_count": 4,
"failed_count": 0,
"rollup": {
"total": 10,
"pending": 0,
"processing": 0,
"completed": 4,
"held": 6,
"failed": 0,
"cancelled": 0
},
"credits_estimated": 260,
"credits_charged": 104,
"jobs": [
{
"job_id": "job_aaa",
"status": "held",
"url": "https://www.youtube.com/watch?v=example1",
"credits_estimated": 26,
"reason": "insufficient_credits"
}
],
"aggregate_results": null,
"webhook_url": null,
"created_at": "2026-04-03T12:00:00.000Z",
"completed_at": null
},
"meta": { "request_id": "req_abc456" }
}Prefer rollup over completed_count / failed_count — the legacy counters can't represent held.
Batch status values
| Prop | Type | Description |
|---|---|---|
| processing | string | At least one job is pending or processing. |
| paused | string | Non-terminal. No runnable jobs remain and at least one is held for credits. Add credits and the batch resumes automatically. |
| completed | string | Every job reached a terminal state. |
| failed | string | The batch as a whole failed. |
| cancelled | string | The batch was cancelled. |
GET /v1/batch
List batches with cursor-based pagination. Accepts status, limit (1-100, default 20), and cursor.
curl "https://api.netraflow.com/v1/batch?status=completed&limit=10" \
-H "X-Api-Key: sk_live_your_key_here"POST /v1/batch/:id/cancel
Cancels the batch and every pending, processing, or held job in it. Idempotent — cancelling an already-cancelled batch succeeds without changing anything.
curl -X POST https://api.netraflow.com/v1/batch/bat_abc123/cancel \
-H "X-Api-Key: sk_live_your_key_here"The response reports cancelled_jobs. Jobs already completed are untouched and remain charged.
Error codes
| Code | HTTP | Description |
|---|---|---|
BATCH_NOT_ALLOWED | 403 | Batch is not available on your plan (Free) |
TOO_MANY_URLS | 422 | More sources than your plan's max_batch_size |
TOO_MANY_AGGREGATE_QUERIES | 422 | Exceeds max_aggregate_queries_per_batch |
BATCH_NOT_FOUND | 404 | Batch does not exist or belongs to another workspace |
BATCH_NOT_CANCELLABLE | 409 | Batch is already in a terminal state |
Single-job error codes apply to the jobs inside a batch. See Jobs.