---
title: "Start bulk deletion of local file groups"
method: POST
path: "/local-file-groups/bulk-deletions"
tags: ["local-file-groups"]
---

# Start bulk deletion of local file groups

`POST /local-file-groups/bulk-deletions`

## Request

- Base URL: `https://developer.qaip.com/api/v1`
- URL: `https://developer.qaip.com/api/v1/local-file-groups/bulk-deletions`
- Auth: API key in header `x-api-key`

Initiates a single asynchronous job that deletes many local file groups at once. Deleting groups one at a time issues 12 serial Iceberg commits per group, which does not scale past a few groups per minute; this endpoint collapses them into one commit per table.

Source group IDs that do not exist or belong to another user are rejected individually and reported in `rejected`; the remaining IDs still start. When nothing is accepted no job is started and `id` is absent.

Whether a group currently has another job in flight (an ingestion, a single deletion or a chunk deletion) is NOT decided here: the job takes the same per-group lock those jobs use and skips any group whose lock is held. Such groups count toward `accepted_count` but come back untouched in `remaining_source_group_ids` of the final status, so resubmit that list once the other job has finished.

The response returns a bulk deletion job id; poll GET /local-file-groups/bulk-deletions/{bulk\_deletion\_id} to check the job status.

Required scope: \`ingestion:manage\`

## Request body

- StartBulkDeletionRequest
  - `source_group_ids` string[], required: IDs of the local file groups to delete. Duplicates are ignored. IDs that cannot be accepted are reported in the response rather than failing the whole request.

## Response `200`

Bulk deletion job successfully started

- StartBulkDeletionResponse
  - `id` string: The id of the started bulk deletion job, used to poll its status. Absent when accepted_count is 0, in which case no job was started.
  - `accepted_count` integer, required: Number of source groups handed to the job. The job may still skip some of them (another job holds the group's lock); the authoritative outcome is the status's `remaining_source_group_ids`.
  - `rejected` BulkDeletionRejection[], required: IDs that were not accepted, with the reason for each
    - `source_group_id` string, required: The ID that was not accepted
    - `reason` 'not_found', required: Why the ID was not accepted. `not_found`: absent or owned by another user. Groups with another job in flight are not rejected here; they are skipped by the job and reported in the status's `remaining_source_group_ids`.

## Other responses

- `400`: Bad Request
- `401`: Unauthorized
- `500`: Internal Server Error
- `502`: The application proxy could not obtain an upstream response before forwarding response headers. The error code is unavailable and retryable is false: upstream side effects may have completed, so a 502 alone does not make retrying safe. Check the operation's idempotency and recovery contract before retrying. A failure after streaming has started instead aborts the stream without appending this JSON body. CDN or load-balancer generated errors may have a different body and are not described by this response.

## Changes

- **2026-10-10** `2489c6f1a9d8`: 13 info
  - added the non-success response with the status `502`
  - added the optional property `error/code` to the response with the `400` status
  - added the optional property `error/code` to the response with the `401` status
  - added the optional property `error/code` to the response with the `500` status
  - …9 more
- **2026-09-11** `0375753f8ee3`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/qlonolink/apis/qaip-apis/changes/local-file-groups/bulk-deletions/post.md)

---

[API](https://skmtc.dev/qlonolink/apis/qaip-apis.md) - [All operations](https://skmtc.dev/qlonolink/apis/qaip-apis/llms.txt) - [OpenAPI document](https://skmtc.dev/qlonolink/apis/qaip-apis/revisions/2489c6f1a9d8?raw)
