# Dispatch one durable Modal upload publication

`POST /v1/datasets/upload/publication`

Persist one complete tree and return immediately after worker dispatch.

- Base URL: `https://junction-api.qualiastudios.dev`
- Authentication: an API key in the `X-API-Key` header, or `Authorization: Bearer …`

## Parameters

- `x-qualia-upload-session` (header, string | null (uuid)): The transfer heartbeat's session_id this tree moved under. A fresh publication under a session the user cancelled is refused. A header rather than a body field, so a newer SDK still passes an older gateway's strict body.

## Request body

Required: `application/json` `BeginUploadPublicationBody`

## Responses

- `200` Successful Response: `application/json` `any`
- `401` Invalid or missing API key: `application/json` `ErrorResponse`
- `422` Validation Error: `application/json` `HTTPValidationError`

## Schemas

```yaml
BeginUploadPublicationBody:
  properties:
    operation_id:
      type: string
      format: uuid
    repo_id:
      type: string
      format: uuid
    name:
      type: string
    kind:
      type: string
      enum:
        - dataset
        - content
      default: dataset
    source_format:
      nullable: true
      type: string
      enum:
        - lerobot_v2_1
        - lerobot_v3
        - mcap_ros2
    expected:
      nullable: true
      allOf:
        - $ref: "#/components/schemas/ExpectedPublicationHead"
    uploads:
      items:
        $ref: "#/components/schemas/StagedUploadBody"
      type: array
    manifests:
      items:
        $ref: "#/components/schemas/UploadVerificationManifestBody"
      type: array
    existing_entries:
      items:
        $ref: "#/components/schemas/ExistingUploadPublicationEntryBody"
      type: array
  additionalProperties: false
  type: object
  required:
    - operation_id
    - repo_id
    - name
    - uploads
    - manifests
    - existing_entries
  title: BeginUploadPublicationBody
ExpectedPublicationHead:
  properties:
    generation:
      type: integer
      exclusiveMinimum: 0
    git_hash_algorithm:
      type: string
      enum:
        - sha1
        - sha256
    git_oid:
      type: string
      pattern: ^(?:[0-9a-f]{40}|[0-9a-f]{64})$
    commit_id:
      type: string
      format: uuid
    pack_digest:
      type: string
      pattern: ^[0-9a-f]{64}$
  additionalProperties: false
  type: object
  required:
    - generation
    - git_hash_algorithm
    - git_oid
    - commit_id
    - pack_digest
  title: ExpectedPublicationHead
StagedUploadBody:
  properties:
    staging_id:
      type: string
      pattern: ^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$
    blob_id:
      type: string
      pattern: ^[0-9a-f]{64}$
    content_length:
      type: integer
      minimum: 1
  additionalProperties: false
  type: object
  required:
    - staging_id
    - blob_id
    - content_length
  title: StagedUploadBody
UploadVerificationManifestBody:
  properties:
    file_format:
      type: string
      default: generic
    terms:
      items:
        $ref: "#/components/schemas/ManifestTermBody"
      type: array
      minItems: 1
    expected_raw_blake3:
      type: string
      pattern: ^[0-9a-f]{64}$
    expected_raw_sha256:
      type: string
      pattern: ^(?:|[0-9a-f]{64})$
      default: ""
    path:
      type: string
      maxLength: 4096
      minLength: 1
    mode:
      type: integer
      enum:
        - 33188
        - 33261
    expected_manifest_id:
      type: string
      pattern: ^(?:|[0-9a-f]{64})$
      default: ""
  additionalProperties: false
  type: object
  required:
    - terms
    - expected_raw_blake3
    - path
    - mode
  title: UploadVerificationManifestBody
ManifestTermBody:
  properties:
    blob_id:
      type: string
      pattern: ^[0-9a-f]{64}$
    offset_in_blob:
      type: integer
      minimum: 0
    length:
      type: integer
      minimum: 1
  additionalProperties: false
  type: object
  required:
    - blob_id
    - offset_in_blob
    - length
  title: ManifestTermBody
  description: |-
    One contiguous run of chunks inside one blob, named as a byte range.

    The blob seal proves ``offset_in_blob`` is a dense prefix sum of length over
    the directory ordinal, so a range of ordinals is exactly one range of bytes
    and the two spellings carry the same fact.
ExistingUploadPublicationEntryBody:
  properties:
    manifest_id:
      type: string
      pattern: ^[0-9a-f]{64}$
    path:
      type: string
      maxLength: 4096
      minLength: 1
    mode:
      type: integer
      enum:
        - 33188
        - 33261
  additionalProperties: false
  type: object
  required:
    - manifest_id
    - path
    - mode
  title: ExistingUploadPublicationEntryBody
ErrorResponse:
  properties:
    detail:
      type: string
      description: Error message describing what went wrong
  type: object
  required:
    - detail
  title: ErrorResponse
  description: Standard error response.
HTTPValidationError:
  properties:
    detail:
      items:
        $ref: "#/components/schemas/ValidationError"
      type: array
  type: object
  title: HTTPValidationError
ValidationError:
  properties:
    loc:
      items:
        type:
          - string
          - integer
      type: array
      title: Location
    msg:
      type: string
      title: Message
    type:
      type: string
      title: Error Type
    input: {}
    ctx:
      type: object
      title: Context
  type: object
  required:
    - loc
    - msg
    - type
  title: ValidationError
```
