Quickstart
Generate and edit images with the Luma Agents REST API — quickstart, SDKs, and authentication.
The Luma Agents API provides access to uni-1, Luma’s image generation and editing model. The API is asynchronous: submit a generation request, poll for the result, and download your image.
Quickstart
Section titled “Quickstart”The workflow is three steps:
- Submit a generation request via
POST /v1/generations - Poll for status via
GET /v1/generations/{generation_id} - Download images from presigned URLs once the state reaches
completed
Generate an image
Section titled “Generate an image”import timefrom luma_agents import Luma
client = Luma()
# 1. Submitgeneration = client.generations.create( prompt="A glass of iced coffee on a marble countertop, morning light streaming through a window", aspect_ratio="16:9",)
# 2. Pollwhile generation.state not in ("completed", "failed"): time.sleep(2) generation = client.generations.get(generation.id)
# 3. Downloadif generation.state == "completed": print(f"Image URL: {generation.output[0].url}")else: print(f"Failed: {generation.failure_reason} (code: {generation.failure_code})")import Luma from "luma-agents";
const client = new Luma();
// 1. Submitlet generation = await client.generations.create({ prompt: "A glass of iced coffee on a marble countertop, morning light streaming through a window", aspect_ratio: "16:9",});
// 2. Pollwhile (generation.state !== "completed" && generation.state !== "failed") { await new Promise((r) => setTimeout(r, 2000)); generation = await client.generations.get(generation.id);}
// 3. Downloadif (generation.state === "completed") { console.log(`Image URL: ${generation.output![0].url}`);} else { console.error(`Failed: ${generation.failure_reason} (code: ${generation.failure_code})`);}package main
import ( "context" "fmt" "log" "time"
"github.com/lumalabs/luma-agents-go")
func main() { if err := run(context.Background()); err != nil { log.Fatal(err) }}
func run(ctx context.Context) error { client := lumaagents.NewClient()
// 1. Submit generation, err := client.Generations.New(ctx, lumaagents.GenerationNewParams{ Prompt: lumaagents.F("A glass of iced coffee on a marble countertop, morning light streaming through a window"), AspectRatio: lumaagents.F(lumaagents.GenerationNewParamsAspectRatio16_9), }) if err != nil { return fmt.Errorf("submit: %w", err) }
// 2. Poll for generation.State != lumaagents.GenerationStateCompleted && generation.State != lumaagents.GenerationStateFailed { time.Sleep(2 * time.Second) generation, err = client.Generations.Get(ctx, generation.ID) if err != nil { return fmt.Errorf("poll: %w", err) } }
// 3. Download if generation.State == lumaagents.GenerationStateCompleted { fmt.Printf("Image URL: %s\n", generation.Output[0].URL) } else { fmt.Printf("Failed: %s (code: %s)\n", generation.FailureReason, generation.FailureCode) } return nil}# 1. SubmitRESPONSE=$(curl -s -X POST https://agents.lumalabs.ai/v1/generations \ -H "Authorization: Bearer $LUMA_AGENTS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "prompt": "A glass of iced coffee on a marble countertop, morning light streaming through a window", "aspect_ratio": "16:9" }')
ID=$(echo "$RESPONSE" | jq -r '.id')
# 2. Pollwhile true; do RESULT=$(curl -s -H "Authorization: Bearer $LUMA_AGENTS_API_KEY" \ "https://agents.lumalabs.ai/v1/generations/$ID") STATE=$(echo "$RESULT" | jq -r '.state') [ "$STATE" = "completed" ] || [ "$STATE" = "failed" ] && break sleep 2done
# 3. Downloadecho "$RESULT" | jq -r '.output[0].url'Edit an image
Section titled “Edit an image”To edit an existing image instead, set type to "image_edit" and provide a source. Polling and download are identical to the generate flow above.
generation = client.generations.create( type="image_edit", prompt="Change the sky to a dramatic sunset with orange and purple clouds", source={"url": "https://example.com/landscape.jpg"},)const generation = await client.generations.create({ type: "image_edit", prompt: "Change the sky to a dramatic sunset with orange and purple clouds", source: { url: "https://example.com/landscape.jpg" },});generation, err := client.Generations.New(ctx, lumaagents.GenerationNewParams{ Type: lumaagents.F(lumaagents.GenerationNewParamsTypeImageEdit), Prompt: lumaagents.F("Change the sky to a dramatic sunset with orange and purple clouds"), Source: lumaagents.F(lumaagents.GenerationNewParamsSource{ URL: lumaagents.F("https://example.com/landscape.jpg"), }),})curl -X POST https://agents.lumalabs.ai/v1/generations \ -H "Authorization: Bearer $LUMA_AGENTS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "type": "image_edit", "prompt": "Change the sky to a dramatic sunset with orange and purple clouds", "source": { "url": "https://example.com/landscape.jpg" } }'See Image editing for image_ref, style transfer, and base64 source images.
Production polling
Section titled “Production polling”Don’t bother with exponential backoff — uni-1 generations typically take 30–60 seconds, so polling every 2 seconds is only ~15–30 GETs per job. What’s worth adding: a hard deadline so a stalled job can’t hang your worker, and a short initial wait so the first few polls aren’t wasted.
deadline = time.time() + 120 # 2-minute hard timeout
time.sleep(20) # uni-1 p50 is ~30s — no point polling sooner
while generation.state not in ("completed", "failed"): if time.time() > deadline: raise TimeoutError(f"Generation {generation.id} did not complete in time") generation = client.generations.get(generation.id) time.sleep(2)const deadline = Date.now() + 120_000; // 2-minute hard timeout
await new Promise((r) => setTimeout(r, 20_000)); // uni-1 p50 is ~30s
while (generation.state !== "completed" && generation.state !== "failed") { if (Date.now() > deadline) { throw new Error(`Generation ${generation.id} did not complete in time`); } generation = await client.generations.get(generation.id); await new Promise((r) => setTimeout(r, 2_000));}deadline := time.Now().Add(2 * time.Minute)
time.Sleep(20 * time.Second) // uni-1 p50 is ~30s
for generation.State != lumaagents.GenerationStateCompleted && generation.State != lumaagents.GenerationStateFailed { if time.Now().After(deadline) { return fmt.Errorf("generation %s did not complete in time", generation.ID) } generation, err = client.Generations.Get(ctx, generation.ID) if err != nil { return fmt.Errorf("poll: %w", err) } time.Sleep(2 * time.Second)}DEADLINE=$(($(date +%s) + 120)) # 2-minute hard timeoutsleep 20 # uni-1 p50 is ~30s
while true; do if [ "$(date +%s)" -gt "$DEADLINE" ]; then echo "Generation $ID did not complete in time" >&2 exit 1 fi RESULT=$(curl -s -H "Authorization: Bearer $LUMA_AGENTS_API_KEY" \ "https://agents.lumalabs.ai/v1/generations/$ID") STATE=$(echo "$RESULT" | jq -r '.state') [ "$STATE" = "completed" ] || [ "$STATE" = "failed" ] && break sleep 2doneAuthentication
Section titled “Authentication”Every request requires a Bearer token in the Authorization header. Set your API key as the LUMA_AGENTS_API_KEY environment variable — the official SDKs read it automatically.
export LUMA_AGENTS_API_KEY="luma-api-..."Base URL
Section titled “Base URL”https://agents.lumalabs.ai/v1Endpoints
Section titled “Endpoints”| Method | Path | Description |
|---|---|---|
POST | /v1/generations | Submit an image generation or edit job |
GET | /v1/generations/{generation_id} | Poll for generation status and output |
pip install luma-agentsnpm install luma-agentsgo get github.com/lumalabs/luma-agents-gogo install 'github.com/lumalabs/luma-agents-cli/cmd/luma-agents-cli@latest'Response headers
Section titled “Response headers”Every response includes X-Request-Id and X-API-Version headers. Successful generation requests also include rate limit headers (X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset). See Rate limits and headers for details.
Next steps
Section titled “Next steps”- Models — Model capabilities, limitations, and output specifications
- Image generation — Full parameter reference for text-to-image
- Image editing — Modify existing images with text prompts and reference images
- Pricing — Pay-as-you-go and Provisioned Throughput plans
- Rate limits and headers — Rate limiting, response headers, and retry strategies
- Error handling — Every error code with troubleshooting steps
- FAQ — Quick answers to common questions
- API Reference — Complete endpoint specifications