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

# Request signed upload URL (recommended)

> Get a signed URL to upload a file directly to storage, bypassing the server. This is the recommended upload method for large files.

**Flow:**
1. Call this endpoint with content_type and file_size_bytes
2. POST to the returned upload_url with header `x-goog-resumable: start` to get a session URI
3. PUT your file content to the session URI (supports chunked/resumable uploads)
4. Use the returned file_id as input to generation endpoints

Allowed types: audio/mpeg, audio/wav, image/jpeg, image/png, image/webp, video/mp4. Max size: 64 MB. Upload URL expires in 15 minutes.



## OpenAPI

````yaml /api-reference/openapi.json post /v1/workspaces/{workspace_id}/files/upload-url
openapi: 3.1.0
info:
  title: Layer REST API
  description: >
    REST API for AI-powered game asset creation on the Layer platform.


    ## Authentication


    All endpoints require a Bearer token in the `Authorization` header:


    ```

    Authorization: Bearer <token>

    ```


    ### Personal Access Tokens (recommended)


    The simplest way to authenticate is with a Personal Access Token (PAT):


    1. Log in to [app.layer.ai](https://app.layer.ai)

    2. Go to **Settings > Personal Access Tokens**

    3. Click **Create Token**, give it a name, and copy the token value

    4. Pass it as `Authorization: Bearer <your-pat-token>`


    PATs are long-lived and ideal for scripts, CI pipelines, and partner
    integrations.


    ### OAuth2 (browser-based)


    For browser-based applications, use the Auth0 OAuth2 flow. Redirect users to

    the Layer login page, exchange the authorization code for a JWT access
    token,

    and use it as `Authorization: Bearer <jwt>`.


    ## Creative Units


    Generations consume Creative Units (CUs). Use the estimate endpoints to
    check

    cost before executing. Check workspace balance via `GET
    /v1/workspaces/{id}`.


    ## Pagination


    List endpoints support cursor-based pagination via `limit` and `cursor`
    query

    parameters. Responses include a `pagination` object with `next_cursor`,

    `has_more_results`, and `total_count`. Cursors are opaque — do not parse or

    construct them.


    ## Errors


    All errors return [RFC 7807 Problem
    Details](https://tools.ietf.org/html/rfc7807):


    ```json

    {
      "type": "https://api.layer.ai/errors/ERROR_CODE",
      "title": "Human-readable title",
      "status": 404,
      "detail": "Detailed description of what went wrong."
    }

    ```


    Common status codes: `401` (unauthenticated), `402` (insufficient balance),

    `403` (forbidden), `404` (not found), `422` (invalid input), `429` (rate
    limited).
  version: 1.0.0
servers:
  - url: https://api.app.layer.ai/api
    description: Production
  - url: /backend/rest
    description: Local development
security: []
paths:
  /v1/workspaces/{workspace_id}/files/upload-url:
    post:
      tags:
        - Files
      summary: Request signed upload URL (recommended)
      description: >-
        Get a signed URL to upload a file directly to storage, bypassing the
        server. This is the recommended upload method for large files.


        **Flow:**

        1. Call this endpoint with content_type and file_size_bytes

        2. POST to the returned upload_url with header `x-goog-resumable: start`
        to get a session URI

        3. PUT your file content to the session URI (supports chunked/resumable
        uploads)

        4. Use the returned file_id as input to generation endpoints


        Allowed types: audio/mpeg, audio/wav, image/jpeg, image/png, image/webp,
        video/mp4. Max size: 64 MB. Upload URL expires in 15 minutes.
      operationId: requestFileUploadUrl
      parameters:
        - name: workspace_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
            title: Workspace Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RequestUploadUrlRequest'
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RequestUploadUrlResponse'
        '401':
          description: Unauthenticated — missing or invalid Bearer token.
          content:
            application/problem+json:
              schema:
                type: object
                properties:
                  type:
                    type: string
                    example: https://api.layer.ai/errors/ERROR_CODE
                  title:
                    type: string
                    example: Error Title
                  status:
                    type: integer
                    example: 400
                  detail:
                    type: string
                    example: Human-readable description.
                required:
                  - type
                  - title
                  - status
                  - detail
        '402':
          description: Insufficient Creative Units balance.
          content:
            application/problem+json:
              schema:
                type: object
                properties:
                  type:
                    type: string
                    example: https://api.layer.ai/errors/ERROR_CODE
                  title:
                    type: string
                    example: Error Title
                  status:
                    type: integer
                    example: 400
                  detail:
                    type: string
                    example: Human-readable description.
                required:
                  - type
                  - title
                  - status
                  - detail
        '403':
          description: Forbidden — insufficient permissions.
          content:
            application/problem+json:
              schema:
                type: object
                properties:
                  type:
                    type: string
                    example: https://api.layer.ai/errors/ERROR_CODE
                  title:
                    type: string
                    example: Error Title
                  status:
                    type: integer
                    example: 400
                  detail:
                    type: string
                    example: Human-readable description.
                required:
                  - type
                  - title
                  - status
                  - detail
        '404':
          description: Resource not found.
          content:
            application/problem+json:
              schema:
                type: object
                properties:
                  type:
                    type: string
                    example: https://api.layer.ai/errors/ERROR_CODE
                  title:
                    type: string
                    example: Error Title
                  status:
                    type: integer
                    example: 400
                  detail:
                    type: string
                    example: Human-readable description.
                required:
                  - type
                  - title
                  - status
                  - detail
        '422':
          description: Invalid input parameters.
          content:
            application/problem+json:
              schema:
                type: object
                properties:
                  type:
                    type: string
                    example: https://api.layer.ai/errors/ERROR_CODE
                  title:
                    type: string
                    example: Error Title
                  status:
                    type: integer
                    example: 400
                  detail:
                    type: string
                    example: Human-readable description.
                required:
                  - type
                  - title
                  - status
                  - detail
        '429':
          description: Rate limited — too many concurrent requests.
          content:
            application/problem+json:
              schema:
                type: object
                properties:
                  type:
                    type: string
                    example: https://api.layer.ai/errors/ERROR_CODE
                  title:
                    type: string
                    example: Error Title
                  status:
                    type: integer
                    example: 400
                  detail:
                    type: string
                    example: Human-readable description.
                required:
                  - type
                  - title
                  - status
                  - detail
        '500':
          description: Internal server error.
          content:
            application/problem+json:
              schema:
                type: object
                properties:
                  type:
                    type: string
                    example: https://api.layer.ai/errors/ERROR_CODE
                  title:
                    type: string
                    example: Error Title
                  status:
                    type: integer
                    example: 400
                  detail:
                    type: string
                    example: Human-readable description.
                required:
                  - type
                  - title
                  - status
                  - detail
      security:
        - HTTPBearer: []
components:
  schemas:
    RequestUploadUrlRequest:
      properties:
        content_type:
          type: string
          title: Content Type
          description: MIME type of the file to upload.
        file_name:
          anyOf:
            - type: string
            - type: 'null'
          title: File Name
          description: Optional file name.
        file_size_bytes:
          type: integer
          exclusiveMinimum: 0
          title: File Size Bytes
          description: Expected file size in bytes. Used to enforce upload limits.
      type: object
      required:
        - content_type
        - file_size_bytes
      title: RequestUploadUrlRequest
    RequestUploadUrlResponse:
      properties:
        file_id:
          type: string
          format: uuid
          title: File Id
          description: >-
            Unique identifier for the file. Use as input to generation endpoints
            after upload completes.
        upload_url:
          type: string
          title: Upload Url
          description: >-
            Signed upload URL. POST to this URL to initiate a resumable upload,
            then PUT file chunks to the session URI returned in the Location
            header. Expires in 15 minutes.
        content_type:
          type: string
          title: Content Type
          description: MIME type to use when uploading.
      type: object
      required:
        - file_id
        - upload_url
        - content_type
      title: RequestUploadUrlResponse
  securitySchemes:
    HTTPBearer:
      type: http
      description: >-
        Personal Access Token or OAuth2 JWT. Create a PAT at app.layer.ai →
        Settings → Personal Access Tokens.
      scheme: bearer

````