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

# Start a large file upload

> Upload flow for files too large or awkward for `POST /files` (up to
200 MB):

1. Call this endpoint with the file's `media_type` and, ideally, its
   `size` and sha256 `hash`.
2. If the response has `deduplicated: true`, the file already exists in
   your account: use the returned `file_id` and `url` and skip the
   upload.
3. Otherwise send the raw bytes with `PUT {upload_url}` (direct to
   storage), or `PUT /files/upload/{session_id}` (`proxy_url`) when
   your environment can only reach `api.varg.ai`. Use the
   `Content-Type` in `headers`. The session is valid for 1 hour and
   accepts one upload.
4. The proxy PUT registers the file and returns `file_id`. If you
   uploaded to `upload_url` directly, register it afterwards with
   `POST /files/import` using `public_url`.

Send `X-Workspace-Id` (or `workspace_id` in the body) to file the
upload into a folder.




## OpenAPI

````yaml /openapi.yaml post /files/upload-session
openapi: 3.1.0
info:
  title: varg API
  version: 2.0.0
  description: |
    Unified REST API for AI media generation at `api.varg.ai/v2`.

    One API key, ~80 models across 8 providers, async jobs, stable output URLs
    on `s3.varg.ai`, files with lineage, and transparent credit billing
    (1 credit = 1 cent = $0.01).

    **The async job pattern:** every generation request returns `202 Accepted`
    with a job object (`status: queued`). Poll `GET /jobs/{id}` until the job
    reaches a terminal status (`completed`, `failed`, or `cancelled`), then read
    `output.outputs[0].url`. Alternatively, set `options.webhook_url` in the
    request to receive an HMAC-signed callback when the job finishes.
servers:
  - url: https://api.varg.ai/v2
security:
  - bearerAuth: []
tags:
  - name: Generation
    description: >-
      Create generation jobs (image, video, speech, music, transcription,
      ffmpeg, render, pipeline)
  - name: Tools
    description: Discover tools, their schemas, and call any tool generically
  - name: Jobs
    description: Poll and manage job lifecycle
  - name: Files
    description: Upload, import, probe, and manage files
  - name: Folders
    description: Group files into folders and file generated output automatically
  - name: Lineage
    description: Resolve which job produced a file
  - name: Presets
    description: Browse and apply reusable parameter values — voices, styles
  - name: Templates
    description: Browse, publish, use and render community templates
  - name: Pricing
    description: Estimate costs and browse the price catalog
  - name: Billing
    description: Balance, usage, and transaction history
  - name: Analytics
    description: >-
      Spend, runs and files over time — summaries, time series, breakdowns,
      activity
  - name: Account
    description: Identity and API key management
paths:
  /files/upload-session:
    post:
      tags:
        - Files
      summary: Start a large file upload
      description: |
        Upload flow for files too large or awkward for `POST /files` (up to
        200 MB):

        1. Call this endpoint with the file's `media_type` and, ideally, its
           `size` and sha256 `hash`.
        2. If the response has `deduplicated: true`, the file already exists in
           your account: use the returned `file_id` and `url` and skip the
           upload.
        3. Otherwise send the raw bytes with `PUT {upload_url}` (direct to
           storage), or `PUT /files/upload/{session_id}` (`proxy_url`) when
           your environment can only reach `api.varg.ai`. Use the
           `Content-Type` in `headers`. The session is valid for 1 hour and
           accepts one upload.
        4. The proxy PUT registers the file and returns `file_id`. If you
           uploaded to `upload_url` directly, register it afterwards with
           `POST /files/import` using `public_url`.

        Send `X-Workspace-Id` (or `workspace_id` in the body) to file the
        upload into a folder.
      operationId: createUploadSession
      parameters:
        - name: X-Workspace-Id
          in: header
          required: false
          description: >-
            Folder (id or slug) to file the upload into. Wins over
            `workspace_id` in the body.
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UploadSessionRequest'
            examples:
              video:
                value:
                  media_type: video/mp4
                  filename: clip.mp4
                  size: 48234112
                  hash: >-
                    sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08
      responses:
        '200':
          description: A new upload session, or the existing file when the hash matches
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/UploadSession'
                  - $ref: '#/components/schemas/UploadSessionDeduplicated'
              examples:
                session:
                  value:
                    deduplicated: false
                    session_id: file_abc123
                    upload_url: >-
                      https://example.r2.cloudflarestorage.com/files/acc_x/file_abc123.mp4?X-Amz-Signature=...
                    public_url: https://s3.varg.ai/files/acc_x/file_abc123.mp4
                    proxy_url: /v2/files/upload/file_abc123
                    headers:
                      Content-Type: video/mp4
                    expires_in: 3600
                    hash: >-
                      sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08
                deduplicated:
                  value:
                    deduplicated: true
                    file_id: file_abc123
                    url: https://s3.varg.ai/files/acc_x/file_abc123.mp4
                    hash: >-
                      sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08
                    size: 48234112
                    media_type: video/mp4
                    filename: clip.mp4
        '400':
          description: >-
            Body is not JSON (`invalid_json`) or `size` is out of range
            (`invalid_size`)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: Unknown folder (`workspace_not_found`)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Could not create the upload URL (`presign_failed`)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
components:
  schemas:
    UploadSessionRequest:
      type: object
      properties:
        media_type:
          type: string
          description: >-
            MIME type of the file. Defaults to `application/octet-stream` (the
            real type is then detected from the bytes on upload).
          example: video/mp4
        filename:
          type: string
        size:
          type: integer
          minimum: 1
          maximum: 209715200
          description: File size in bytes (max 200 MB)
        hash:
          type: string
          description: >-
            sha256 of the file, with or without the `sha256:` prefix. Lets the
            API skip the upload when you already have the file.
        workspace_id:
          type: string
          description: >-
            Folder (id or slug) to file the upload into. `X-Workspace-Id` takes
            precedence.
    UploadSession:
      type: object
      required:
        - deduplicated
        - session_id
        - upload_url
        - public_url
        - proxy_url
        - headers
        - expires_in
      properties:
        deduplicated:
          type: boolean
          enum:
            - false
        session_id:
          type: string
          description: Id for `PUT /files/upload/{session_id}`. Also becomes the file id.
        upload_url:
          type: string
          description: >-
            Presigned URL. `PUT` the bytes here directly, with the headers
            below.
        public_url:
          type: string
          description: URL the file will have once uploaded
        proxy_url:
          type: string
          description: >-
            Path of the proxy endpoint on this API, for clients that cannot
            reach `upload_url`
          example: /v2/files/upload/file_abc123
        headers:
          type: object
          description: Headers to send with the PUT
          additionalProperties:
            type: string
        expires_in:
          type: integer
          description: Seconds until the session expires
          example: 3600
        hash:
          type:
            - string
            - 'null'
    UploadSessionDeduplicated:
      type: object
      description: The file already exists in your account; no upload is needed.
      required:
        - deduplicated
        - file_id
        - url
      properties:
        deduplicated:
          type: boolean
          enum:
            - true
        file_id:
          type: string
        url:
          type: string
        hash:
          type:
            - string
            - 'null'
        size:
          type:
            - integer
            - 'null'
        media_type:
          type:
            - string
            - 'null'
        filename:
          type:
            - string
            - 'null'
    ErrorResponse:
      type: object
      properties:
        error:
          type: object
          properties:
            code:
              type: string
              example: model_not_found
            message:
              type: string
              example: 'Unknown model: flux-shnell'
            details: {}
  responses:
    Unauthorized:
      description: Missing or invalid API key / JWT
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            unauthorized:
              value:
                error:
                  code: unauthorized
                  message: Invalid or missing API key or JWT
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: |
        varg API key (`varg_...`). Get one at [app.varg.ai](https://app.varg.ai)
        or run `bunx vargai login`. App sessions may alternatively send a
        Supabase JWT.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.