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

# List Media

> List the images and videos of your team's media library

## Overview

Returns the images and videos of your team's media library, newest first, with the total count for paging. These are the ids every create endpoint takes in `media` (and in `mediaId`, `startFrameMediaId`, `endFrameMediaId` for Scenes).

The list includes media that are still on their way in: an import being downloaded (`PROCESSING`), an upload waiting for its file (`PENDING`), and ones that failed. Only a `COMPLETED` media can go into a video; any other answers `400` on create.

<RequestExample>
  ```bash cURL theme={null}
  curl "https://api.hooked.so/v1/media/list?type=video&limit=20" \
    -H "x-api-key: your_api_key_here"
  ```

  ```javascript JavaScript theme={null}
  const params = new URLSearchParams({ type: "video", limit: "20" });
  const response = await fetch(`https://api.hooked.so/v1/media/list?${params}`, {
    headers: { "x-api-key": process.env.HOOKED_API_KEY },
  });
  const { data } = await response.json();

  const ready = data.media.filter((media) => media.status === "COMPLETED");
  console.log(`${ready.length} ready of ${data.total} videos`);
  ```

  ```python Python theme={null}
  import os
  import requests

  response = requests.get(
      "https://api.hooked.so/v1/media/list",
      params={"type": "video", "limit": 20},
      headers={"x-api-key": os.environ["HOOKED_API_KEY"]},
  )
  data = response.json()["data"]
  print(f"{len(data['media'])} of {data['total']} videos")
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "success": true,
    "message": "Media fetched successfully",
    "data": {
      "media": [
        {
          "id": "cm4x9s8u60009ab12kl56mn90",
          "name": "Demo clip",
          "type": "video",
          "status": "COMPLETED",
          "error": null,
          "url": "https://files.hooked.so/team/public/demo--fid--9c1d.mp4",
          "thumbnail": "https://files.hooked.so/team/public/demo--fid--9c1d.jpg",
          "durationSeconds": 12.4,
          "size": 8388608,
          "aspectRatio": "ratio_9_16",
          "isAIGenerated": false,
          "createdAt": "2026-10-01T09:30:00.000Z"
        }
      ],
      "total": 42,
      "limit": 20,
      "offset": 0
    }
  }
  ```

  ```json 400 theme={null}
  {
    "success": false,
    "message": "type: Must be image or video"
  }
  ```
</ResponseExample>

## Paging

`total` counts every media that matches the filters; you are done when `offset + limit >= total`. `limit` is 50 by default and at most 100. Use `search` to find a media by part of its name.

## Errors

| Status | Message | Cause |
| - | - | - |
| 400 | `type: Must be image or video` | Unknown `type`. |
| 401 | `code: "not_authenticated"` | Missing or invalid `x-api-key`. |
| 403 | `code: "entitlement_required"` | Your team does not have the Hooked app product. |
| 500 | `Failed to fetch media` | Retry the request. |

## Related

<CardGroup cols={2}>
  <Card title="Import Media from URL" icon="link" href="/api-reference/media/import">
    Add a file from a public URL
  </Card>

  <Card title="Upload Media" icon="upload" href="/api-reference/media/upload">
    Upload a file from your machine
  </Card>
</CardGroup>


## OpenAPI

````yaml GET /v1/media/list
openapi: 3.0.0
info:
  title: Hooked API
  version: 1.0.0
  description: AI Video Generation API
servers:
  - url: https://api.hooked.so
security:
  - ApiKeyAuth: []
tags:
  - name: Videos
    description: Create projects, follow them and render videos
  - name: Account Analysis
    description: Analyze TikTok and YouTube accounts
  - name: Channels
    description: Connected social accounts you publish to
  - name: Publish
    description: Schedule videos to your connected accounts
  - name: Images
    description: 'Image editing: background removal and expansion'
  - name: Media
    description: 'Your media library: list, import from a URL, upload a file'
  - name: Avatars
    description: Your team's own avatars (Actors) and their Hook + Demo reactions
paths:
  /v1/media/list:
    get:
      tags:
        - Media
      summary: List Media
      description: >-
        The images and videos of your team's media library, newest first, with
        the total count for paging.
      operationId: listMedia
      parameters:
        - name: type
          in: query
          required: false
          description: >-
            Only `image` or only `video`. Both when left out. Any other value
            answers 400.
          schema:
            type: string
            enum:
              - image
              - video
        - name: search
          in: query
          required: false
          description: Only media whose name contains this text (case-insensitive).
          schema:
            type: string
        - name: limit
          in: query
          required: false
          description: >-
            Page size, 1 to 100. Larger values are capped at 100; missing or
            invalid values fall back to 50.
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 50
        - name: offset
          in: query
          required: false
          description: >-
            Media to skip. Missing or invalid values fall back to 0. You are
            done when `offset + limit >= total`.
          schema:
            type: integer
            minimum: 0
            default: 0
      responses:
        '200':
          description: Media
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  message:
                    type: string
                  data:
                    type: object
                    properties:
                      media:
                        type: array
                        items:
                          $ref: '#/components/schemas/LibraryMedia'
                        description: The media on this page.
                      total:
                        type: integer
                        description: How many media match the filters, across all pages.
                      limit:
                        type: integer
                        description: The page size used.
                      offset:
                        type: integer
                        description: The offset used.
              example:
                success: true
                message: Media fetched successfully
                data:
                  media:
                    - id: cm4x9s8u60009ab12kl56mn90
                      name: Demo clip
                      type: video
                      status: COMPLETED
                      error: null
                      url: https://files.hooked.so/team/public/demo--fid--9c1d.mp4
                      thumbnail: https://files.hooked.so/team/public/demo--fid--9c1d.jpg
                      durationSeconds: 12.4
                      size: 8388608
                      aspectRatio: ratio_9_16
                      isAIGenerated: false
                      createdAt: '2026-10-01T09:30:00.000Z'
                    - id: cm4x9r2t50007ab12gh34ij78
                      name: Product shot
                      type: image
                      status: COMPLETED
                      error: null
                      url: >-
                        https://files.hooked.so/team/public/product-shot--fid--3f2a.png
                      thumbnail: null
                      durationSeconds: null
                      size: 482113
                      aspectRatio: null
                      isAIGenerated: false
                      createdAt: '2026-10-01T10:00:00.000Z'
                  total: 42
                  limit: 20
                  offset: 0
        '400':
          description: Unknown `type`
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationError400'
              example:
                success: false
                message: 'type: Must be image or video'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/EntitlementRequired'
        '429':
          $ref: '#/components/responses/RateLimited429'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error500'
              example:
                success: false
                message: Failed to fetch media
      security:
        - ApiKeyAuth: []
components:
  schemas:
    LibraryMedia:
      type: object
      description: >-
        An image or video of your team's media library. Pass its `id` wherever a
        create endpoint takes a media id, once `status` is `COMPLETED`.
      required:
        - id
        - name
        - type
        - status
        - error
        - url
        - thumbnail
        - durationSeconds
        - size
        - aspectRatio
        - isAIGenerated
        - createdAt
      properties:
        id:
          type: string
          description: The media id
        name:
          type: string
          description: The name shown in your library
        type:
          type: string
          enum:
            - image
            - video
        status:
          type: string
          enum:
            - PENDING
            - PROCESSING
            - COMPLETED
            - FAILED
          description: >-
            `PENDING`: an upload waiting for its file and the complete call.
            `PROCESSING`: an import downloading or a generation running.
            `COMPLETED`: ready to use. `FAILED`: the import, upload or
            generation did not work (a failed generation's credits are given
            back); an import still running after 15 minutes, or a generation
            after 60, also reads as `FAILED`.
        error:
          type: string
          nullable: true
          description: >-
            Why it failed, when `status` is `FAILED` (a provider's refusal, a
            URL that did not answer, a file of the wrong type, a job that timed
            out). `null` otherwise, and for a failure from before the reason was
            kept.
        url:
          type: string
          description: URL of the file; an empty string until `status` is `COMPLETED`
        thumbnail:
          type: string
          nullable: true
          description: >-
            URL of the video's thumbnail, once made; `null` for images and until
            then
        durationSeconds:
          type: number
          nullable: true
          description: Length of a video in seconds; `null` for images and while unknown
        size:
          type: integer
          description: File size in bytes (0 until the file is in your library)
        aspectRatio:
          type: string
          nullable: true
          description: >-
            `ratio_9_16`, `ratio_1_1` or `ratio_16_9` when known, otherwise
            `null`
        isAIGenerated:
          type: boolean
          description: Whether a model made it in Hooked
        createdAt:
          type: string
          format: date-time
    ValidationError400:
      type: object
      description: >-
        The request is invalid. `message` is `<field>: <reason>` when a field is
        to blame.
      properties:
        success:
          type: boolean
          enum:
            - false
        message:
          type: string
      required:
        - success
        - message
      example:
        success: false
        message: 'webhook: Must be a valid HTTPS URL'
    Error500:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - false
        message:
          type: string
        error:
          type: string
          description: Present on some endpoints
      example:
        success: false
        message: Internal server error
    Error401:
      type: object
      description: Missing or invalid `x-api-key`.
      properties:
        code:
          type: string
          enum:
            - not_authenticated
        message:
          type: string
          example: Not authenticated
        errorCode:
          type: string
          enum:
            - NOT_AUTHENTICATED
        details:
          type: object
          additionalProperties:
            type: string
      example:
        code: not_authenticated
        message: Not authenticated
        errorCode: NOT_AUTHENTICATED
        details:
          x-api-key: Header not provided or API Key invalid
    EntitlementRequired403:
      type: object
      description: >-
        Valid key, but the team does not have the product this endpoint belongs
        to.
      properties:
        code:
          type: string
          enum:
            - entitlement_required
        error:
          type: string
          enum:
            - entitlement_required
        message:
          type: string
        product:
          type: string
          example: app
      required:
        - code
        - error
        - message
        - product
      example:
        code: entitlement_required
        error: entitlement_required
        message: This endpoint requires the "app" product.
        product: app
  responses:
    Unauthorized:
      description: Missing or invalid API key
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error401'
    EntitlementRequired:
      description: The team does not have the product this endpoint needs
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/EntitlementRequired403'
    RateLimited429:
      description: >-
        Your team is over a rate limit: 30 POST requests per minute, 120 other
        requests per minute, or 3 downloads of your URLs running at once.
        Nothing ran and nothing was charged: wait `Retry-After` seconds and send
        the request again. See [Rate
        limits](/guides/error-handling#rate-limits-429).
      headers:
        Retry-After:
          description: Seconds to wait before sending again.
          schema:
            type: integer
        X-RateLimit-Limit:
          description: The limit of the bucket you hit (not sent for the download cap).
          schema:
            type: integer
        X-RateLimit-Remaining:
          description: 'Requests left in this window: 0 (not sent for the download cap).'
          schema:
            type: integer
        X-RateLimit-Reset:
          description: >-
            When the window ends, in Unix seconds (not sent for the download
            cap).
          schema:
            type: integer
      content:
        application/json:
          schema:
            type: object
            properties:
              success:
                type: boolean
                enum:
                  - false
              errorCode:
                type: string
                enum:
                  - RATE_LIMITED
              message:
                type: string
              retryAfterSeconds:
                type: integer
            required:
              - success
              - errorCode
              - message
              - retryAfterSeconds
          example:
            success: false
            errorCode: RATE_LIMITED
            message: >-
              Rate limit exceeded: 30 POST requests per minute per team. Retry
              after 12 s.
            retryAfterSeconds: 12
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key

````

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