Skip to main content
Glama

Create Bulk Actions

create_bulk_actions
Destructive

Batch up to 1,000 Wistia create, update, delete, or move actions asynchronously, then track aggregate progress and per-action results.

Instructions

Submits a batch of up to 1000 create, update, delete, and move actions to be processed asynchronously. Returns a background job status whose Show endpoint reports aggregate progress and per-action results, including the hashed IDs of created records.

Supported resource types are media, folder, subfolder, channel, channel_episode, captions, and the ten customization_* concerns. A folder is a top-level folder (previously called a project); a subfolder is nested inside one and requires folder_id and name when created. A captions action operates on one caption track -- one media in one language.

Because caption actions carry SRT contents inline, they are the resource type most likely to reach the request body limit before the action cap. Purchasing captions is not available here -- it has its own endpoint.

A move action targets one media and accepts a destination folder_id and optional subfolder_id. Bulk moves can use different destinations and are not subject to the Move Media endpoint's 100-item limit or separate throttle.

Player customizations are addressed one concern at a time (customization_appearance, customization_playback, and so on), matching the Update Customizations endpoints; each accepts update only, takes the media's hashed ID as its id, and takes the same payload as its corresponding endpoint. There is no batch equivalent of the broad customize endpoint, so a batch always states which slice of the player it is changing.

A media update payload can also carry a custom_metadata object mapping field keys to the values to set (null clears a field; omitted fields are left untouched). Values are validated against each field's type exactly as the Set Custom Metadata Field Value endpoint validates them, and each write is recorded with its actor and source. Requires the custom metadata feature on the account; without it actions carrying custom_metadata fail individually.

Deleting a folder or subfolder also soft-deletes its media. An account owner or manager can restore that media from the trash until it purges. To keep the media when deleting a subfolder, use the Delete Subfolder endpoint; it moves the media to the folder's root level instead.

Each action in the batch is authorized and processed independently: failures (including authorization failures) are reported per action and do not prevent other actions from completing. Media creation is not supported -- uploads and URL imports have their own endpoints.

Requires api token with one of the following permissions

Read, update & delete anything

Tokens with the "Act with a team member's permissions" permission (all:delegate_to_contact_permissions scope) can also be used. Requests made with such a token are authorized using the permissions of the contact assigned to the token. Requires confirm=true for the requested mutation. May share access, notify people or incur provider charges.

Input Schema

NameRequiredDescriptionDefault
jobNo
accountNoNamed private Wistia account; selects credentials, not a remote account ID.
actionsNo
confirmNoSet true only when the user asked for exactly this action.
payloadNoComplete JSON request body instead of body flags. Supports current nested customization, caption and nullable values.
payload_fileNoRegular local JSON body file, at most 5 MB. Cannot be mixed with body flags or payload.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed26 schema fields changedv3.0.0
    • addedInput schema / $defs
      Added value: +{
      +  "actions": {
      +    "description": "An array of actions to process, one per record. Maximum 1000 actions per\nrequest, and the request body must stay under 2 MB -- whichever limit is\nreached first. An oversized body is rejected with a `413` and no action\nin it runs. Each action specifies an operation (create, update, delete,\nor move), a resource type, and the relevant payload or record ID.\n\nUse `job` instead when every record takes the same payload.\n",
      +    "items": {
      +      "description": "A single action within a bulk request.",
      +      "properties": {
      +        "id": {
      +          "description": "The hashed ID of the resource. Required for update, delete, and move\noperations.\n\nFor `captions` this is the caption track's own ID (the `id` field\nreturned by List Captions), not the media's -- a media can have a track\nper language.\n",
      +          "type": "string"
      +        },
      +        "operation": {
      +          "description": "The operation to perform. Media creation is not supported here --\nuploads and URL imports have their own endpoints.\n\n`delete` also soft-deletes media inside a `folder` or `subfolder`. An\naccount owner or manager can restore it from the trash until it purges.\n\n`move` applies to `media` only, one action per media. Each action\ncarries its own destination, so a single request can move media into\nmany different folders.\n",
      +          "enum": [
      +            "create",
      +            "update",
      +            "delete",
      +            "move"
      +          ],
      +          "type": "string"
      +        },
      +        "payload": {
      +          "description": "The data for the operation. Required for create, update, and move\noperations.\nThe accepted fields depend on the resource type and match the corresponding\ncreate or update endpoint's request body (for example, a channel_episode\ncreate takes the same fields as the Create Channel Episode endpoint,\nincluding channel_id).\n\nCreating a subfolder requires `folder_id` (the parent folder's hashed ID)\nand `name`.\n\nCreating captions requires `media_id` and `caption_file` (the SRT\ncontents as a string; the multipart file upload the Create Captions\nendpoint accepts is not available here) and takes an optional\n`language`, detected from the file when omitted. Updating captions\ntakes `caption_file`; the track's language is fixed by the record.\nCreating captions for a language that already has a track replaces it,\nmatching the Create Captions endpoint.\n\nMoving a media requires `folder_id` (the destination folder's hashed ID)\nand accepts an optional `subfolder_id`, which must belong to that\nfolder. Omit `subfolder_id` to move the media to the folder's root\nlevel.\n\nA `customization_*` payload is a partial update of that concern only:\njust the fields you send are changed, and a field naming another\nconcern's setting fails the action.\n\nA `media` update payload can also carry a `custom_metadata` object\nmapping field keys to the values to set, in the same shapes the Set\nCustom Metadata Field Value endpoint accepts for each field's type. A\n`null` value clears that field; fields the object omits are left\nuntouched. Requires the custom metadata feature on the account, and\neach write is recorded with its actor and source.\n",
      +          "type": "object",
      +          "unevaluatedProperties": true
      +        },
      +        "resource_type": {
      +          "description": "The type of resource to operate on. `folder` means a top-level folder\n(previously called a project); use `subfolder` for a folder nested\ninside one. `captions` operates on a single caption track -- one media\nin one language.\n\nThe `customization_*` types each write one concern of a media's player\ncustomizations and accept `update` only. Their `id` is the media's\nhashed ID, and their payload matches the corresponding Update\nCustomizations endpoint (for example, `customization_appearance` takes\nthe same fields as Update Appearance Customizations). Sending a field\nanother concern owns fails that action rather than writing it, so a\nbatch can never quietly overwrite unrelated player settings.\n",
      +          "enum": [
      +            "media",
      +            "folder",
      +            "subfolder",
      +            "channel",
      +            "channel_episode",
      +            "captions",
      +            "customization_access",
      +            "customization_accessibility",
      +            "customization_appearance",
      +            "customization_chapters",
      +            "customization_engagement",
      +            "customization_lead_capture",
      +            "customization_playback",
      +            "customization_related_media",
      +            "customization_sharing",
      +            "customization_thumbnail"
      +          ],
      +          "type": "string"
      +        }
      +      },
      +      "required": [
      +        "operation",
      +        "resource_type"
      +      ],
      +      "type": "object",
      +      "unevaluatedProperties": false
      +    },
      +    "maxItems": 1000,
      +    "minItems": 1,
      +    "type": "array"
      +  },
      +  "job": {
      +    "description": "One change applied to many records, named by a parent (`scope`) or listed\nexplicitly (`ids`). The server resolves the target and runs one action per\nrecord, so a folder of 400 media takes one job rather than 400 actions.\n\nA `scope` resolves to exactly what the matching list endpoint returns for\nthat parent, including its defaults -- so a `folder` scope on `media` reaches\nmedia in that folder's subfolders, and includes **archived** media.\n\nA job resolves to at most 5000 records. Beyond that it is rejected rather\nthan truncated, so a job never silently acts on part of the set you named --\nnarrow the scope, or send the records as an actions array.\n\nCannot be used with `create`, which has no record to address, and is not\navailable to external contacts.\n",
      +    "properties": {
      +      "ids": {
      +        "description": "The records to apply the change to, named explicitly. Use this instead of\n`scope` when the records do not share a parent -- it is still far cheaper\nthan one action each, since only the ids repeat and the payload is stated\nonce.\n\nGive either `scope` or `ids`, never both.\n",
      +        "items": {
      +          "type": "string"
      +        },
      +        "maxItems": 1000,
      +        "minItems": 1,
      +        "type": "array"
      +      },
      +      "operation": {
      +        "description": "The operation to apply to every matching record. `create` is not\naccepted here.\n",
      +        "enum": [
      +          "update",
      +          "delete",
      +          "move"
      +        ],
      +        "type": "string"
      +      },
      +      "payload": {
      +        "description": "The data applied to every matching record, in the same shape a single\naction's payload takes for this resource type. Required for `update` and\n`move`.\n",
      +        "type": "object",
      +        "unevaluatedProperties": true
      +      },
      +      "resource_type": {
      +        "description": "The type of record to operate on, using the same vocabulary as a single\naction. Which parents are valid depends on it -- see `scope`.\n",
      +        "enum": [
      +          "media",
      +          "folder",
      +          "subfolder",
      +          "channel",
      +          "channel_episode",
      +          "captions",
      +          "customization_access",
      +          "customization_accessibility",
      +          "customization_appearance",
      +          "customization_chapters",
      +          "customization_engagement",
      +          "customization_lead_capture",
      +          "customization_playback",
      +          "customization_related_media",
      +          "customization_sharing",
      +          "customization_thumbnail"
      +        ],
      +        "type": "string"
      +      },
      +      "scope": {
      +        "description": "The parent whose records the job applies to.\n\nWhich parent types are valid depends on the job's `resource_type` and\n`operation`:\n\n- `media` and the `customization_*` types: `account`, `folder`, `subfolder`,\n  `channel`.\n- `captions` with `update` or `delete`, which address a caption track:\n  `account`, `media`, `folder`, `channel`.\n- `channel_episode`: `account`, `channel`, `media`.\n- `subfolder`: `account`, `folder`.\n- `folder` and `channel`: `account`.\n\nAn invalid combination is rejected with the valid parents listed.\n",
      +        "properties": {
      +          "id": {
      +            "description": "The parent's hashed ID. Required for every scope type except `account`.\n",
      +            "type": "string"
      +          },
      +          "type": {
      +            "description": "The kind of parent `id` names. Required, because a hashed ID does not say\nwhat it belongs to -- the same value could name a folder or a channel.\nUse `account` to mean every record the job could reach, with no `id`.\n",
      +            "enum": [
      +              "account",
      +              "folder",
      +              "subfolder",
      +              "channel",
      +              "media"
      +            ],
      +            "type": "string"
      +          }
      +        },
      +        "required": [
      +          "type"
      +        ],
      +        "type": "object",
      +        "unevaluatedProperties": false
      +      }
      +    },
      +    "required": [
      +      "operation",
      +      "resource_type"
      +    ],
      +    "type": "object",
      +    "unevaluatedProperties": false
      +  }
      +}
    • addedInput schema / properties / actions / $ref
      Added value: +"#/$defs/actions"
    • removedInput schema / properties / actions / description
      Removed value: -"An array of actions to process, one per record. Maximum 1000 actions per\nrequest, and the request body must stay under 2 MB -- whichever limit is\nreached first. An oversized body is rejected with a `413` and no action\nin it runs. Each action specifies an operation (create, update, delete,\nor move), a resource type, and the relevant payload or record ID.\n\nUse `job` instead when every record takes the same payload.\n"
    • removedInput schema / properties / actions / items
      Removed value: -{
      -  "description": "A single action within a bulk request.",
      -  "properties": {
      -    "id": {
      -      "description": "The hashed ID of the resource. Required for update, delete, and move\noperations.\n\nFor `captions` this is the caption track's own ID (the `id` field\nreturned by List Captions), not the media's -- a media can have a track\nper language.\n",
      -      "type": "string"
      -    },
      -    "operation": {
      -      "description": "The operation to perform. Media creation is not supported here --\nuploads and URL imports have their own endpoints.\n\n`delete` also soft-deletes media inside a `folder` or `subfolder`. An\naccount owner or manager can restore it from the trash until it purges.\n\n`move` applies to `media` only, one action per media. Each action\ncarries its own destination, so a single request can move media into\nmany different folders.\n",
      -      "enum": [
      -        "create",
      -        "update",
      -        "delete",
      -        "move"
      -      ],
      -      "type": "string"
      -    },
      -    "payload": {
      -      "description": "The data for the operation. Required for create, update, and move\noperations.\nThe accepted fields depend on the resource type and match the corresponding\ncreate or update endpoint's request body (for example, a channel_episode\ncreate takes the same fields as the Create Channel Episode endpoint,\nincluding channel_id).\n\nCreating a subfolder requires `folder_id` (the parent folder's hashed ID)\nand `name`.\n\nCreating captions requires `media_id` and `caption_file` (the SRT\ncontents as a string; the multipart file upload the Create Captions\nendpoint accepts is not available here) and takes an optional\n`language`, detected from the file when omitted. Updating captions\ntakes `caption_file`; the track's language is fixed by the record.\nCreating captions for a language that already has a track replaces it,\nmatching the Create Captions endpoint.\n\nMoving a media requires `folder_id` (the destination folder's hashed ID)\nand accepts an optional `subfolder_id`, which must belong to that\nfolder. Omit `subfolder_id` to move the media to the folder's root\nlevel.\n\nA `customization_*` payload is a partial update of that concern only:\njust the fields you send are changed, and a field naming another\nconcern's setting fails the action.\n\nA `media` update payload can also carry a `custom_metadata` object\nmapping field keys to the values to set, in the same shapes the Set\nCustom Metadata Field Value endpoint accepts for each field's type. A\n`null` value clears that field; fields the object omits are left\nuntouched. Requires the custom metadata feature on the account, and\neach write is recorded with its actor and source.\n",
      -      "type": "object",
      -      "unevaluatedProperties": true
      -    },
      -    "resource_type": {
      -      "description": "The type of resource to operate on. `folder` means a top-level folder\n(previously called a project); use `subfolder` for a folder nested\ninside one. `captions` operates on a single caption track -- one media\nin one language.\n\nThe `customization_*` types each write one concern of a media's player\ncustomizations and accept `update` only. Their `id` is the media's\nhashed ID, and their payload matches the corresponding Update\nCustomizations endpoint (for example, `customization_appearance` takes\nthe same fields as Update Appearance Customizations). Sending a field\nanother concern owns fails that action rather than writing it, so a\nbatch can never quietly overwrite unrelated player settings.\n",
      -      "enum": [
      -        "media",
      -        "folder",
      -        "subfolder",
      -        "channel",
      -        "channel_episode",
      -        "captions",
      -        "customization_access",
      -        "customization_accessibility",
      -        "customization_appearance",
      -        "customization_chapters",
      -        "customization_engagement",
      -        "customization_lead_capture",
      -        "customization_playback",
      -        "customization_related_media",
      -        "customization_sharing",
      -        "customization_thumbnail"
      -      ],
      -      "type": "string"
      -    }
      -  },
      -  "required": [
      -    "operation",
      -    "resource_type"
      -  ],
      -  "type": "object",
      -  "unevaluatedProperties": false
      -}
    • removedInput schema / properties / actions / maxItems
      Removed value: -1000
    • removedInput schema / properties / actions / minItems
      Removed value: -1
    • removedInput schema / properties / actions / type
      Removed value: -"array"
    • changedInput schema / properties / confirm / description
      Previous value: -"Must be true for the specific user-requested write."New value: +"Set true only when the user asked for exactly this action."
    • addedInput schema / properties / job / $ref
      Added value: +"#/$defs/job"
    • removedInput schema / properties / job / description
      Removed value: -"One change applied to many records, named by a parent (`scope`) or listed\nexplicitly (`ids`). The server resolves the target and runs one action per\nrecord, so a folder of 400 media takes one job rather than 400 actions.\n\nA `scope` resolves to exactly what the matching list endpoint returns for\nthat parent, including its defaults -- so a `folder` scope on `media` reaches\nmedia in that folder's subfolders, and includes **archived** media.\n\nA job resolves to at most 5000 records. Beyond that it is rejected rather\nthan truncated, so a job never silently acts on part of the set you named --\nnarrow the scope, or send the records as an actions array.\n\nCannot be used with `create`, which has no record to address, and is not\navailable to external contacts.\n"
    • removedInput schema / properties / job / properties
      Removed value: -{
      -  "ids": {
      -    "description": "The records to apply the change to, named explicitly. Use this instead of\n`scope` when the records do not share a parent -- it is still far cheaper\nthan one action each, since only the ids repeat and the payload is stated\nonce.\n\nGive either `scope` or `ids`, never both.\n",
      -    "items": {
      -      "type": "string"
      -    },
      -    "maxItems": 1000,
      -    "minItems": 1,
      -    "type": "array"
      -  },
      -  "operation": {
      -    "description": "The operation to apply to every matching record. `create` is not\naccepted here.\n",
      -    "enum": [
      -      "update",
      -      "delete",
      -      "move"
      -    ],
      -    "type": "string"
      -  },
      -  "payload": {
      -    "description": "The data applied to every matching record, in the same shape a single\naction's payload takes for this resource type. Required for `update` and\n`move`.\n",
      -    "type": "object",
      -    "unevaluatedProperties": true
      -  },
      -  "resource_type": {
      -    "description": "The type of record to operate on, using the same vocabulary as a single\naction. Which parents are valid depends on it -- see `scope`.\n",
      -    "enum": [
      -      "media",
      -      "folder",
      -      "subfolder",
      -      "channel",
      -      "channel_episode",
      -      "captions",
      -      "customization_access",
      -      "customization_accessibility",
      -      "customization_appearance",
      -      "customization_chapters",
      -      "customization_engagement",
      -      "customization_lead_capture",
      -      "customization_playback",
      -      "customization_related_media",
      -      "customization_sharing",
      -      "customization_thumbnail"
      -    ],
      -    "type": "string"
      -  },
      -  "scope": {
      -    "description": "The parent whose records the job applies to.\n\nWhich parent types are valid depends on the job's `resource_type` and\n`operation`:\n\n- `media` and the `customization_*` types: `account`, `folder`, `subfolder`,\n  `channel`.\n- `captions` with `update` or `delete`, which address a caption track:\n  `account`, `media`, `folder`, `channel`.\n- `channel_episode`: `account`, `channel`, `media`.\n- `subfolder`: `account`, `folder`.\n- `folder` and `channel`: `account`.\n\nAn invalid combination is rejected with the valid parents listed.\n",
      -    "properties": {
      -      "id": {
      -        "description": "The parent's hashed ID. Required for every scope type except `account`.\n",
      -        "type": "string"
      -      },
      -      "type": {
      -        "description": "The kind of parent `id` names. Required, because a hashed ID does not say\nwhat it belongs to -- the same value could name a folder or a channel.\nUse `account` to mean every record the job could reach, with no `id`.\n",
      -        "enum": [
      -          "account",
      -          "folder",
      -          "subfolder",
      -          "channel",
      -          "media"
      -        ],
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "type"
      -    ],
      -    "type": "object",
      -    "unevaluatedProperties": false
      -  }
      -}
    • removedInput schema / properties / job / required
      Removed value: -[
      -  "operation",
      -  "resource_type"
      -]
    • removedInput schema / properties / job / type
      Removed value: -"object"
    • removedInput schema / properties / job / unevaluatedProperties
      Removed value: -false
    • addedInput schema / properties / payload / properties / actions / $ref
      Added value: +"#/$defs/actions"
    • removedInput schema / properties / payload / properties / actions / description
      Removed value: -"An array of actions to process, one per record. Maximum 1000 actions per\nrequest, and the request body must stay under 2 MB -- whichever limit is\nreached first. An oversized body is rejected with a `413` and no action\nin it runs. Each action specifies an operation (create, update, delete,\nor move), a resource type, and the relevant payload or record ID.\n\nUse `job` instead when every record takes the same payload.\n"
    • removedInput schema / properties / payload / properties / actions / items
      Removed value: -{
      -  "description": "A single action within a bulk request.",
      -  "properties": {
      -    "id": {
      -      "description": "The hashed ID of the resource. Required for update, delete, and move\noperations.\n\nFor `captions` this is the caption track's own ID (the `id` field\nreturned by List Captions), not the media's -- a media can have a track\nper language.\n",
      -      "type": "string"
      -    },
      -    "operation": {
      -      "description": "The operation to perform. Media creation is not supported here --\nuploads and URL imports have their own endpoints.\n\n`delete` also soft-deletes media inside a `folder` or `subfolder`. An\naccount owner or manager can restore it from the trash until it purges.\n\n`move` applies to `media` only, one action per media. Each action\ncarries its own destination, so a single request can move media into\nmany different folders.\n",
      -      "enum": [
      -        "create",
      -        "update",
      -        "delete",
      -        "move"
      -      ],
      -      "type": "string"
      -    },
      -    "payload": {
      -      "description": "The data for the operation. Required for create, update, and move\noperations.\nThe accepted fields depend on the resource type and match the corresponding\ncreate or update endpoint's request body (for example, a channel_episode\ncreate takes the same fields as the Create Channel Episode endpoint,\nincluding channel_id).\n\nCreating a subfolder requires `folder_id` (the parent folder's hashed ID)\nand `name`.\n\nCreating captions requires `media_id` and `caption_file` (the SRT\ncontents as a string; the multipart file upload the Create Captions\nendpoint accepts is not available here) and takes an optional\n`language`, detected from the file when omitted. Updating captions\ntakes `caption_file`; the track's language is fixed by the record.\nCreating captions for a language that already has a track replaces it,\nmatching the Create Captions endpoint.\n\nMoving a media requires `folder_id` (the destination folder's hashed ID)\nand accepts an optional `subfolder_id`, which must belong to that\nfolder. Omit `subfolder_id` to move the media to the folder's root\nlevel.\n\nA `customization_*` payload is a partial update of that concern only:\njust the fields you send are changed, and a field naming another\nconcern's setting fails the action.\n\nA `media` update payload can also carry a `custom_metadata` object\nmapping field keys to the values to set, in the same shapes the Set\nCustom Metadata Field Value endpoint accepts for each field's type. A\n`null` value clears that field; fields the object omits are left\nuntouched. Requires the custom metadata feature on the account, and\neach write is recorded with its actor and source.\n",
      -      "type": "object",
      -      "unevaluatedProperties": true
      -    },
      -    "resource_type": {
      -      "description": "The type of resource to operate on. `folder` means a top-level folder\n(previously called a project); use `subfolder` for a folder nested\ninside one. `captions` operates on a single caption track -- one media\nin one language.\n\nThe `customization_*` types each write one concern of a media's player\ncustomizations and accept `update` only. Their `id` is the media's\nhashed ID, and their payload matches the corresponding Update\nCustomizations endpoint (for example, `customization_appearance` takes\nthe same fields as Update Appearance Customizations). Sending a field\nanother concern owns fails that action rather than writing it, so a\nbatch can never quietly overwrite unrelated player settings.\n",
      -      "enum": [
      -        "media",
      -        "folder",
      -        "subfolder",
      -        "channel",
      -        "channel_episode",
      -        "captions",
      -        "customization_access",
      -        "customization_accessibility",
      -        "customization_appearance",
      -        "customization_chapters",
      -        "customization_engagement",
      -        "customization_lead_capture",
      -        "customization_playback",
      -        "customization_related_media",
      -        "customization_sharing",
      -        "customization_thumbnail"
      -      ],
      -      "type": "string"
      -    }
      -  },
      -  "required": [
      -    "operation",
      -    "resource_type"
      -  ],
      -  "type": "object",
      -  "unevaluatedProperties": false
      -}
    • removedInput schema / properties / payload / properties / actions / maxItems
      Removed value: -1000
    • removedInput schema / properties / payload / properties / actions / minItems
      Removed value: -1
    • removedInput schema / properties / payload / properties / actions / type
      Removed value: -"array"
    • addedInput schema / properties / payload / properties / job / $ref
      Added value: +"#/$defs/job"
    • removedInput schema / properties / payload / properties / job / description
      Removed value: -"One change applied to many records, named by a parent (`scope`) or listed\nexplicitly (`ids`). The server resolves the target and runs one action per\nrecord, so a folder of 400 media takes one job rather than 400 actions.\n\nA `scope` resolves to exactly what the matching list endpoint returns for\nthat parent, including its defaults -- so a `folder` scope on `media` reaches\nmedia in that folder's subfolders, and includes **archived** media.\n\nA job resolves to at most 5000 records. Beyond that it is rejected rather\nthan truncated, so a job never silently acts on part of the set you named --\nnarrow the scope, or send the records as an actions array.\n\nCannot be used with `create`, which has no record to address, and is not\navailable to external contacts.\n"
    • removedInput schema / properties / payload / properties / job / properties
      Removed value: -{
      -  "ids": {
      -    "description": "The records to apply the change to, named explicitly. Use this instead of\n`scope` when the records do not share a parent -- it is still far cheaper\nthan one action each, since only the ids repeat and the payload is stated\nonce.\n\nGive either `scope` or `ids`, never both.\n",
      -    "items": {
      -      "type": "string"
      -    },
      -    "maxItems": 1000,
      -    "minItems": 1,
      -    "type": "array"
      -  },
      -  "operation": {
      -    "description": "The operation to apply to every matching record. `create` is not\naccepted here.\n",
      -    "enum": [
      -      "update",
      -      "delete",
      -      "move"
      -    ],
      -    "type": "string"
      -  },
      -  "payload": {
      -    "description": "The data applied to every matching record, in the same shape a single\naction's payload takes for this resource type. Required for `update` and\n`move`.\n",
      -    "type": "object",
      -    "unevaluatedProperties": true
      -  },
      -  "resource_type": {
      -    "description": "The type of record to operate on, using the same vocabulary as a single\naction. Which parents are valid depends on it -- see `scope`.\n",
      -    "enum": [
      -      "media",
      -      "folder",
      -      "subfolder",
      -      "channel",
      -      "channel_episode",
      -      "captions",
      -      "customization_access",
      -      "customization_accessibility",
      -      "customization_appearance",
      -      "customization_chapters",
      -      "customization_engagement",
      -      "customization_lead_capture",
      -      "customization_playback",
      -      "customization_related_media",
      -      "customization_sharing",
      -      "customization_thumbnail"
      -    ],
      -    "type": "string"
      -  },
      -  "scope": {
      -    "description": "The parent whose records the job applies to.\n\nWhich parent types are valid depends on the job's `resource_type` and\n`operation`:\n\n- `media` and the `customization_*` types: `account`, `folder`, `subfolder`,\n  `channel`.\n- `captions` with `update` or `delete`, which address a caption track:\n  `account`, `media`, `folder`, `channel`.\n- `channel_episode`: `account`, `channel`, `media`.\n- `subfolder`: `account`, `folder`.\n- `folder` and `channel`: `account`.\n\nAn invalid combination is rejected with the valid parents listed.\n",
      -    "properties": {
      -      "id": {
      -        "description": "The parent's hashed ID. Required for every scope type except `account`.\n",
      -        "type": "string"
      -      },
      -      "type": {
      -        "description": "The kind of parent `id` names. Required, because a hashed ID does not say\nwhat it belongs to -- the same value could name a folder or a channel.\nUse `account` to mean every record the job could reach, with no `id`.\n",
      -        "enum": [
      -          "account",
      -          "folder",
      -          "subfolder",
      -          "channel",
      -          "media"
      -        ],
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "type"
      -    ],
      -    "type": "object",
      -    "unevaluatedProperties": false
      -  }
      -}
    • removedInput schema / properties / payload / properties / job / required
      Removed value: -[
      -  "operation",
      -  "resource_type"
      -]
    • removedInput schema / properties / payload / properties / job / type
      Removed value: -"object"
    • removedInput schema / properties / payload / properties / job / unevaluatedProperties
      Removed value: -false
  2. First observedv2.0.0

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Far exceeds the annotation baseline (destructive/openWorld/non-idempotent). It discloses async processing, per-action independent authorization, fail-per-action semantics, soft-delete of nested media, the 5000-record cap with rejection-not-truncation, body-size limits/413, and the confirm=true requirement.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose and async/return behavior are front-loaded, and each paragraph covers a distinct resource-type concern. It is long, but the complexity of a 1000-action, 16-resource-type endpoint justifies most of it; a few clauses could be tightened.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, yet the description explains the return value (background job status whose Show endpoint – get_job_status – reports aggregate and per-action results with hashed IDs). For a complex async mutation tool, nothing an agent needs to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 67%, but the description materially adds meaning: it enumerates supported resource types, explains scope-vs-ids exclusivity, the customization_* partial-update constraint, custom_metadata null-clears semantics, and the captions SRT-inline behavior. Adds value beyond the already-detailed schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (Submits a batch), resource (create/update/delete/move actions), and scope (up to 1000, processed asynchronously). It clearly differentiates from bulk_tag, bulk_copy_media, and the single-record mutation siblings by describing itself as the general batch-action surface.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly routes alternatives: 'use the Delete Subfolder endpoint' to keep media, and 'purchasing captions... has its own endpoint', plus the schema note to prefer `job` when every record shares a payload. It does not, however, directly compare against sibling bulk tools like bulk_tag or bulk_copy_media.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Deploy Server

Other Tools