---
updatedAt: 2026-07-10T19:01:19.000Z
---

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

# Video Generation

<Callout icon="🚀" theme="default">
  ### Looking for the latest Luma API?

  Create and manage API access in the [Luma API Platform](https://platform.lumalabs.ai/). For current API guides and reference, visit the [Luma Agents API documentation](https://docs.agents.lumalabs.ai/).
</Callout>

# Installation

```python
pip install lumaai
```

<https://pypi.org/project/lumaai/>

# Authentication

1. Get a key from <https://platform.lumalabs.ai/>
2. Pass it to client sdk by either
   1. setting `LUMAAI_API_KEY`
   2. or passing `auth_token` to the client

# Models

| name        | model param |
| :---------- | :---------- |
| Ray 2 Flash | ray-flash-2 |
| Ray 2       | ray-2       |

# Setting up client

Using `LUMAAI_API_KEY` env variable

```python
from lumaai import LumaAI

client = LumaAI()
```

Using auth\_token parameter

```python
import os
from lumaai import LumaAI

client = LumaAI(
    auth_token=os.environ.get("LUMAAI_API_KEY"),
)
```

<br />

## How do I get the video for a generation?

* Right now the only supported way is via polling
* The create endpoint returns an id which is an UUID V4
* You can use it to poll for updates (you can see the video at `generation.assets.video`)

### Usage Example

```python
import requests
import time
from lumaai import LumaAI

client = LumaAI()

generation = client.generations.create(
  prompt="A teddy bear in sunglasses playing electric guitar and dancing",
)
completed = False
while not completed:
  generation = client.generations.get(id=generation.id)
  if generation.state == "completed":
    completed = True
  elif generation.state == "failed":
    raise RuntimeError(f"Generation failed: {generation.failure_reason}")
  print("Dreaming")
  time.sleep(3)

video_url = generation.assets.video

# download the video
response = requests.get(video_url, stream=True)
with open(f'{generation.id}.mp4', 'wb') as file:
    file.write(response.content)
print(f"File downloaded as {generation.id}.mp4")
```

# Async library

Import and use `AsyncLumaai`

```python
import os
from lumaai import AsyncLumaAI

client = AsyncLumaAI(
    auth_token=os.environ.get("LUMAAI_API_KEY"),
)
```

For all the functions add await (eg. below)

```python
generation = await client.generations.create(
    prompt="A teddy bear in sunglasses playing electric guitar and dancing",
    model="ray-2"
)
```

<br />

# Ray 2 Text to Video

```python Python
generation = client.generations.create(
    prompt="A teddy bear in sunglasses playing electric guitar and dancing",
    model="ray-2",
    resolution="720p",
    duration="5s"
)
```

Resolution can be 540p, 720p, 1080, 4k

# Ray 2 Image to Video

```python
generation = client.generations.create(
    prompt="Low-angle shot of a majestic tiger prowling through a snowy landscape, leaving paw prints on the white blanket",
    model="ray-2",
    keyframes={
      "frame0": {
        "type": "image",
        "url": "https://storage.cdn-luma.com/dream_machine/7e4fe07f-1dfd-4921-bc97-4bcf5adea39a/video_0_thumb.jpg"
      }
    }
)
```

# How to use concepts

```python
generation = client.generations.create(
    prompt="a car",
    model="ray-2",
    resolution="720p",
    duration="5s",
    concepts=[
      {
      	"key": "handheld"
      }
    ]
)
```

We have this new `/concepts/list` api one can hit to get list of concepts available

`https://api.lumalabs.ai/dream-machine/v1/generations/concepts/list`

# Text to Video

```python Python
generation = client.generations.create(
    prompt="A teddy bear in sunglasses playing electric guitar and dancing",
    model="ray-2"
)
```

### Downloading a video

```python
import requests

url = 'https://example.com/video.mp4'
response = requests.get(url, stream=True)

file_name = 'video.mp4'
with open('video.mp4', 'wb') as file:
    file.write(response.content)
print(f"File downloaded as {file_name}")
```

## With loop, aspect ratio

```python Python
generation = client.generations.create(
    prompt="A teddy bear in sunglasses playing electric guitar and dancing",
    model="ray-2"
    loop=True,
    aspect_ratio="3:4"
)
```

# Image to Video

<Callout icon="☁️" theme="default">
  ### Image URL

  You should upload and use your own cdn image urls, currently this is the only way to pass an image
</Callout>

## With start frame

```python
generation = client.generations.create(
    prompt="Low-angle shot of a majestic tiger prowling through a snowy landscape, leaving paw prints on the white blanket",
    model="ray-2"
    keyframes={
      "frame0": {
        "type": "image",
        "url": "https://storage.cdn-luma.com/dream_machine/7e4fe07f-1dfd-4921-bc97-4bcf5adea39a/video_0_thumb.jpg"
      }
    }
)
```

## With start frame, loop

```python
generation = client.generations.create(
    prompt="Low-angle shot of a majestic tiger prowling through a snowy landscape, leaving paw prints on the white blanket",
    model="ray-2"
    loop=True,
    keyframes={
      "frame0": {
        "type": "image",
        "url": "https://storage.cdn-luma.com/dream_machine/7e4fe07f-1dfd-4921-bc97-4bcf5adea39a/video_0_thumb.jpg"
      }
    }
)
```

## With ending frame

```python
generation = client.generations.create(
    prompt="Low-angle shot of a majestic tiger prowling through a snowy landscape, leaving paw prints on the white blanket",
    model="ray-2"
    keyframes={
      "frame1": {
        "type": "image",
        "url": "https://storage.cdn-luma.com/dream_machine/7e4fe07f-1dfd-4921-bc97-4bcf5adea39a/video_0_thumb.jpg"
      }
    }
)
```

## With start and end keyframes

```python
generation = client.generations.create(
    prompt="Low-angle shot of a majestic tiger prowling through a snowy landscape, leaving paw prints on the white blanket",
    model="ray-2"
    keyframes={
      "frame0": {
        "type": "image",
        "url": "https://storage.cdn-luma.com/dream_machine/7e4fe07f-1dfd-4921-bc97-4bcf5adea39a/video_0_thumb.jpg"
      },
      "frame1": {
        "type": "image",
        "url": "https://storage.cdn-luma.com/dream_machine/12d17326-a7b6-4538-b9b7-4a2e146d4488/video_0_thumb.jpg"
      }
    }
)
```

# Extend Video

## Extend video

> Extend is currently supported only for generated videos. Please make sure the generation is in `completed` state before passing it

```python
generation = client.generations.create(
    prompt="A teddy bear in sunglasses playing electric guitar and dancing",
    model="ray-2"
    keyframes={
      "frame0": {
        "type": "generation",
        "id": "d1968551-6113-4b46-b567-09210c2e79b0"
      }
    }
)
```

## Reverse extend video

> Generate video leading up to the provided video.
>
> Extend is currently supported only for generated videos. Please make sure the generation is in `completed` state before passing it

```python
generation = client.generations.create(
    prompt="A teddy bear in sunglasses playing electric guitar and dancing",
    model="ray-2"
    keyframes={
      "frame1": {
        "type": "generation",
        "id": "d1968551-6113-4b46-b567-09210c2e79b0"
      }
    }
)
```

## Extend a video with an end-frame

> Extend is currently supported only for generated videos. Please make sure the generation is in `completed` state before passing it

```python
generation = client.generations.create(
    prompt="Low-angle shot of a majestic tiger prowling through a snowy landscape, leaving paw prints on the white blanket",
    model="ray-2"
    keyframes={
      "frame0": {
        "type": "generation",
        "id": "d1968551-6113-4b46-b567-09210c2e79b0"
      },
      "frame1": {
        "type": "image",
        "url": "https://storage.cdn-luma.com/dream_machine/12d17326-a7b6-4538-b9b7-4a2e146d4488/video_0_thumb.jpg"
      }
    }
)
```

## Reverse extend a video with a start-frame

> Extend is currently supported only for generated videos. Please make sure the generation is in `completed` state before passing it

```python
generation = client.generations.create(
    prompt="Low-angle shot of a majestic tiger prowling through a snowy landscape, leaving paw prints on the white blanket",
    model="ray-2"
    keyframes={
      "frame0": {
        "type": "image",
        "url": "https://storage.cdn-luma.com/dream_machine/12d17326-a7b6-4538-b9b7-4a2e146d4488/video_0_thumb.jpg"
      },
      "frame1": {
        "type": "generation",
        "id": "d1968551-6113-4b46-b567-09210c2e79b0"
      }
    }
)
```

## Interpolate between 2 videos

> Interpolate is currently supported only for generated videos. Please make sure the generation is in `completed` state before passing it

```python
generation = client.generations.create(
    prompt="A teddy bear in sunglasses playing electric guitar and dancing",
    model="ray-2"
    keyframes={
      "frame1": {
        "type": "generation",
        "id": "d312d37a-7ff4-49f2-94f8-218f3fe2a4bd"
      },
      "frame1": {
        "type": "generation",
        "id": "d1968551-6113-4b46-b567-09210c2e79b0"
      }
    }
)
```

# Generations

## Get generation with id

```python
generation = client.generations.get(id="d1968551-6113-4b46-b567-09210c2e79b0")
```

## List all generations

```python
generation = client.generations.list(limit=100, offset=0)
```

## Delete generation

```python
generation = client.generations.delete(id="d1968551-6113-4b46-b567-09210c2e79b0")
```

# Camera Motions

> 📘 How to use camera motion
>
> Just add the camera motion value as part of prompt itself

## Get all supported camera motions

```python
supported_camera_motions = client.generations.camera_motion.list()
```

## How to use camera motion

Camera is controlled by language in Dream Machine. You can find supported camera moves by calling the Camera Motions endpoint. This will return an array of supported camera motion strings (like "camera orbit left") which can be used in prompts. In addition to these exact strings, syntactically similar phrases also work, though there can be mismatches sometimes.

<br />

# How to get a callback when generation has an update

* It will get status updates (dreaming/completed/failed)
* It will also get the video url as part of it when completed
* It's a `POST` endpoint you can pass, and request body will have the generation [object](https://github.com/lumalabs/lumaai-api/blob/35768db34e52600e319cb799e4488249e61eef17/openapi.yaml#L258) in it
* It expected to be called multiple times for a status
* If the endpoint returns a status code other than 200, it will be retried max 3 times with 100ms delay and the request has a 5s timeout

example

```python
generation = await client.generations.create(
    prompt="A teddy bear in sunglasses playing electric guitar and dancing",
    callback_url="<your_api_endpoint_here>"
)
```