---
title: "Bulk-submit a whole bucket as N auto-chunked, auto-queued batches"
method: POST
path: "/v1/buckets/{bucket_identifier}/batches/bulk-submit"
tags: ["Bucket Batches"]
---

# Bulk-submit a whole bucket as N auto-chunked, auto-queued batches

`POST /v1/buckets/{bucket_identifier}/batches/bulk-submit`

## Request

- Base URL: `https://api.mixpeek.com`
- URL: `https://api.mixpeek.com/v1/buckets/{bucket_identifier}/batches/bulk-submit`
- Auth: HTTP bearer and API key in header `X-Namespace`

One call that streams the bucket's objects (paginated, de-duplicated), chunks them server-side into `chunk_size`-object batches, and submits each (accept-and-queue). Replaces the client-side chunk loop + cursor pacing — no 409 cursor-overlap, no 5k count-timeout, no manual 429 handling. Poll the returned batch ids / `batch_group_id` for QUEUED -> PROCESSING.

## Path parameters

- `bucket_identifier` string, required: The bucket to ingest.

## Request body

- BulkSubmitBatchesRequest: Submit a WHOLE bucket as N auto-chunked, auto-queued batches in one call. The server streams the bucket's objects (paginated), de-duplicates them, chunks them into ``chunk_size``-object batches, and submits each — so the client makes ONE call instead of a paced chunk-loop. This kills the client-side cursor-overlap (409 storm), the 5k object-count timeout, and the no-whole-bucket frustration at once (phase 4). Each batch is accepted and QUEUED (accept-and-queue admission); poll the returned ``batch_group_id`` / batch ids for QUEUED -> PROCESSING.
  - `collection_ids` string[], nullable: Collections to process. Omit to auto-discover all collections sourced from this bucket (plus downstream dependencies).
  - `filters` LogicalOperatorInput: Represents a logical operation (AND, OR, NOT) on filter conditions. Allows nesting with a defined depth limit. Also supports shorthand syntax where field names can be passed directly as key-value pairs for equality filtering (e.g., {"metadata.title": "value"}).
    - `AND` union[], nullable: Logical AND operation - all conditions must be true
      - union
        - LogicalOperatorInput (recursive)
        - FilterCondition: Represents a single filter condition. Attributes: field: The field to filter on operator: The comparison operator value: The value to compare against
          - `field` string, required: Field name to filter on
          - `operator` 'eq' | 'ne' | 'gt' | 'lt' | 'gte' | 'lte' | 'in' | 'nin' | 'contains' | 'starts_with' | 'ends_with' | 'regex' | 'exists' | 'is_null' | 'text' | 'phrase' | 'words' | 'geo_radius' | 'geo_bounding_box' | 'geo_polygon': Supported filter operators across database implementations. `text` is a case-insensitive substring match on the MVS vector store, in the in-memory evaluator and in the collections list filter; it does not tokenize or rank. On the Mongo query translator it becomes a Mongo `$text` search, which needs a collection text index and searches every indexed field. For whole-word matching on one field use `words`: every word of the value must appear as a whole word, compared on its English stem.
          - `value` union, required: Value to compare against
            - DynamicValue: A value that should be dynamically resolved from the query request.
              - …
            - unknown
    - `OR` union[], nullable: Logical OR operation - at least one condition must be true
      - union
        - LogicalOperatorInput (recursive)
        - FilterCondition: Represents a single filter condition. Attributes: field: The field to filter on operator: The comparison operator value: The value to compare against
          - `field` string, required: Field name to filter on
          - `operator` 'eq' | 'ne' | 'gt' | 'lt' | 'gte' | 'lte' | 'in' | 'nin' | 'contains' | 'starts_with' | 'ends_with' | 'regex' | 'exists' | 'is_null' | 'text' | 'phrase' | 'words' | 'geo_radius' | 'geo_bounding_box' | 'geo_polygon': Supported filter operators across database implementations. `text` is a case-insensitive substring match on the MVS vector store, in the in-memory evaluator and in the collections list filter; it does not tokenize or rank. On the Mongo query translator it becomes a Mongo `$text` search, which needs a collection text index and searches every indexed field. For whole-word matching on one field use `words`: every word of the value must appear as a whole word, compared on its English stem.
          - `value` union, required: Value to compare against
            - DynamicValue: A value that should be dynamically resolved from the query request.
              - …
            - unknown
    - `NOT` union[], nullable: Logical NOT operation - all conditions must be false
      - union
        - LogicalOperatorInput (recursive)
        - FilterCondition: Represents a single filter condition. Attributes: field: The field to filter on operator: The comparison operator value: The value to compare against
          - `field` string, required: Field name to filter on
          - `operator` 'eq' | 'ne' | 'gt' | 'lt' | 'gte' | 'lte' | 'in' | 'nin' | 'contains' | 'starts_with' | 'ends_with' | 'regex' | 'exists' | 'is_null' | 'text' | 'phrase' | 'words' | 'geo_radius' | 'geo_bounding_box' | 'geo_polygon': Supported filter operators across database implementations. `text` is a case-insensitive substring match on the MVS vector store, in the in-memory evaluator and in the collections list filter; it does not tokenize or rank. On the Mongo query translator it becomes a Mongo `$text` search, which needs a collection text index and searches every indexed field. For whole-word matching on one field use `words`: every word of the value must appear as a whole word, compared on its English stem.
          - `value` union, required: Value to compare against
            - DynamicValue: A value that should be dynamically resolved from the query request.
              - …
            - unknown
    - `case_sensitive` boolean, nullable: Whether to perform case-sensitive matching
  - `chunk_size` integer: Objects per batch. Clamped down to your tier's max_batch_size. Default 1000 — a good balance of parallelism and per-batch overhead. Sizing model: each batch runs as its own job whose workers scale at ~1 CPU worker per 500 objects up to a per-job worker ceiling, so 16k-20k objects saturates one job's parallelism — for large corpora (100k+ objects) prefer chunk_size 20000. Larger chunks don't run faster; they only raise the cost of a mid-run failure (progress is still resumable per-object via the processing ledger). Much smaller chunks pay one cluster cold-start each and queue behind your tier's concurrent-batch limit. Full guide: docs.mixpeek.com/operations/batch-ingestion-at-scale.
  - `dedup_strategy` 'skip' | 'replace' | 'force': Controls how duplicate objects are handled during batch processing. Dedup is scoped to (bucket_id, collection_id): an object is considered a duplicate if the target collection already has documents produced from the same source object in any prior batch.
  - `max_objects` integer, nullable: Optional cap on total objects streamed (safety bound for very large buckets). Omit to submit the whole bucket.

## Response `200`

Successful Response

- BulkSubmitBatchesResponse: Result of a whole-bucket bulk submit.
  - `batch_group_id` string, required: Correlates all batches created by this call.
  - `total_objects` integer, required: Distinct objects streamed (post-dedup).
  - `total_batches` integer, required: Batches created.
  - `submitted` integer, required: Batches accepted/queued successfully.
  - `failed` integer, required: Batches that failed admission/submit.
  - `chunk_size` integer, required: Effective per-batch object count used.
  - `batches` BulkSubmittedBatch[], required: Per-batch results with status + queue position.
    - `batch_id` string, required
    - `status` string, required
    - `object_count` integer, required
    - `queue_position` integer, nullable
    - `error` string, nullable
    - `estimate` BatchCostEstimate: Dry-run estimate of what submitting a DRAFT batch will cost + re-pay.
      - `batch_id` string, required
      - `collection_ids` string[]
      - `dedup_strategy` string: skip | replace | force — controls re-extraction
      - `object_count` integer: Objects this batch will process
      - `already_extracted_count` integer: Objects in this batch already extracted before (re-paid under force/replace)
      - `estimated_credits` integer: Credits submitting this batch will consume (same calc as submit)
      - `estimated_usd` number, nullable: Dollar cost of this batch under live v2 pricing (file type × amount × search-by features). Credits are milli-dollars of this value.
      - `estimated_repay_credits` integer: ~credits re-paying already-extracted objects (force/replace only; linear approx)
      - `features` string[]: What this batch searches by (dimension 3 of pricing): feature keys billed per file type; custom plugins as 'custom:<name>'.
      - `extractors` string[]: Internal implementation of `features` — prefer rendering `features`; extractor names are the deeper disclosure layer.
      - `content_summary` object, nullable: Dimensions 1+2 of pricing: file types and how much of each (counts, video minutes, pages, tokens…)
      - `documents_to_remove` integer, nullable: OPTIONAL. For dedup_strategy replace: the documents the batch's objects have now in its collections. A replace removes each of these that its re-run does not overwrite in place, after the new documents are written, so this is the most it removes. Absent for skip and force.
      - `warnings` string[]

## Other responses

- `400`: Bad Request
- `401`: Unauthorized
- `403`: Forbidden
- `404`: Not Found
- `422`: Unprocessable Entity
- `429`: Too Many Requests
- `500`: Internal Server Error
- `503`: Service Unavailable

## Changes

- **2026-10-09** `61a175e8eb9a`: 1 warning, 5 info
  - removed the optional property `detail` from the response with the `422` status
  - added the non-success response with the status `429`
  - added the non-success response with the status `503`
  - added the optional property `success` to the response with the `422` status
  - …2 more
- **2026-10-06** `b75474e978ff`: 1 info
  - added the optional property `batches/items/estimate` to the response with the `200` status
- **2026-09-26** `5231c1d891e8`: 3 info
  - added the new `words` enum value to the request property `filters/anyOf[subschema #1: LogicalOperator]/AND/anyOf[subschema #1]/items/anyOf[subschema #2: FilterCondition]/operator`
  - added the new `words` enum value to the request property `filters/anyOf[subschema #1: LogicalOperator]/NOT/anyOf[subschema #1]/items/anyOf[subschema #2: FilterCondition]/operator`
  - added the new `words` enum value to the request property `filters/anyOf[subschema #1: LogicalOperator]/OR/anyOf[subschema #1]/items/anyOf[subschema #2: FilterCondition]/operator`
- **2026-08-09** `5d4c905106b4`: 1 info
  - the endpoint scheme security `BearerAuth AND NamespaceHeader` was added to the API
- …earlier changes not shown

[Operation history](https://skmtc.dev/mixpeek/apis/mixpeek-api/changes/v1/buckets/:bucket_identifier/batches/bulk-submit/post.md)

---

[API](https://skmtc.dev/mixpeek/apis/mixpeek-api.md) - [All operations](https://skmtc.dev/mixpeek/apis/mixpeek-api/llms.txt) - [OpenAPI document](https://skmtc.dev/mixpeek/apis/mixpeek-api/revisions/790bc16455f6?raw)
