> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hanji.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Create a batch

> Submit uploaded files as one batch job. Returns immediately with `status: "pending"`; poll `GET /v1/batches/{batch_id}` for per-item progress. Pass an `Idempotency-Key` header to make retries safe: the same key within 3 days returns the same batch instead of creating a duplicate.



## OpenAPI

````yaml /openapi.json post /v1/batches
openapi: 3.1.0
info:
  title: Hanji
  summary: Parse documents into structured data. Text, tables, and figures in one call.
  version: 0.1.0
servers:
  - url: https://api.hanji.dev
    description: production
security:
  - APIKeyHeader: []
paths:
  /v1/batches:
    post:
      tags:
        - v1
        - async-batch
      summary: Create a batch
      description: >-
        Submit uploaded files as one batch job. Returns immediately with
        `status: "pending"`; poll `GET /v1/batches/{batch_id}` for per-item
        progress. Pass an `Idempotency-Key` header to make retries safe: the
        same key within 3 days returns the same batch instead of creating a
        duplicate.
      operationId: create_batch_v1
      parameters:
        - name: Idempotency-Key
          in: header
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            title: Idempotency-Key
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateBatchRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BatchResource'
        '402':
          description: Quota exceeded.
        '404':
          description: >-
            One or more `file_id`s don't exist for this account (or their 3-day
            TTL lapsed).
          content:
            application/json:
              example:
                error: file_not_found
                file_ids:
                  - file_abc123
        '409':
          description: >-
            One or more files have no bytes in storage: the upload never
            completed or expired. A *finished* upload does not 409.
          content:
            application/json:
              example:
                error: file_not_uploaded
                file_ids:
                  - file_abc123
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      security:
        - APIKeyHeader: []
components:
  schemas:
    CreateBatchRequest:
      properties:
        source:
          oneOf:
            - $ref: '#/components/schemas/FilesSource'
            - $ref: '#/components/schemas/UrlSource'
          title: Source
          description: >-
            The documents to process: {"type": "files", "file_ids": [...]} for
            previously-uploaded files, or {"type": "urls", "urls": [...]} to
            have us fetch each URL directly (no upload step; source bytes never
            written to our storage).
          discriminator:
            propertyName: type
            mapping:
              files:
                $ref: '#/components/schemas/FilesSource'
              urls:
                $ref: '#/components/schemas/UrlSource'
        engine:
          anyOf:
            - type: string
              maxLength: 64
            - type: 'null'
          title: Engine
          description: >-
            Reserved for future engine selection. Leave unset; only the default
            engine is accepted today.
        extract_text:
          type: boolean
          title: Extract Text
          description: >-
            Include text chunks in each item's result. Set false to skip text
            spans in every item.
          default: true
        extract_images:
          type: boolean
          title: Extract Images
          description: >-
            Include figure (image) chunks in each item's result. Set false to
            skip figure extraction in every item.
          default: true
        ocr:
          type: string
          enum:
            - auto
            - never
            - force
          title: Ocr
          description: >-
            Deprecated. Accepted for backward compatibility but currently has no
            effect.
          default: auto
        table_output_format:
          type: string
          enum:
            - markdown
            - cell_grid
            - html
          title: Table Output Format
          description: >-
            How table chunks are structured in each item's result. 'markdown'
            (default) keeps the existing markdown-derived cells; 'cell_grid'
            returns true per-cell bounding boxes on table chunks.
          default: markdown
        chunking:
          type: string
          enum:
            - none
            - semantic
          title: Chunking
          description: >-
            'none' (default): item results unchanged. 'semantic': each item's
            result additionally carries `segments` — elements grouped toward
            chunk_size characters at semantic/structural boundaries.
          default: none
        chunk_size:
          type: integer
          title: Chunk Size
          description: >-
            Target segment size in characters. Segments land in a +/-25% band
            around this target. Only meaningful when chunking is enabled;
            validated (200-8000) only in that case and ignored otherwise.
          default: 1000
        metadata:
          anyOf:
            - additionalProperties: true
              type: object
            - type: 'null'
          title: Metadata
          description: >-
            Arbitrary JSON stored with the batch and echoed back on every poll,
            in the batch list, and in webhook event bodies. Put your own run
            ids, tenant ids, or job references here. It never affects
            processing. Maximum 16 KB serialized.
        webhook:
          anyOf:
            - $ref: '#/components/schemas/WebhookConfig'
            - type: 'null'
          description: >-
            Optional completion webhook for this batch. Omitted means no webhook
            fires. `{"mode": "svix"}` delivers a signed `batch.update` event to
            your registered endpoints when the batch reaches a terminal status;
            `{"mode": "direct", "url": ...}` sends an unsigned event to the
            given HTTPS URL (prototyping).
      type: object
      required:
        - source
      title: CreateBatchRequest
    BatchResource:
      properties:
        object:
          type: string
          title: Object
          default: batch
        id:
          type: string
          title: Id
        status:
          type: string
          title: Status
        counts:
          $ref: '#/components/schemas/BatchCounts'
        total_items:
          type: integer
          title: Total Items
        engine:
          anyOf:
            - type: string
            - type: 'null'
          title: Engine
        options:
          additionalProperties: true
          type: object
          title: Options
        metadata:
          anyOf:
            - additionalProperties: true
              type: object
            - type: 'null'
          title: Metadata
        created_at:
          type: string
          title: Created At
        started_at:
          anyOf:
            - type: string
            - type: 'null'
          title: Started At
        completed_at:
          anyOf:
            - type: string
            - type: 'null'
          title: Completed At
        expires_at:
          type: string
          title: Expires At
      type: object
      required:
        - id
        - status
        - counts
        - total_items
        - engine
        - options
        - created_at
        - expires_at
      title: BatchResource
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          type: array
          title: Detail
      type: object
      title: HTTPValidationError
    FilesSource:
      properties:
        type:
          type: string
          const: files
          title: Type
          default: files
        file_ids:
          items:
            type: string
          type: array
          maxItems: 10000
          minItems: 1
          title: File Ids
          description: >-
            Uploaded file ids (from POST /v1/files) to process, 1-10,000 per
            batch.
      type: object
      required:
        - file_ids
      title: FilesSource
    UrlSource:
      properties:
        type:
          type: string
          const: urls
          title: Type
          default: urls
        urls:
          items:
            type: string
          type: array
          maxItems: 100
          minItems: 1
          title: Urls
          description: >-
            Public or presigned HTTP(S) URLs to fetch and process, 1-100 per
            batch. Each URL becomes one item; we fetch it when that item starts
            processing, not when you submit the batch — a slow or large download
            doesn't block this request.
      type: object
      required:
        - urls
      title: UrlSource
      description: |-
        Public or presigned URLs — no upload step. Source bytes are never
        written to our storage; only the extraction result is. Presigned URLs
        work the same as public ones — pass the full URL through unmodified,
        including its signature query string.
    WebhookConfig:
      properties:
        mode:
          type: string
          enum:
            - svix
            - registered
            - direct
            - disabled
          title: Mode
          description: >-
            "svix": signed delivery to your registered endpoints. "direct":
            unsigned delivery to `url` (prototyping). "disabled": suppress for
            this batch (same as omitting `webhook`).
        url:
          anyOf:
            - type: string
              maxLength: 2048
            - type: 'null'
          title: Url
          description: >-
            Destination URL. Required (HTTPS, public hostname) iff mode is
            "direct".
      type: object
      required:
        - mode
      title: WebhookConfig
      description: |-
        Per-batch webhook opt-in (plan 083 §3.3). Shaped like Reducto's
        `async.webhook` so a ported request body maps directly. `registered` is
        an accepted alias of `svix`; only `svix` is documented.
    BatchCounts:
      properties:
        pending:
          type: integer
          title: Pending
          default: 0
        running:
          type: integer
          title: Running
          default: 0
        succeeded:
          type: integer
          title: Succeeded
          default: 0
        failed:
          type: integer
          title: Failed
          default: 0
        cancelled:
          type: integer
          title: Cancelled
          default: 0
      type: object
      title: BatchCounts
    ValidationError:
      properties:
        loc:
          items:
            anyOf:
              - type: string
              - type: integer
          type: array
          title: Location
        msg:
          type: string
          title: Message
        type:
          type: string
          title: Error Type
        input:
          title: Input
        ctx:
          type: object
          title: Context
      type: object
      required:
        - loc
        - msg
        - type
      title: ValidationError
  securitySchemes:
    APIKeyHeader:
      type: apiKey
      in: header
      name: X-API-KEY

````