# Bulk Jobs API Base path: `/api/v1/bulk-jobs` All endpoints require `Authorization: Bearer `. Related: [[02 - Videos API]], [[08 - Saved Views API]], [[10 - Quota API]] --- ## GET /bulk-jobs List bulk jobs for the current team. **Query parameters:** | Param | Type | Description | |---|---|---| | `status` | string | Optional filter by job status | **Response:** `BulkJob[]` --- ## GET /bulk-jobs/:id Get a single bulk job with all of its individual item records. **Response:** `BulkJob` with `items: BulkJobItem[]` --- ## POST /bulk-jobs/:id/rollback Roll back a completed bulk job, reverting the changes made to each item. Requires `EDITOR` role. **Response:** Updated `BulkJob` **What rollback does:** For each `BulkJobItem` with `status: "done"`, the rollback service writes `item.beforeSnapshot` back to the `Video` row. `beforeSnapshot` contains the `youtubeSnapshot` fields captured before the push: `title`, `tags`, `categoryId`, `privacyStatus`, `defaultLanguage`, `defaultAudioLanguage`, `selfDeclaredMadeForKids`, `embeddable`, `license`, `recordingDate`. **For `SYNC_PUSH` jobs specifically:** Rollback is a **local-only operation**. YouTube is not contacted and the data already pushed to YouTube is not reversed. After rollback: - The `Video` row's fields are restored to their pre-push values. - `lastSyncedHash` is **not** restored — it retains the hash computed at push time. - Because the local fields no longer match `lastSyncedHash`, the video will show as "push pending" again. This is the expected outcome: the local DB now diverges from YouTube, and a new push is required to re-align them. This means rollback on a `SYNC_PUSH` job does not undo anything on YouTube — it only rewinds the local record and marks the video as needing another sync. --- ## GET /bulk-jobs/push-pending/preview Preview all push-pending videos with field-level diffs showing what will change when pushed to YouTube. **Query parameters:** | Param | Type | Description | |---|---|---| | `sort` | string | Field to sort by | | `order` | `asc\|desc` | Sort direction | **Response:** Array of per-video diff previews --- ## POST /bulk-jobs/push-pending Create a bulk sync job for a selected set of push-pending videos. Enqueues YouTube sync jobs for each video. Requires `EDITOR` role. **Request body:** ```json { "videoIds": ["cuid", "cuid"] } ``` > Tip: use `POST /saved-views/:id/execute` to get a `videoIds` list from a saved view. See [[08 - Saved Views API]]. **Response:** Created `BulkJob` --- ## Bulk Change (Header modal) The following endpoints power the bulk metadata change modal in the application header. ### POST /bulk-jobs/preview Preview the effect of a bulk metadata change before applying it. **Request body:** ```json { "type": "SET_PRIVACY|SET_TEMPLATE|ADD_TAGS|REMOVE_TAGS|SEARCH_REPLACE_TITLE", "payload": {}, "savedViewId": "cuid" } ``` **`type` values:** | Type | Description | |---|---| | `SET_PRIVACY` | Change privacy status for matched videos | | `SET_TEMPLATE` | Apply a template to matched videos | | `ADD_TAGS` | Add tags to matched videos | | `REMOVE_TAGS` | Remove tags from matched videos | | `SEARCH_REPLACE_TITLE` | Find and replace in video titles | `savedViewId` is optional. When provided, the operation is scoped to videos matching that saved view. **Response:** ```json { "count": 5, "type": "SET_PRIVACY", "previews": [ { "videoId": "cuid", "before": { "privacyStatus": "PRIVATE" }, "after": { "privacyStatus": "PUBLIC" } } ] } ``` --- ### POST /bulk-jobs/apply Apply a previewed bulk metadata change. Creates a `BulkJob` record and processes each matched video. Requires `EDITOR` role. **Request body:** Same shape as `POST /bulk-jobs/preview`. **Response:** Created `BulkJob` --- ## Notes - Bulk sync jobs consume YouTube API quota (50 units per video pushed). Check remaining quota via `GET /quota/today` before triggering large bulk pushes. See [[10 - Quota API]]. - `BulkJob` items record `before` and `after` snapshots for each video, enabling rollback. - Rollback is only available for completed jobs and reverses the stored `before` snapshot.