---
title: "Create a bulk YouTube job and obtain a direct R2 upload URL"
method: POST
path: "/bulk-jobs"
tags: ["Bulk Jobs"]
---

# Create a bulk YouTube job and obtain a direct R2 upload URL

`POST /bulk-jobs`

## Request

- Base URL: `https://api.flashdata.dev/v2`
- URL: `https://api.flashdata.dev/v2/bulk-jobs`
- Auth: one of:
  - API key in cookie `__Host-fd_session` and API key in header `X-CSRF-Token`
  - API key in header `X-API-Key`

Creates an awaiting-upload coordinator record. Upload a UTF-8 text file containing one 11-character YouTube video ID per line to upload.href, then call the start operation. The file can be streamed and may contain millions of IDs.

## Request body

- CreateBulkJobRequest
  - `source` 'youtube_metadata' | 'youtube_transcript' | 'youtube_captions' | 'youtube_trainability' | 'youtube_download', required
  - `options` object: Reused for every ID. Metadata accepts include_formats and include_chapters. Transcript and captions accept language and auto. Trainability accepts no source options. These four data sources optionally accept result_storage. Supported storage_type values are s3, s3_compatible, oss, gcs, azure, cos, bos, and tos. storage_url is the bucket name (Azure container name); object_prefix is optional. S3, S3-compatible, OSS, COS, BOS, and TOS use access_key and secret_key. S3-compatible and OSS also require a public HTTPS endpoint_url. COS, BOS, and TOS require region and use fixed provider endpoints. COS bucket names include the APPID. BOS S3-compatible HTTPS delivery supports bj, su, and hkg. GCS requires service_account with project_id, client_email, and private_key. Azure requires account_name and a container SAS sas_token with write permission. Default object_prefix is YYYYMMDD, frozen to the UTC bulk creation date. Files are written to <prefix>/<source>/<bulkId>/results/part-NNNNNNNN.jsonl.gz; manifest.json in the same bulk directory is written last. Each JSONL row includes its input index and completed, failed, or invalid status. Internal R2 results remain available through the result links for 24 hours. Download accepts the normal YouTube download parameters, requires customer storage, and does not permit browser_delivery. Download storage supports the same eight provider types and credential shapes listed above under the storage field. Download storage may include object_prefix; YYYYMMDD tokens resolve to the UTC upload date, while literal prefixes are unchanged.
  - `callback_url` string, uri: Optional public HTTPS endpoint notified once after manifest publication.

## Response `201`

Bulk job created with a 15-minute direct upload URL

- BulkJobCreated
  - `job` BulkJob, required
    - `id` string, required
    - `source` 'youtube_metadata' | 'youtube_transcript' | 'youtube_captions' | 'youtube_trainability' | 'youtube_download', required
    - `status` 'awaiting_upload' | 'running' | 'paused' | 'finalizing' | 'completed' | 'failed' | 'cancelled', required
    - `input` object, required
      - `bytes` integer, required
      - `complete` boolean, required
      - `scannedBytes` integer, required
      - `scannedLines` integer, required
    - `counts` object, required
      - `accepted` integer, required
      - `completed` integer, required
      - `failed` integer, required
      - `invalid` integer, required
      - `results` integer, required
    - `pauseReason` string, nullable, required
    - `delivery` object, required
      - `customerStorage` boolean, required
      - `storageType` 's3' | 's3_compatible' | 'oss' | 'gcs' | 'azure' | 'cos' | 'bos' | 'tos' | 'null', nullable, required
      - `uploadedParts` integer, required
      - `retryCount` integer, required
    - `error` object, nullable, required
      - `code` string, required
      - `detail` string, nullable, required
    - `createdAt` string, date-time, required
    - `startedAt` string, date-time, nullable, required
    - `completedAt` string, date-time, nullable, required
    - `expiresAt` string, date-time, nullable, required
    - `links` JobLink[], required
      - `rel` 'self' | 'results' | 'content' | 'download', required
      - `href` string, uri, required
      - `method` 'GET', required
      - `expires_at` string, date-time
      - `filename` string
      - `content_type` string
      - `size_bytes` integer
  - `upload` object, required
    - `href` string, uri, required
    - `method` 'PUT', required
    - `expiresAt` string, date-time, required
    - `contentType` 'text/plain; charset=utf-8', required

## Other responses

- `401`: Authentication required or invalid
- `422`: Request validation failed
- `503`: A required dependency or catalog is temporarily unavailable

---

[API](https://skmtc.dev/flashdata/apis/flashdata-customer-api.md) · [All operations](https://skmtc.dev/flashdata/apis/flashdata-customer-api/llms.txt) · [OpenAPI document](https://skmtc.dev/flashdata/apis/flashdata-customer-api/revisions/109179fe9313?raw)
