Migrate legacy Ray models
Move Ray 3, Ray 2, Ray 2 Flash, Ray 2 Relaxed, Ray 3 Reference, and Ray 3 Refiner integrations to Ray 3.2 on the Luma Agents API.
Move legacy Luma video integrations to Ray 3.2 on the Luma Agents API. This guide is for API customers using any of these retiring models:
- Ray 3
- Ray 2
- Ray 2 Flash
- Ray 2 Relaxed
- Ray 3 Reference
- Ray 3 Refiner
If you received a deprecation notice, use the retirement date in that message as the cutoff for your account. Legacy requests will continue to work during the notice period, but begin migrating early enough to validate your production workflows before you cut over.
The migration in one view
Section titled “The migration in one view”The legacy API used model variants and separate request shapes to express intent. The Luma Agents API gives you one model and a small set of composable primitives:
| Decision | Legacy approach | Luma Agents API |
|---|---|---|
| Where to send work | Separate video and modify routes | POST https://agents.lumalabs.ai/v1/generations |
| Which model to call | Ray 3, Ray 2, Flash, Relaxed, Reference, or Refiner | model: "ray-3.2" |
| What operation to run | Implied by model or route | type: "video", "video_edit", or "video_reframe" |
| What media to use | Route-specific media and keyframes shapes | source, video.start_frame, video.end_frame, or video.*.keyframes |
| How to tune output | Top-level fields and model variants | Common settings under video; edit settings under video.edit |
| How to get the result | Async generation object | Submit once, poll GET /v1/generations/{id}, download output[].url |
Choose the primitive that matches your job
Section titled “Choose the primitive that matches your job”| What you want to do | type | Core inputs | Start here |
|---|---|---|---|
| Generate from text | video | prompt | Text-to-video |
| Animate one image | video | video.start_frame | Image-to-video |
| Interpolate between two images | video | video.start_frame + video.end_frame | Image-to-video |
| Direct a new clip with several images | video | video.keyframes + video.keyframe_indexes | Multi-keyframe generation |
| Continue a completed Luma video | video | One generation_id in video.start_frame or video.end_frame | Extend a video |
| Restyle, refine, or transform a video | video_edit | source + optional video.edit | Video editing |
| Pin the look of an edit at exact moments | video_edit | source + video.edit.keyframes + indexes | Edit keyframes |
| Change a video’s aspect ratio | video_reframe | source + target aspect_ratio | Video reframing |
After your new account is provisioned
Section titled “After your new account is provisioned”- Create an API key in the Luma developer dashboard. New keys begin with
luma-api-and are shown only once. - Store the key on your server as
LUMA_AGENTS_API_KEY. Do not expose it in browser or mobile code. - Point your client to
https://agents.lumalabs.ai/v1. - Confirm
ray-3.2access with the Playground, then copy its generated cURL for your first request shape. - Port one workflow at a time using the primitive matrix above.
export LUMA_AGENTS_API_KEY="luma-api-..."
curl -X POST https://agents.lumalabs.ai/v1/generations \ -H "Authorization: Bearer $LUMA_AGENTS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "ray-3.2", "type": "video", "prompt": "A slow dolly through a greenhouse at sunrise", "aspect_ratio": "16:9", "video": { "resolution": "720p", "duration": "5s" } }'The response is a generation object in queued state. Save its id; you use that same id to poll, edit, extend, or reframe the result.
Map each retiring model by intent
Section titled “Map each retiring model by intent”Do not look for one new model name per retired model. Every row below uses model: "ray-3.2"; the request’s type, media references, and controls now express the difference.
| Retiring model or workflow | New request shape | What changed |
|---|---|---|
| Ray 3 | type: "video" | Use the standard generation primitive for text-to-video and image-to-video. |
| Ray 2 | type: "video" | Move output controls under video and re-evaluate prompts and output quality. |
| Ray 2 Flash | type: "video" | There is no separate Flash model identifier. Benchmark Ray 3.2 latency and adjust timeouts and concurrency for your account. |
| Ray 2 Relaxed | type: "video" | There is no separate Relaxed model identifier. Preserve your creative intent in the prompt and anchor frames. |
| Ray 3 Reference | type: "video" or "video_edit" with keyframes | Use generation keyframes to direct a new clip, or edit keyframes to direct changes to an existing clip. |
| Ray 3 Refiner | type: "video_edit" with source | Start with video.edit.auto_controls: true; add strength, per-signal controls, or keyframes only when you need more control. |
Translate the request envelope
Section titled “Translate the request envelope”| Legacy field or behavior | New field or behavior | Migration note |
|---|---|---|
POST .../generations/video | POST /v1/generations + type: "video" | Text-to-video, image-to-video, interpolation, and extend share one type. |
POST .../generations/video/modify | POST /v1/generations + type: "video_edit" | The route no longer selects the operation. |
| Any retiring model identifier | model: "ray-3.2" | Use this exact public wire value. |
| Dedicated HDR model | video.hdr: true | HDR is a control, not a model. See video generation constraints. |
Top-level resolution, duration, loop | video.resolution, video.duration, video.loop | Common video settings now live together. |
keyframes.frame0 | video.start_frame | Drop the old type discriminator. |
keyframes.frame1 | video.end_frame | Set both start and end images to interpolate. |
Generation keyframe { "type": "generation", "id": "..." } | { "generation_id": "..." } | A single generation ref in start_frame extends forward; one in end_frame extends backward. |
Modify media.url | source: { "url": "...", "media_type": "video/mp4" } | Or use source.generation_id / source.file_id. |
Modify mode | video.edit.strength | Values are adhere_1–3, flex_1–3, and reimagine_1–3. |
callback_url | Poll GET /v1/generations/{id} | The Agents API result flow is submit, poll, download. |
Before and after: generate a video
Section titled “Before and after: generate a video”// Legacy{ "model": "ray-3", "prompt": "A fox runs through fresh snow", "resolution": "720p", "duration": "5s", "aspect_ratio": "16:9"}
// Luma Agents API{ "model": "ray-3.2", "type": "video", "prompt": "A fox runs through fresh snow", "aspect_ratio": "16:9", "video": { "resolution": "720p", "duration": "5s" }}Before and after: refine an existing video
Section titled “Before and after: refine an existing video”// Legacy modify/refiner request{ "model": "ray-3", "prompt": "Transform the scene into moonlit 35mm film footage", "media": { "url": "https://example.com/source.mp4" }, "mode": "flex_2"}
// Luma Agents API{ "model": "ray-3.2", "type": "video_edit", "prompt": "Transform the scene into moonlit 35mm film footage", "source": { "url": "https://example.com/source.mp4", "media_type": "video/mp4" }, "video": { "edit": { "auto_controls": true } }}Start edits in automatic mode. If you need predictable source adherence, replace auto_controls with a strength preset. For precise creative direction, add keyframes at specific source-frame indexes.
Understand the new media primitives
Section titled “Understand the new media primitives”The same reference shapes are reused across generation, editing, and reframing. Choose the form that best matches where the media already lives:
| Reference | Use when | Shape |
|---|---|---|
| Hosted media | The asset is available at a public URL | { "url": "https://...", "media_type": "video/mp4" } for source video |
| Uploaded file | You want to upload once and reuse the asset | { "file_id": "..." } from the Files API |
| Inline data | The asset is small and cannot be hosted | { "data": "<base64>", "media_type": "video/mp4" } |
| Prior Luma result | The asset came from a completed generation on the same API client | { "generation_id": "..." } |
Not every reference form is valid in every position. The linked generation, editing, and reframing guides list the exact combinations. As a rule of thumb, use source for the video being changed and keyframe fields for images that direct the result.
Poll and download
Section titled “Poll and download”POST /v1/generations returns immediately. Poll the returned id until state is completed or failed:
GENERATION_ID="<id-from-post-response>"
curl -H "Authorization: Bearer $LUMA_AGENTS_API_KEY" \ "https://agents.lumalabs.ai/v1/generations/$GENERATION_ID"| State | Meaning | What your integration should do |
|---|---|---|
queued | Accepted and waiting for capacity | Continue polling with backoff. |
processing | Generation is running | Continue polling. |
completed | Output is ready | Download each output[].url. |
failed | The job did not complete | Log failure_code, failure_reason, and X-Request-Id; retry only when the error is transient. |
Output URLs expire after one hour. Poll the generation again to mint a fresh URL if needed.
Cut over safely
Section titled “Cut over safely”Use this checklist for each production workflow:
- Inventory every call using a retiring model, including background jobs and rarely used fallback paths.
- Group calls by intent: generate, edit/refine, extend, or reframe.
- Port each group to its new
typeand request shape. - Run representative prompts and media through the Playground.
- Compare output quality, latency, failure handling, and cost with your current production baseline.
- Update polling deadlines and concurrency handling; do not carry Ray 2 Flash timing assumptions forward.
- Confirm your integration records generation
id,state,failure_code, andX-Request-Id. - Route a small percentage of production traffic to the new API, then ramp up while watching errors and latency.
- Move all traffic before the retirement date in your deprecation notice, then remove legacy model identifiers and fallback code.
Common migration mistakes
Section titled “Common migration mistakes”| Symptom | Likely cause | Fix |
|---|---|---|
Unknown model | Sent a retired model identifier | Send model: "ray-3.2". |
| Type is not supported for model | Reused an image type or omitted the video operation | Use video, video_edit, or video_reframe from the primitive matrix. |
| Video options have no effect or fail validation | Left output fields at the top level | Move them under video. |
| Source URL is rejected | Omitted its MIME type | Add source.media_type, such as video/mp4. |
| Edit source is rejected for duration | Source is longer than 18 seconds | Trim it to 18 seconds or shorter. Reframe sources must be 10 seconds or shorter. |
| A completed generation cannot be referenced | It belongs to another API client or is not complete | Use a completed generation owned by the same client, or pass a URL / uploaded file instead. |
| Client waits forever | Polling recognizes only the old lifecycle values | Stop on completed or failed and enforce a deadline. |
Need migration help?
Section titled “Need migration help?”If you need help planning your cutover or meeting the timing in your deprecation notice, email support+luma-agents-api@lumalabs.ai. For request-shape or runtime issues, include:
- the retiring model or workflow you are replacing;
- a redacted old request and new request;
- the new generation id and
X-Request-Id; - the HTTP status,
failure_code, andfailure_reason.
Continue with the full references
Section titled “Continue with the full references”- Video generation — text, image, multi-keyframe, extend, loop, and HDR
- Video editing — source media, automatic controls, strength, advanced controls, and keyframes
- Video reframing — target aspect ratios and source placement
- Files API — upload media once and reference it by
file_id - Error handling — HTTP errors, generation failures, and retry guidance
- Pricing — current Ray 3.2 rates and Provisioned Throughput