Purpose
This post is about using Luma's Agents image API on my personal website's travel page. I was interested in AI image generation, and wanted to generate more creative covers for each of my trips.
I came away impressed. The uni-1 model takes a prompt plus up to nine reference images and returns one image. The docs are clear, the SDK is small, and the generation quality was impressive enough to put on my site.
This post outlines the mini pipeline I created to generate these images for my website. The code is in PR 37.
1. What the API actually is
Luma's image generation is an asynchronous job, not a single request. You create a generation with a model, a type, a prompt, and up to nine reference images. Then you wait until the job is completed or failed.
const generation = await luma.generations.create({
prompt,
model: "uni-1",
type: "image",
aspect_ratio: "2:3",
});Nine reference images is a documented cap. Each reference must be a publicly accessible URL, or a file already stored with Luma. Since I'm already on Vercel, I just used my existing photos from each trip and provided the public URLs as input.
On completion, Luma returns a presigned download URL that expires in an hour.
A generation is inexpensive in absolute terms. Pay-as-you-go pricing for uni-1 is about $0.04 with no references, and $0.067 with nine. There is no free tier. I designed the pipeline to wait for completion and upload the result to my own Vercel storage before that download link expires.
2. The pipeline
My site already stores trip photos in Vercel Blob storage. The pipeline takes a prompt and a handful of those photos, asks Luma for one image, waits for completion, and writes the result back to Blob.
Validation is also vital here. I confirm that the request is well formed and that every photo URL actually exists. Only then do I call Luma.
The interesting part is not the HTTP. It is the wait. A generation can take minutes, so the long-running work sits on Vercel Workflows instead of a request you hope finishes in time.
If something fails after Luma has already produced an image, I keep the generation id. The job is still on Luma's side, and the output can be fetched again before the presigned URL expires.
3. The prompt
The prompt is the other half of the API. The reference images supply raw material for Luma's model to build from. The prompt steers what Luma does with them.
I used one prompt for every trip. I did not describe individual photos, and I did not ask the model to use something from every image. I wanted to explore its creativity. Thus, I told it to pick standout feature(s), keep people out of the frame, and produce a single cover that still reads at a small size. Here's my prompt below:
A vibrant photo composite for a travel website trip cover, with no people
anywhere in the frame. Do not require an element from every photo. Select
the most standout feature or features from these photos and use that as
the main focus, then blend supporting scenery into one cohesive scene.
Rich saturated colors and luminous light, matching the bold, punchy feel
of an editorial travel photo grid, while keeping the composition clean
and balanced with a clear focal point so it reads easily as a single
cover image at small sizes.That combination was enough to get covers I was willing to publish.
Conclusion
Luma's image API is straightforward, and the results were better than I expected for a first integration. The interesting work was using Vercel Workflows for the first time, and refining the prompt after a few sub-optimal images. The covers on my travel page came out of it, and I intend to continue using Luma's API for future trips.