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

# Create a HappyHorse video

> Create a HappyHorse text-to-video or reference-image video task through CometAPI with POST /v1/videos, then poll the task and download the completed MP4 file.

Create a HappyHorse video from text, reference images, or an opening frame. The API returns a task ID immediately. Store the returned `id` to poll the task and download the completed video.

`POST /v1/videos` uses `multipart/form-data`. Send controls as form fields and reference images as `input_reference` fields, with one HTTPS URL or uploaded image file per field.

## Choose an input mode

| Goal                       | Model                              | Required fields                                        | Optional fields   |
| -------------------------- | ---------------------------------- | ------------------------------------------------------ | ----------------- |
| Text-to-video              | `happyhorse-1.0`, `happyhorse-1.1` | `model`, `prompt`                                      | `seconds`, `size` |
| Reference-to-video         | `happyhorse-1.0`, `happyhorse-1.1` | `model`, `prompt`, 1–9 `input_reference` URLs or files | `seconds`, `size` |
| First-frame image-to-video | `happyhorse-1.0`, `happyhorse-1.1` | `model`, `prompt`, one `first_frame` URL or file       | `seconds`, `size` |

Reference images guide the subjects and visual details in the video. Send 1–9 publicly accessible HTTPS image URLs or 1–9 image files, repeating `input_reference` once per image in image order.

Use only URLs or only files within this field. Send each URL separately rather than joining URLs with commas.

For `input_reference`, each reference image must be at or below 10 MB with `happyhorse-1.0`.
With `happyhorse-1.1`, each reference image must be at or below 20 MB.
These model limits apply to both image URLs and uploaded files.

Use JPEG, JPG, PNG, or WEBP images with a shortest side of at least 400 px.

The `input_reference` upload limit is 20 MiB (20 × 1024 × 1024 bytes) per file. Uploaded images must also meet the model-specific limit above.

The request samples at the top of this page show multiple image URLs for HappyHorse 1.1 and multiple file uploads for both models.

To set the opening frame, send `first_frame` once with one publicly accessible HTTPS image URL or one image file. Use this field in a separate request from `input_reference`.

## Set duration and size

| Model ID         | `seconds`        | Default                  |
| ---------------- | ---------------- | ------------------------ |
| `happyhorse-1.0` | integer `3`-`15` | `5` seconds, `1920x1080` |
| `happyhorse-1.1` | integer `3`-`15` | `5` seconds, `1920x1080` |

Choose an exact `WxH` value for `size` from the table below.

For first-frame requests, the image determines the framing and aspect ratio, while `size` selects the output resolution tier.

| Model            | Frame shape           | `size` values           |
| ---------------- | --------------------- | ----------------------- |
| `happyhorse-1.0` | Landscape             | `1280x720`, `1920x1080` |
|                  | Portrait              | `720x1280`, `1080x1920` |
|                  | Square                | `1440x1440`             |
| `happyhorse-1.1` | Landscape             | `1280x720`, `1920x1080` |
|                  | Portrait              | `720x1280`, `1080x1920` |
|                  | Square                | `1440x1440`             |
|                  | Classic landscape     | `1440x1080`             |
|                  | Classic portrait      | `720x960`, `1080x1440`  |
|                  | Wide landscape        | `2520x1080`             |
|                  | Wide portrait         | `1080x2520`             |
|                  | Near-square landscape | `900x720`, `1350x1080`  |
|                  | Near-square portrait  | `720x900`, `1080x1350`  |

## Task flow

<Steps>
  <Step title="Create the task">
    Send the multipart form request and store the returned `id`.
  </Step>

  <Step title="Poll the task">
    Call [Retrieve a HappyHorse video](./retrieve) until `status` is `completed`, `failed`, or `error`.
  </Step>

  <Step title="Download the result">
    When the task is `completed`, call [Retrieve HappyHorse video content](./retrieve-content) to download the MP4 file.
  </Step>
</Steps>


## OpenAPI

````yaml api/openapi/video/happyhorse/post-create.openapi.json POST /v1/videos
openapi: 3.1.0
info:
  title: HappyHorse Video Create API
  version: 1.0.0
  description: >-
    Create an asynchronous HappyHorse video task through CometAPI. Send
    text-to-video and reference-image video requests through the same POST
    /v1/videos multipart endpoint. Save the returned id, poll GET
    /v1/videos/{task_id}, and download the completed MP4 file.
servers:
  - url: https://api.cometapi.com
security:
  - bearerAuth: []
paths:
  /v1/videos:
    post:
      summary: Create a HappyHorse video task
      description: >-
        Create a HappyHorse text-to-video, reference-to-video, or first-frame
        video task. Send fields as multipart/form-data. For reference-to-video,
        send 1–9 HTTPS image URLs or 1–9 uploaded image files by repeating
        input_reference once per image. Use only URLs or only files within
        input_reference. Use first_frame separately to set the opening frame.
      operationId: happyhorse_create_video
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/HappyHorseCreateRequest'
            encoding:
              input_reference:
                contentType: text/plain, image/jpeg, image/png, image/webp
                style: form
                explode: true
              first_frame:
                contentType: text/plain, image/jpeg, image/png, image/webp
            examples:
              happyhorse_1_1_text_to_video:
                summary: HappyHorse 1.1 text-to-video
                value:
                  model: happyhorse-1.1
                  prompt: >-
                    A close-up cinematic shot of a ceramic coffee cup on a
                    wooden table. Steam rises slowly while morning light moves
                    across the background.
                  seconds: 3
                  size: 1920x1080
              happyhorse_1_1_reference_to_video:
                summary: HappyHorse 1.1 reference-to-video
                value:
                  model: happyhorse-1.1
                  prompt: >-
                    Use the uploaded reference image as the visual guide. Create
                    a short cinematic shot with gentle natural motion.
                  seconds: 3
                  size: 1280x720
                  input_reference:
                    - '@/path/to/reference.png'
              happyhorse_1_0_text_to_video:
                summary: HappyHorse 1.0 text-to-video
                value:
                  model: happyhorse-1.0
                  prompt: >-
                    A person reads beside a tall window while soft daylight
                    moves across the room.
                  seconds: 3
                  size: 1280x720
              happyhorse_1_1_uploaded_references_to_video:
                summary: HappyHorse 1.1 multiple reference images
                value:
                  model: happyhorse-1.1
                  prompt: Keep both reference subjects in gentle motion.
                  seconds: 3
                  size: 1280x720
                  input_reference:
                    - '@/path/to/reference-1.png'
                    - '@/path/to/reference-2.png'
              happyhorse_1_1_first_frame_url:
                summary: HappyHorse 1.1 first frame from URL
                value:
                  model: happyhorse-1.1
                  prompt: Start from this image and slowly pan right.
                  seconds: 3
                  size: 1280x720
                  first_frame: >-
                    https://apidoc.cometapi.com/images/image/gemini/6100640_569429.png
              happyhorse_1_1_first_frame_file:
                summary: HappyHorse 1.1 first frame from file
                value:
                  model: happyhorse-1.1
                  prompt: Start from this image and slowly pan right.
                  seconds: 3
                  size: 1280x720
                  first_frame: '@/path/to/first-frame.png'
              happyhorse_1_0_uploaded_references_to_video:
                summary: HappyHorse 1.0 multiple reference images
                value:
                  model: happyhorse-1.0
                  prompt: Keep both reference subjects in gentle motion.
                  seconds: 3
                  size: 1280x720
                  input_reference:
                    - '@/path/to/reference-1.png'
                    - '@/path/to/reference-2.png'
              happyhorse_1_0_first_frame_url:
                summary: HappyHorse 1.0 first frame from URL
                value:
                  model: happyhorse-1.0
                  prompt: Start from this image and slowly pan right.
                  seconds: 3
                  size: 1280x720
                  first_frame: >-
                    https://apidoc.cometapi.com/images/image/gemini/6100640_569429.png
              happyhorse_1_0_first_frame_file:
                summary: HappyHorse 1.0 first frame from file
                value:
                  model: happyhorse-1.0
                  prompt: Start from this image and slowly pan right.
                  seconds: 3
                  size: 1280x720
                  first_frame: '@/path/to/first-frame.png'
              happyhorse_1_1_reference_image_url:
                summary: HappyHorse 1.1 reference image URLs
                value:
                  model: happyhorse-1.1
                  prompt: >-
                    Use both reference images as visual guides. Preserve their
                    visual details with gentle natural motion.
                  seconds: 3
                  size: 1280x720
                  input_reference:
                    - >-
                      https://apidoc.cometapi.com/images/image/gemini/6100640_569429.png
                    - >-
                      https://apidoc.cometapi.com/images/image/gemini/6100640_569420.png
      responses:
        '200':
          description: >-
            Task created. Store the returned id and poll GET
            /v1/videos/{task_id}.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HappyHorseVideoTask'
              example:
                id: task_example
                task_id: task_example
                object: video
                model: happyhorse-1.1
                status: queued
                progress: 0
                created_at: 1779938152
        '400':
          description: >-
            The request is missing a required field or contains a value that the
            selected model cannot use.
        '401':
          description: The API key is missing or invalid.
      security:
        - bearerAuth: []
      x-codeSamples:
        - lang: Shell
          label: HappyHorse 1.1 text-to-video
          source: |-
            curl https://api.cometapi.com/v1/videos \
              -H "Authorization: Bearer $COMETAPI_KEY" \
              -F model=happyhorse-1.1 \
              -F 'prompt=A close-up cinematic shot of a ceramic coffee cup on a wooden table. Steam rises slowly while morning light moves across the background.' \
              -F seconds=3 \
              -F size=1920x1080
        - lang: Python
          label: HappyHorse 1.1 text-to-video
          source: |
            import os
            import requests

            fields = [
                ("model", (None, "happyhorse-1.1")),
                ("prompt", (None, "A close-up cinematic shot of a ceramic coffee cup on a wooden table. Steam rises slowly while morning light moves across the background.")),
                ("seconds", (None, "3")),
                ("size", (None, "1920x1080")),
            ]

            response = requests.post(
                "https://api.cometapi.com/v1/videos",
                headers={"Authorization": "Bearer " + os.environ["COMETAPI_KEY"]},
                files=fields,
                timeout=120,
            )

            response.raise_for_status()
            print(response.json())
        - lang: JavaScript
          label: HappyHorse 1.1 text-to-video
          source: >
            const form = new FormData();

            form.append("model", "happyhorse-1.1");

            form.append("prompt", "A close-up cinematic shot of a ceramic coffee
            cup on a wooden table. Steam rises slowly while morning light moves
            across the background.");

            form.append("seconds", "3");

            form.append("size", "1920x1080");


            const response = await fetch("https://api.cometapi.com/v1/videos", {
              method: "POST",
              headers: { Authorization: `Bearer ${process.env.COMETAPI_KEY}` },
              body: form,
            });


            const result = await response.json();

            console.log(result);
        - lang: Shell
          label: HappyHorse 1.1 reference-to-video
          source: |-
            curl https://api.cometapi.com/v1/videos \
              -H "Authorization: Bearer $COMETAPI_KEY" \
              -F model=happyhorse-1.1 \
              -F 'prompt=Use the uploaded reference image as the visual guide. Create a short cinematic shot with gentle natural motion.' \
              -F seconds=3 \
              -F size=1280x720 \
              -F 'input_reference=@/path/to/reference.png'
        - lang: Python
          label: HappyHorse 1.1 reference-to-video
          source: >
            import os

            import requests


            prompt = "Use the uploaded reference image as the visual guide.
            Create a short cinematic shot with gentle natural motion."


            with open("/path/to/reference.png", "rb") as reference:
                response = requests.post(
                    "https://api.cometapi.com/v1/videos",
                    headers={"Authorization": "Bearer " + os.environ["COMETAPI_KEY"]},
                    data={
                        "model": "happyhorse-1.1",
                        "prompt": prompt,
                        "seconds": "3",
                        "size": "1280x720",
                    },
                    files={"input_reference": ("reference.png", reference, "image/png")},
                    timeout=120,
                )

            response.raise_for_status()

            print(response.json())
        - lang: JavaScript
          label: HappyHorse 1.1 reference-to-video
          source: >
            import { readFile } from "node:fs/promises";


            const reference = await readFile("/path/to/reference.png");


            const form = new FormData();

            form.append("model", "happyhorse-1.1");

            form.append("prompt", "Use the uploaded reference image as the
            visual guide. Create a short cinematic shot with gentle natural
            motion.");

            form.append("seconds", "3");

            form.append("size", "1280x720");

            form.append("input_reference", new Blob([reference], { type:
            "image/png" }), "reference.png");


            const response = await fetch("https://api.cometapi.com/v1/videos", {
              method: "POST",
              headers: { Authorization: `Bearer ${process.env.COMETAPI_KEY}` },
              body: form,
            });


            const result = await response.json();

            console.log(result);
        - lang: Shell
          label: HappyHorse 1.0 text-to-video
          source: |-
            curl https://api.cometapi.com/v1/videos \
              -H "Authorization: Bearer $COMETAPI_KEY" \
              -F model=happyhorse-1.0 \
              -F 'prompt=A person reads beside a tall window while soft daylight moves across the room.' \
              -F seconds=3 \
              -F size=1280x720
        - lang: Python
          label: HappyHorse 1.0 text-to-video
          source: |
            import os
            import requests

            fields = [
                ("model", (None, "happyhorse-1.0")),
                ("prompt", (None, "A person reads beside a tall window while soft daylight moves across the room.")),
                ("seconds", (None, "3")),
                ("size", (None, "1280x720")),
            ]

            response = requests.post(
                "https://api.cometapi.com/v1/videos",
                headers={"Authorization": "Bearer " + os.environ["COMETAPI_KEY"]},
                files=fields,
                timeout=120,
            )

            response.raise_for_status()
            print(response.json())
        - lang: JavaScript
          label: HappyHorse 1.0 text-to-video
          source: >
            const form = new FormData();

            form.append("model", "happyhorse-1.0");

            form.append("prompt", "A person reads beside a tall window while
            soft daylight moves across the room.");

            form.append("seconds", "3");

            form.append("size", "1280x720");


            const response = await fetch("https://api.cometapi.com/v1/videos", {
              method: "POST",
              headers: { Authorization: `Bearer ${process.env.COMETAPI_KEY}` },
              body: form,
            });


            const result = await response.json();

            console.log(result);
        - lang: Shell
          label: HappyHorse 1.1 multiple reference images
          source: |
            curl \
              https://api.cometapi.com/v1/videos \
              -H "Authorization: Bearer $COMETAPI_KEY" \
              --form-string model=happyhorse-1.1 \
              --form-string 'prompt=Keep both reference subjects in gentle motion.' \
              --form-string seconds=3 \
              --form-string size=1280x720 \
              --form 'input_reference=@/path/to/reference-1.png;type=image/png' \
              --form 'input_reference=@/path/to/reference-2.png;type=image/png'
        - lang: Python
          label: HappyHorse 1.1 multiple reference images
          source: |
            import os
            from contextlib import ExitStack

            import requests

            with ExitStack() as stack:
                fields = [
                    ("model", (None, "happyhorse-1.1")),
                    ("prompt", (None, "Keep both reference subjects in gentle motion.")),
                    ("seconds", (None, "3")),
                    ("size", (None, "1280x720")),
                    (
                        "input_reference",
                        (
                            "reference-1.png",
                            stack.enter_context(open("/path/to/reference-1.png", "rb")),
                            "image/png",
                        ),
                    ),
                    (
                        "input_reference",
                        (
                            "reference-2.png",
                            stack.enter_context(open("/path/to/reference-2.png", "rb")),
                            "image/png",
                        ),
                    ),
                ]

                response = requests.post(
                    "https://api.cometapi.com/v1/videos",
                    headers={
                        "Authorization": "Bearer " + os.environ["COMETAPI_KEY"]
                    },
                    files=fields,
                    timeout=120,
                )

            response.raise_for_status()
            print(response.json())
        - lang: JavaScript
          label: HappyHorse 1.1 multiple reference images
          source: >
            import { readFile } from "node:fs/promises";


            const form = new FormData();

            form.append("model", "happyhorse-1.1");

            form.append("prompt", "Keep both reference subjects in gentle
            motion.");

            form.append("seconds", "3");

            form.append("size", "1280x720");

            form.append(
              "input_reference",
              new Blob([await readFile("/path/to/reference-1.png")], {
                type: "image/png",
              }),
              "reference-1.png",
            );

            form.append(
              "input_reference",
              new Blob([await readFile("/path/to/reference-2.png")], {
                type: "image/png",
              }),
              "reference-2.png",
            );


            const response = await fetch("https://api.cometapi.com/v1/videos", {
              method: "POST",
              headers: { Authorization: `Bearer ${process.env.COMETAPI_KEY}` },
              body: form,
            });


            if (!response.ok) {
              throw new Error(await response.text());
            }


            console.log(await response.json());
        - lang: Shell
          label: HappyHorse 1.1 first frame from URL
          source: >-
            image1=https://apidoc.cometapi.com/images/image/gemini/6100640_569429.png


            curl https://api.cometapi.com/v1/videos \
              -H "Authorization: Bearer $COMETAPI_KEY" \
              --form-string model=happyhorse-1.1 \
              --form-string 'prompt=Start from this image and slowly pan right.' \
              --form-string seconds=3 \
              --form-string size=1280x720 \
              --form-string "first_frame=$image1"
        - lang: Python
          label: HappyHorse 1.1 first frame from URL
          source: >
            import os


            import requests


            url1 =
            "https://apidoc.cometapi.com/images/image/gemini/6100640_569429.png"


            prompt = "Start from this image and slowly pan right."


            fields = [
                ("model", (None, "happyhorse-1.1")),
                ("prompt", (None, prompt)),
                ("seconds", (None, "3")),
                ("size", (None, "1280x720")),
                (
                    "first_frame",
                    (None, url1),
                ),
            ]


            response = requests.post(
                "https://api.cometapi.com/v1/videos",
                headers={"Authorization": "Bearer " + os.environ["COMETAPI_KEY"]},
                files=fields,
                timeout=120,
            )


            response.raise_for_status()

            print(response.json())
        - lang: JavaScript
          label: HappyHorse 1.1 first frame from URL
          source: >
            const form = new FormData();

            form.append("model", "happyhorse-1.1");

            form.append("prompt", "Start from this image and slowly pan
            right.");

            form.append("seconds", "3");

            form.append("size", "1280x720");

            form.append(
              "first_frame",
              "https://apidoc.cometapi.com/images/image/gemini/6100640_569429.png",
            );


            const response = await fetch("https://api.cometapi.com/v1/videos", {
              method: "POST",
              headers: { Authorization: "Bearer " + process.env.COMETAPI_KEY },
              body: form,
            });


            if (!response.ok) {
              throw new Error(await response.text());
            }


            console.log(await response.json());
        - lang: Shell
          label: HappyHorse 1.1 first frame from file
          source: |-
            curl https://api.cometapi.com/v1/videos \
              -H "Authorization: Bearer $COMETAPI_KEY" \
              --form-string model=happyhorse-1.1 \
              --form-string 'prompt=Start from this image and slowly pan right.' \
              --form-string seconds=3 \
              --form-string size=1280x720 \
              --form 'first_frame=@/path/to/first-frame.png;type=image/png'
        - lang: Python
          label: HappyHorse 1.1 first frame from file
          source: |
            import os

            import requests

            prompt = (
                "Start from this image and slowly pan right."
            )

            with open("/path/to/first-frame.png", "rb") as image_1:
                fields = [
                    ("model", (None, "happyhorse-1.1")),
                    ("prompt", (None, prompt)),
                    ("seconds", (None, "3")),
                    ("size", (None, "1280x720")),
                    ("first_frame", ("first-frame.png", image_1, "image/png")),
                ]

                response = requests.post(
                    "https://api.cometapi.com/v1/videos",
                    headers={"Authorization": "Bearer " + os.environ["COMETAPI_KEY"]},
                    files=fields,
                    timeout=120,
                )

            response.raise_for_status()
            print(response.json())
        - lang: JavaScript
          label: HappyHorse 1.1 first frame from file
          source: >
            import { readFile } from "node:fs/promises";


            const image_1 = await readFile("/path/to/first-frame.png");


            const form = new FormData();

            form.append("model", "happyhorse-1.1");

            form.append("prompt", "Start from this image and slowly pan
            right.");

            form.append("seconds", "3");

            form.append("size", "1280x720");

            form.append(
              "first_frame",
              new Blob([image_1], { type: "image/png" }),
              "first-frame.png",
            );


            const response = await fetch("https://api.cometapi.com/v1/videos", {
              method: "POST",
              headers: { Authorization: "Bearer " + process.env.COMETAPI_KEY },
              body: form,
            });


            if (!response.ok) {
              throw new Error(await response.text());
            }


            console.log(await response.json());
        - lang: Shell
          label: HappyHorse 1.0 multiple reference images
          source: |
            curl \
              https://api.cometapi.com/v1/videos \
              -H "Authorization: Bearer $COMETAPI_KEY" \
              --form-string model=happyhorse-1.0 \
              --form-string 'prompt=Keep both reference subjects in gentle motion.' \
              --form-string seconds=3 \
              --form-string size=1280x720 \
              --form 'input_reference=@/path/to/reference-1.png;type=image/png' \
              --form 'input_reference=@/path/to/reference-2.png;type=image/png'
        - lang: Python
          label: HappyHorse 1.0 multiple reference images
          source: |
            import os
            from contextlib import ExitStack

            import requests

            with ExitStack() as stack:
                fields = [
                    ("model", (None, "happyhorse-1.0")),
                    ("prompt", (None, "Keep both reference subjects in gentle motion.")),
                    ("seconds", (None, "3")),
                    ("size", (None, "1280x720")),
                    (
                        "input_reference",
                        (
                            "reference-1.png",
                            stack.enter_context(open("/path/to/reference-1.png", "rb")),
                            "image/png",
                        ),
                    ),
                    (
                        "input_reference",
                        (
                            "reference-2.png",
                            stack.enter_context(open("/path/to/reference-2.png", "rb")),
                            "image/png",
                        ),
                    ),
                ]

                response = requests.post(
                    "https://api.cometapi.com/v1/videos",
                    headers={
                        "Authorization": "Bearer " + os.environ["COMETAPI_KEY"]
                    },
                    files=fields,
                    timeout=120,
                )

            response.raise_for_status()
            print(response.json())
        - lang: JavaScript
          label: HappyHorse 1.0 multiple reference images
          source: >
            import { readFile } from "node:fs/promises";


            const form = new FormData();

            form.append("model", "happyhorse-1.0");

            form.append("prompt", "Keep both reference subjects in gentle
            motion.");

            form.append("seconds", "3");

            form.append("size", "1280x720");

            form.append(
              "input_reference",
              new Blob([await readFile("/path/to/reference-1.png")], {
                type: "image/png",
              }),
              "reference-1.png",
            );

            form.append(
              "input_reference",
              new Blob([await readFile("/path/to/reference-2.png")], {
                type: "image/png",
              }),
              "reference-2.png",
            );


            const response = await fetch("https://api.cometapi.com/v1/videos", {
              method: "POST",
              headers: { Authorization: `Bearer ${process.env.COMETAPI_KEY}` },
              body: form,
            });


            if (!response.ok) {
              throw new Error(await response.text());
            }


            console.log(await response.json());
        - lang: Shell
          label: HappyHorse 1.0 first frame from URL
          source: >-
            image1=https://apidoc.cometapi.com/images/image/gemini/6100640_569429.png


            curl https://api.cometapi.com/v1/videos \
              -H "Authorization: Bearer $COMETAPI_KEY" \
              --form-string model=happyhorse-1.0 \
              --form-string 'prompt=Start from this image and slowly pan right.' \
              --form-string seconds=3 \
              --form-string size=1280x720 \
              --form-string "first_frame=$image1"
        - lang: Python
          label: HappyHorse 1.0 first frame from URL
          source: >
            import os


            import requests


            url1 =
            "https://apidoc.cometapi.com/images/image/gemini/6100640_569429.png"


            prompt = "Start from this image and slowly pan right."


            fields = [
                ("model", (None, "happyhorse-1.0")),
                ("prompt", (None, prompt)),
                ("seconds", (None, "3")),
                ("size", (None, "1280x720")),
                (
                    "first_frame",
                    (None, url1),
                ),
            ]


            response = requests.post(
                "https://api.cometapi.com/v1/videos",
                headers={"Authorization": "Bearer " + os.environ["COMETAPI_KEY"]},
                files=fields,
                timeout=120,
            )


            response.raise_for_status()

            print(response.json())
        - lang: JavaScript
          label: HappyHorse 1.0 first frame from URL
          source: >
            const form = new FormData();

            form.append("model", "happyhorse-1.0");

            form.append("prompt", "Start from this image and slowly pan
            right.");

            form.append("seconds", "3");

            form.append("size", "1280x720");

            form.append(
              "first_frame",
              "https://apidoc.cometapi.com/images/image/gemini/6100640_569429.png",
            );


            const response = await fetch("https://api.cometapi.com/v1/videos", {
              method: "POST",
              headers: { Authorization: "Bearer " + process.env.COMETAPI_KEY },
              body: form,
            });


            if (!response.ok) {
              throw new Error(await response.text());
            }


            console.log(await response.json());
        - lang: Shell
          label: HappyHorse 1.0 first frame from file
          source: |-
            curl https://api.cometapi.com/v1/videos \
              -H "Authorization: Bearer $COMETAPI_KEY" \
              --form-string model=happyhorse-1.0 \
              --form-string 'prompt=Start from this image and slowly pan right.' \
              --form-string seconds=3 \
              --form-string size=1280x720 \
              --form 'first_frame=@/path/to/first-frame.png;type=image/png'
        - lang: Python
          label: HappyHorse 1.0 first frame from file
          source: |
            import os

            import requests

            prompt = (
                "Start from this image and slowly pan right."
            )

            with open("/path/to/first-frame.png", "rb") as image_1:
                fields = [
                    ("model", (None, "happyhorse-1.0")),
                    ("prompt", (None, prompt)),
                    ("seconds", (None, "3")),
                    ("size", (None, "1280x720")),
                    ("first_frame", ("first-frame.png", image_1, "image/png")),
                ]

                response = requests.post(
                    "https://api.cometapi.com/v1/videos",
                    headers={"Authorization": "Bearer " + os.environ["COMETAPI_KEY"]},
                    files=fields,
                    timeout=120,
                )

            response.raise_for_status()
            print(response.json())
        - lang: JavaScript
          label: HappyHorse 1.0 first frame from file
          source: >
            import { readFile } from "node:fs/promises";


            const image_1 = await readFile("/path/to/first-frame.png");


            const form = new FormData();

            form.append("model", "happyhorse-1.0");

            form.append("prompt", "Start from this image and slowly pan
            right.");

            form.append("seconds", "3");

            form.append("size", "1280x720");

            form.append(
              "first_frame",
              new Blob([image_1], { type: "image/png" }),
              "first-frame.png",
            );


            const response = await fetch("https://api.cometapi.com/v1/videos", {
              method: "POST",
              headers: { Authorization: "Bearer " + process.env.COMETAPI_KEY },
              body: form,
            });


            if (!response.ok) {
              throw new Error(await response.text());
            }


            console.log(await response.json());
        - lang: Shell
          label: HappyHorse 1.1 reference image URLs
          source: |
            curl \
              https://api.cometapi.com/v1/videos \
              -H "Authorization: Bearer $COMETAPI_KEY" \
              --form-string model=happyhorse-1.1 \
              --form-string 'prompt=Use both reference images as visual guides. Preserve their visual details with gentle natural motion.' \
              --form-string seconds=3 \
              --form-string size=1280x720 \
              --form-string input_reference=https://apidoc.cometapi.com/images/image/gemini/6100640_569429.png \
              --form-string input_reference=https://apidoc.cometapi.com/images/image/gemini/6100640_569420.png
        - lang: Python
          label: HappyHorse 1.1 reference image URLs
          source: |
            import os

            import requests

            fields = [
                ("model", (None, "happyhorse-1.1")),
                (
                    "prompt",
                    (
                        None,
                        "Use both reference images as visual guides. Preserve their "
                        "visual details with gentle natural motion."
                    ),
                ),
                ("seconds", (None, "3")),
                ("size", (None, "1280x720")),
                (
                    "input_reference",
                    (
                        None,
                        "https://apidoc.cometapi.com/images/image/gemini/6100640_569429.png"
                    ),
                ),
                (
                    "input_reference",
                    (
                        None,
                        "https://apidoc.cometapi.com/images/image/gemini/6100640_569420.png"
                    ),
                ),
            ]

            response = requests.post(
                "https://api.cometapi.com/v1/videos",
                headers={
                    "Authorization": "Bearer " + os.environ["COMETAPI_KEY"]
                },
                files=fields,
                timeout=120,
            )

            response.raise_for_status()
            print(response.json())
        - lang: JavaScript
          label: HappyHorse 1.1 reference image URLs
          source: |
            const form = new FormData();
            form.append("model", "happyhorse-1.1");
            form.append(
              "prompt",
              "Use both reference images as visual guides. Preserve their visual " +
              "details with gentle natural motion.",
            );
            form.append("seconds", "3");
            form.append("size", "1280x720");
            form.append(
              "input_reference",
              "https://apidoc.cometapi.com/images/image/gemini/6100640_569429.png",
            );
            form.append(
              "input_reference",
              "https://apidoc.cometapi.com/images/image/gemini/6100640_569420.png",
            );

            const response = await fetch("https://api.cometapi.com/v1/videos", {
              method: "POST",
              headers: { Authorization: `Bearer ${process.env.COMETAPI_KEY}` },
              body: form,
            });

            if (!response.ok) {
              throw new Error(await response.text());
            }

            console.log(await response.json());
components:
  schemas:
    HappyHorseCreateRequest:
      type: object
      required:
        - model
        - prompt
      properties:
        model:
          type: string
          description: HappyHorse model ID for this endpoint.
          enum:
            - happyhorse-1.0
            - happyhorse-1.1
          example: happyhorse-1.1
        prompt:
          type: string
          description: >-
            Text prompt that describes the video to generate. For image inputs,
            describe the motion and visual details to preserve.
          example: >-
            Use the uploaded reference image as the visual guide. Create a short
            cinematic shot with gentle natural motion.
        seconds:
          type: integer
          minimum: 3
          maximum: 15
          default: 5
          description: >-
            Requested clip duration in whole seconds. Send an integer from 3
            through 15 as a form field. The default is 5.
          example: 3
        size:
          type: string
          description: >-
            Output size as an exact WxH value. Use one of the documented size
            values for the selected HappyHorse model. For first-frame requests,
            size selects the resolution tier; the image determines the framing
            and aspect ratio.
          example: 1920x1080
        input_reference:
          description: >-
            Reference images for reference-to-video. Send 1–9 publicly
            accessible HTTPS image URLs or 1–9 uploaded image files by repeating
            input_reference once per image. Use only URLs or only files within
            this field; do not join URLs with commas. Reference images guide
            subjects and visual details. CometAPI preserves image order. Use
            JPEG, JPG, PNG, or WEBP images with a shortest side of at least 400
            px. Each reference image must be at or below 10 MB for
            happyhorse-1.0 or 20 MB for happyhorse-1.1. These model limits apply
            to both image URLs and uploaded files. The input_reference file
            upload limit is 20 MiB (20 x 1024 x 1024 bytes) per file. Keep
            uploads within the model limit as well. Keep this field separate
            from first_frame.
          anyOf:
            - title: Single image URL
              type: string
              format: uri
              pattern: ^https://
              description: One publicly accessible HTTPS image URL.
            - title: Image URLs
              type: array
              minItems: 1
              maxItems: 9
              items:
                type: string
                format: uri
                pattern: ^https://
                description: One publicly accessible HTTPS image URL.
            - title: Image files
              type: array
              minItems: 1
              maxItems: 9
              items:
                type: string
                format: binary
                description: One uploaded reference image file.
        first_frame:
          description: >-
            Opening-frame image as one publicly accessible HTTPS URL or one
            image file. Send this field once, using either a URL or a file. Use
            JPEG, JPG, PNG, or WEBP images up to 20 MB. Do not combine
            first_frame with input_reference.
          anyOf:
            - type: string
              format: uri
              pattern: ^https://
            - type: string
              format: binary
      additionalProperties: false
      not:
        required:
          - first_frame
          - input_reference
    HappyHorseVideoTask:
      type: object
      required:
        - id
        - object
        - model
        - status
        - progress
        - created_at
      properties:
        id:
          type: string
          description: Task ID. Use this value with retrieve and content endpoints.
          example: task_example
        task_id:
          type: string
          description: Compatibility alias for id when present.
          example: task_example
        object:
          type: string
          description: Object type. Video tasks return video.
          example: video
        model:
          type: string
          description: Model ID used for the task.
          example: happyhorse-1.1
        status:
          type: string
          description: >-
            Task lifecycle status. Poll until the value is completed, failed, or
            error.
          enum:
            - queued
            - in_progress
            - completed
            - failed
            - error
          example: queued
        progress:
          type: integer
          minimum: 0
          maximum: 100
          description: Task progress as a coarse percentage.
          example: 0
        created_at:
          type: integer
          description: Task creation time as a Unix timestamp in seconds.
          example: 1779938152
        completed_at:
          type: integer
          description: >-
            Task completion time as a Unix timestamp in seconds. This field
            appears on completed tasks.
          example: 1779938219
        video_url:
          type: string
          description: Temporary video delivery URL. This field appears on completed tasks.
          example: <temporary-video-url>
        error:
          type: object
          description: Failure details. This field appears when the task fails.
          additionalProperties: true
      additionalProperties: true
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: Bearer authentication. Use your CometAPI API key.

````