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

# Generate presigned upload URL

> Single-file upload **step 1**: get a presigned PUT URL and `materialId`. PUT the file to `uploadUrl`, then call [Complete single-file upload](/api-reference/app-synced/assets/materials/complete-upload). If `material` is returned, the same file is already in your library and no upload is needed. Required unless you create the job from `source.youtubeUrl`.

Uploads are de-duplicated by `fileHash`: uploading a file that is already in your website library returns the existing material, and deleting that material also removes it from **My assets**.



## OpenAPI

````yaml /api-reference/app-synced.json post /openapi/v1/app/assets/material/upload/gen-upload-url
openapi: 3.1.0
info:
  title: VMEG Open API (App-Synced)
  description: >-
    Same protocol as the Standalone API, but every task, material, and cloned
    voice lives in your VMEG website account: jobs show up in **My tasks**, open
    in the editor, and can be re-exported. Poll `GET
    /openapi/v1/app/tasks/detail` for results (no webhooks). See [Standalone vs
    App-Synced](/guides/app-synced/comparison).


    Linked guides are written for the Standalone API. The steps are the same;
    use the `/openapi/v1/app` prefix instead of `/openapi/v1`.
  version: 1.0.0
servers:
  - url: https://api.vmeg.ai
    description: Production
security:
  - apiKeyAuth: []
tags:
  - name: Media translation
    x-group: Video & audio translate and dub
    description: >-
      Translate and dub uploaded video/audio or a YouTube link on the same
      pipeline as vmeg.ai. The first pass renders the dubbed file; the job also
      appears in **My tasks** for editing and re-export. Poll [Query job
      status](/api-reference/app-synced/tasks/get-task-detail) for results.
  - name: Voice clone
    x-group: Voice cloning
    description: >-
      Clone a voice from a short recording. The voice is saved to **My voices**
      on the website and returned as `cv_*` for translate-and-dub jobs.
  - name: Task management
    x-group: Task status and history
    description: >-
      List, inspect, or delete the video/audio translation jobs in your VMEG
      account, including jobs created on the website.
  - name: Assets - Materials
    x-group: Upload files (materials)
    description: >-
      Upload and manage the files in your website material library (**My
      assets**). Finish the upload (single-file or multipart), then pass
      `materialId` to create-async.
  - name: Assets - Voices
    x-group: Voices (presets and clones)
    description: >-
      List preset system voices (`sv_*`) and manage your cloned voices (`cv_*`,
      same as **My voices** on the website).
paths:
  /openapi/v1/app/assets/material/upload/gen-upload-url:
    post:
      tags:
        - Assets - Materials
      summary: Generate presigned upload URL
      description: >-
        Single-file upload **step 1**: get a presigned PUT URL and `materialId`.
        PUT the file to `uploadUrl`, then call [Complete single-file
        upload](/api-reference/app-synced/assets/materials/complete-upload). If
        `material` is returned, the same file is already in your library and no
        upload is needed. Required unless you create the job from
        `source.youtubeUrl`.


        Uploads are de-duplicated by `fileHash`: uploading a file that is
        already in your website library returns the existing material, and
        deleting that material also removes it from **My assets**.
      operationId: appMaterialGenUploadUrl
      parameters:
        - $ref: '#/components/parameters/IdempotencyKeyRequired'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/OpenApiMaterialFileHashRequest'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OpenApiMaterialGenUploadUrlResponse'
components:
  parameters:
    IdempotencyKeyRequired:
      name: X-Idempotency-Key
      in: header
      required: true
      description: >-
        Required on mutating `POST` requests that create tasks or change
        persisted data (max 64 characters). See
        [Idempotency](/guides/idempotency).
      schema:
        type: string
        maxLength: 64
  schemas:
    OpenApiMaterialFileHashRequest:
      type: object
      required:
        - fileHash
        - fileName
      properties:
        fileHash:
          type: string
          description: File MD5 hash
        fileName:
          type: string
          description: File name including extension
    OpenApiMaterialGenUploadUrlResponse:
      allOf:
        - $ref: '#/components/schemas/OpenApiResponseBase'
        - type: object
          properties:
            data:
              $ref: '#/components/schemas/OpenApiMaterialGenUploadUrlData'
    OpenApiResponseBase:
      type: object
      properties:
        code:
          type: integer
          example: 200
          description: Business code; 200 means success
        message:
          type: string
          example: ''
          description: Human-readable detail when `code` is not success
      required:
        - code
    OpenApiMaterialGenUploadUrlData:
      type: object
      properties:
        uploadUrl:
          type: string
          description: Presigned PUT URL; empty when instant upload (dedup) applies
        material:
          $ref: '#/components/schemas/OpenApiMaterialDto'
          description: Present when the file already exists (instant upload)
        materialId:
          type: string
          description: >-
            Material ID for this upload. See
            [Materials](/guides/app-synced/comparison)
    OpenApiMaterialDto:
      type: object
      properties:
        materialId:
          type: string
          description: Material ID. See [Materials](/guides/app-synced/comparison)
        category:
          type: string
          example: video
          description: Material type
        name:
          type: string
          description: Display file name
        addressUrl:
          type: string
          description: Main file CDN URL
        thumbnailUrl:
          type: string
          description: Thumbnail CDN URL
        audioUrl:
          type: string
          description: Separated audio track CDN URL
        resolution:
          type: string
          example: 1920x1080
          description: Video resolution when applicable (e.g. `1920x1080`)
        mimeType:
          type: string
          description: MIME type of the main file
        fileHash:
          type: string
          description: MD5 hash of the main file
        filesize:
          type: integer
          format: int64
          description: File size in bytes
        duration:
          type: integer
          format: int64
          description: Duration in milliseconds
        createTime:
          type: string
          description: Registration time (ISO 8601)
        updateTime:
          type: string
          description: Last update time (ISO 8601)
  securitySchemes:
    apiKeyAuth:
      type: http
      scheme: bearer
      description: >-
        Send your API Key in the **`Authorization`** header (`Bearer
        <api_key>`). See [Authentication](/guides/authentication).

````