> ## 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.

# Get Project Scenes

> Read a project's pictures and clips, to swap one with Edit Project

## Overview

Answers the pictures and clips of a project in the order they play, as they are on its timeline now. Use it to change one moment of a video without making it again: find the scene, make a new image or clip for it, and swap it in with [Edit Project](/api-reference/project/edit) in `scenes`, by `index`.

* `index` counts from `0` in play order. Layers that overlap (a picture over a background clip) are listed one after the other.
* `startMs` and `endMs` are milliseconds from the start of the video.
* `text` is what the captions say while the scene is on screen, to tell which moment it is.
* `prompt` is what the scene was generated from. Rework it and [generate an image](/api-reference/media/generate-image) or a [clip](/api-reference/media/generate-video) with the project's `aspectRatio`; once it is `COMPLETED`, swap it in.
* `replaceable` is `false` for a clip that plays its own sound (an avatar speaking, a character's lines). Swapping it would drop that sound, so it is edited in the dashboard.

## Changing one scene

1. `GET /v1/project/{projectId}/scenes` and pick the scene by its `text` or time.
2. Make the new media: [Generate Image](/api-reference/media/generate-image) for an image scene, [Generate Video](/api-reference/media/generate-video) for a clip scene (at least as long as the scene), or use one already in your [library](/api-reference/media/list). Wait until it is `COMPLETED`.
3. `PATCH /v1/project/{projectId}/edit` with `{ "scenes": [{ "index": 2, "mediaId": "..." }] }`.
4. [Render Project](/api-reference/video/render) for the new video. Only the new media costs credits; editing and rendering are free.

<RequestExample>
  ```bash cURL theme={null}
  curl -X GET "https://api.hooked.so/v1/project/cm4x9k2p10001ab12cd34ef56/scenes" \
    -H "x-api-key: your_api_key_here"
  ```

  ```javascript JavaScript theme={null}
  const projectId = "cm4x9k2p10001ab12cd34ef56";

  const response = await fetch(`https://api.hooked.so/v1/project/${projectId}/scenes`, {
    headers: { "x-api-key": process.env.HOOKED_API_KEY },
  });
  const { data } = await response.json();

  for (const scene of data.scenes) {
    console.log(scene.index, scene.kind, `${scene.startMs}ms`, scene.text);
  }
  ```

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

  project_id = "cm4x9k2p10001ab12cd34ef56"
  response = requests.get(
      f"https://api.hooked.so/v1/project/{project_id}/scenes",
      headers={"x-api-key": os.environ["HOOKED_API_KEY"]},
  )
  for scene in response.json()["data"]["scenes"]:
      print(scene["index"], scene["kind"], scene["startMs"], scene["text"])
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "success": true,
    "message": "Scenes fetched successfully",
    "data": {
      "projectId": "cm4x9k2p10001ab12cd34ef56",
      "aspectRatio": "ratio_9_16",
      "scenes": [
        {
          "index": 0,
          "kind": "image",
          "startMs": 0,
          "endMs": 2400,
          "text": "Three habits that changed my mornings",
          "mediaId": "cm4x9p3r40005ab12gh56ij11",
          "url": "https://assets.example.com/scene-0.png",
          "prompt": "A sunrise over a quiet kitchen, warm light, steam rising from a coffee cup",
          "replaceable": true
        },
        {
          "index": 1,
          "kind": "video",
          "startMs": 2400,
          "endMs": 6000,
          "text": "Try them",
          "mediaId": null,
          "url": "https://assets.example.com/scene-1.mp4",
          "prompt": null,
          "replaceable": true
        }
      ]
    }
  }
  ```

  ```json 404 theme={null}
  {
    "success": false,
    "message": "Project not found"
  }
  ```
</ResponseExample>

## Errors

| Status | When |
| - | - |
| 401 | Missing or invalid API key (`code: "not_authenticated"`) |
| 403 | The team does not have the Hooked app product (`code: "entitlement_required"`) |
| 404 | No such project. Another team's project, or an id that is not one, answers the same `Project not found` |
| 500 | `Internal server error`. Retry |


## OpenAPI

````yaml GET /v1/project/{projectId}/scenes
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/project/{projectId}/scenes:
    get:
      tags:
        - Videos
      summary: Get Project Scenes
      description: >-
        The pictures and clips of a project in play order, numbered as [Edit
        Project](/api-reference/project/edit) takes them in `scenes`, with when
        each is on screen, what the captions say meanwhile and the prompt it was
        generated from. Read them to change one moment of a video: make a new
        image or clip and swap it in, then render again.
      operationId: getProjectScenes
      parameters:
        - name: projectId
          in: path
          required: true
          schema:
            type: string
          description: >-
            The `projectId` a create endpoint answered, or one from GET
            /v1/project/list.
          example: cm4x9k2p10001ab12cd34ef56
      responses:
        '200':
          description: The project's scenes
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  message:
                    type: string
                  data:
                    type: object
                    required:
                      - projectId
                      - aspectRatio
                      - scenes
                    properties:
                      projectId:
                        type: string
                      aspectRatio:
                        type: string
                        nullable: true
                        description: >-
                          The project's shape (`ratio_9_16`, `ratio_1_1`,
                          `ratio_16_9`): generate new images and clips with it.
                      scenes:
                        type: array
                        items:
                          type: object
                          required:
                            - index
                            - kind
                            - startMs
                            - endMs
                            - text
                            - mediaId
                            - url
                            - prompt
                            - replaceable
                          properties:
                            index:
                              type: integer
                              description: >-
                                The number to send in `scenes[].index` of Edit
                                Project. Counts from 0 in play order.
                            kind:
                              type: string
                              enum:
                                - image
                                - video
                              description: >-
                                An image or a clip. A scene is swapped for media
                                of the same kind.
                            startMs:
                              type: integer
                              description: >-
                                When it appears, in milliseconds from the start
                                of the video.
                            endMs:
                              type: integer
                              description: >-
                                When it leaves, in milliseconds from the start
                                of the video.
                            text:
                              type: string
                              description: >-
                                What the captions say while it is on screen;
                                empty when nothing.
                            mediaId:
                              type: string
                              nullable: true
                              description: >-
                                The library media it shows, or `null` when it
                                was made by the generation without one.
                            url:
                              type: string
                              description: The file it shows (signed, valid for a while).
                            prompt:
                              type: string
                              nullable: true
                              description: >-
                                The prompt it was generated from, to make a new
                                version of it; `null` when it was not generated.
                            replaceable:
                              type: boolean
                              description: >-
                                `false` for a clip that plays its own sound (an
                                avatar speaking, a character's lines): swapping
                                it would drop that sound, so it is edited in the
                                dashboard.
              example:
                success: true
                message: Scenes fetched successfully
                data:
                  projectId: cm4x9k2p10001ab12cd34ef56
                  aspectRatio: ratio_9_16
                  scenes:
                    - index: 0
                      kind: image
                      startMs: 0
                      endMs: 2400
                      text: Three habits that changed my mornings
                      mediaId: cm4x9p3r40005ab12gh56ij11
                      url: https://assets.example.com/scene-0.png
                      prompt: >-
                        A sunrise over a quiet kitchen, warm light, steam rising
                        from a coffee cup
                      replaceable: true
                    - index: 1
                      kind: video
                      startMs: 2400
                      endMs: 6000
                      text: Try them
                      mediaId: null
                      url: https://assets.example.com/scene-1.mp4
                      prompt: null
                      replaceable: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/EntitlementRequired'
        '404':
          description: >-
            Not found. Another team's project, or an id that is not one, answers
            the same way as a missing one.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFound404'
              example:
                success: false
                message: Project not found
        '429':
          $ref: '#/components/responses/RateLimited429'
        '500':
          $ref: '#/components/responses/InternalError'
      security:
        - ApiKeyAuth: []
components:
  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
    InternalError:
      description: Internal server error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error500'
  schemas:
    NotFound404:
      type: object
      description: >-
        Not found. Another team's resource answers the same way as a missing
        one.
      properties:
        success:
          type: boolean
          enum:
            - false
        message:
          type: string
      required:
        - success
        - message
      example:
        success: false
        message: Project not found
    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
    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
  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.