Skip to content
lumalabs.ai
Images

Image layering

Decompose an image into ordered RGBA layers with the Luma Agents API — layer extraction with real transparency on uni-1.

Decompose an existing image into up to 10 ordered RGBA layers — each a standalone PNG with real transparency, stacked front-to-back so the original composition can be reassembled or re-edited layer by layer. The uni-1 model analyzes the image, plans the split automatically, and extracts each layer as a complete element. For modifying an image in place, see Image editing.

Use type: "layering" when you want to take an image apart — not change it. Each extracted layer is a complete element (the model fills in content hidden behind foreground objects), so layers can be moved, restyled, or recomposed independently.

ScenarioUseWhy
Separate a subject from its backgroundlayeringBoth come back as standalone RGBA images
Build animatable / parallax scenes from a stilllayeringOrdered depth layers, background last
Prepare design comps for per-element editinglayeringEach element is its own transparent PNG
Change something in the image (sky, color, style)image_edit + sourceEdits in place — see Image editing
  1. You submit a source image (and optionally a short prompt guiding how to split it).
  2. The server plans the layers automatically — a vision model analyzes the image before generating, deciding how many layers to extract and what goes in each.
  3. Each planned layer is generated as a full RGBA image. Occluded regions are completed, so every layer is a whole element rather than a cutout with holes behind it.
  4. The completed generation returns N outputs (up to 10), ordered front-to-back — the last output is always the opaque background.

A layering request requires type: "layering" and a source image. The prompt field is required by the request schema — like every generation request — but for layering it may be an empty string.

from luma_agents import Luma
client = Luma()
generation = client.generations.create(
type="layering",
model="uni-1",
prompt="separate the subject from the background",
source={"url": "https://example.com/product-shot.jpg"},
)

The source field takes the same shape as image editing — a URL, inline base64 data, an uploaded file, or a prior generation reference.

From a URL:

{
"source": { "url": "https://example.com/photo.jpg" }
}

From base64 data:

{
"source": {
"data": "iVBORw0KGgoAAAANSUhEUgAAAAUA...",
"media_type": "image/jpeg"
}
}

From a prior generation — decompose an image you just generated by passing that completed generation’s top-level id as source.generation_id. The referenced generation must be owned by the same client:

{
"source": { "generation_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" }
}

From an uploaded file — reference a file you uploaded via the Files API by its file_id:

{
"source": { "file_id": "f1e2d3c4-b5a6-7890-abcd-ef0123456789" }
}

The prompt field must be present on every request, but for layering its content is optional — pass "" to let the model choose the decomposition on its own. It is also shorter than elsewhere — at most 500 characters. It does not describe an image to generate; it guides how the planner splits the source.

{
"type": "layering",
"prompt": "keep the text and logo on their own layers, group the props together",
"source": { "url": "https://example.com/poster.jpg" }
}

Sets the output resolution for every extracted layer. Defaults to "1k".

ValueDescription
1kFaster and lower cost — the default
2kRe-renders each layer at higher quality; flat 2× the 1k rate
generation = client.generations.create(
type="layering",
prompt="",
source={"url": "https://example.com/product-shot.jpg"},
layering={"resolution": "2k"},
)

These constraints are specific to type: "layering" requests.

RuleConstraint
typeMust be "layering"
modelMust be uni-1 — layering is not available on uni-1-max
sourceRequired. Provide exactly one of url, data, generation_id, or file_id
promptRequired field, may be empty. Maximum 500 characters (guides the split; does not describe a new image)
layering.resolution"1k" or "2k". Defaults to "1k"
layering.*Unknown keys in the layering block are rejected, not ignored
image_refRejected on layering requests
web_searchRejected on layering requests
videoRejected on layering requests

Common validation errors:

MistakeHTTP codeError
Missing source422"source image is required for layering"
Including image_ref422"image_ref is not supported for layering"
Including web_search422"web_search is not supported for layering"
Including a video block422"video options are not supported for layering"
prompt over 500 characters422"prompt must be at most 500 characters for layering"
layering block on a non-layering type422"layering options are only supported for type='layering'"

See Error handling for the full list of validation errors.

Some problems only surface after submission, when the generation is polled. These fail with state: "failed" and a standard failure_code — any hold placed at submit is released in full:

Situationfailure_code
The source image passed the submit checks but could not be used for layer extractioncorrupt_input
Layer planning failed for this image — retry, or adjust the prompt guidancegeneration_failed
The source image or an output was flagged by content moderationcontent_moderated

Layer planning failure is the one worth handling explicitly: the vision pass could not produce a usable decomposition for that particular image, and the server already retried once before reporting it. It shows up most on images with no clear foreground/background separation — a flat texture, an abstract pattern, an already-isolated object on plain white. Retrying the identical request rarely helps; adding prompt guidance does.

Layering follows the standard polling flow — submit returns HTTP 201 with state: "queued"; poll GET /v1/generations/{id} until the state reaches completed or failed. See the Quickstart for the polling pattern.

On completion, output contains one entry per extracted layer, ordered front-to-backoutput[0] is the frontmost element and the last entry is always the background. Each output carries a layer object describing what the layer contains:

{
"id": "d290f1ee-6c54-4b01-90e6-d701748f0851",
"type": "layering",
"state": "completed",
"model": "uni-1",
"created_at": "2026-07-16T12:00:00Z",
"output": [
{
"type": "image",
"url": "https://storage.example.com/generations/d290f1ee/layer0.png?X-Amz-Expires=3600&...",
"layer": {
"index": 0,
"label": "subject",
"description": "A woman in a red coat, complete from head to toe",
"alpha_hint": "soft"
}
},
{
"type": "image",
"url": "https://storage.example.com/generations/d290f1ee/layer1.png?X-Amz-Expires=3600&...",
"layer": {
"index": 1,
"label": "background",
"description": "The full street scene behind the subject",
"alpha_hint": "none"
}
}
],
"failure_reason": null,
"failure_code": null
}
FieldDescription
indexLayer position, front-to-back, starting at 0. The last layer is the background
labelShort (1–2 word) layer name
descriptionComplete-element caption for the layer’s content
alpha_hintEdge treatment of the layer’s transparency — see below

alpha_hint values:

ValueMeaning
softFeathered edges — hair, fur, glass, smoke
hardClean solid edges — objects, text, graphic elements
noneFully opaque — the background layer

Every layer is an RGBA PNG with real transparency — composite them in order (last first, first last on top) to reassemble the source image.

Layering is priced per generation, by layering.resolution. The rate is flat — it does not depend on how many layers come back.

layering.resolutionPrice per generation
1k$0.2250
2k$0.4500

A 2-layer result and a 10-layer result cost the same at the same resolution, so you know the charge before you submit. The hold placed at submit equals the final charge — nothing is released on a successful generation. A failed generation releases the hold in full and is never charged.

Layering counts against your standard generation limits — see Rate limits and headers. Rejections return HTTP 429 with Retry-After and the standard X-RateLimit-* headers, before any hold is placed, so a 429 never charges you.

A layering request occupies far more capacity than its single request slot suggests: one submission fans out to as many as ten image generations. Pace accordingly — treat one layering submission as up to ten generations, and prefer a modest concurrency ceiling with retries over bursting. If your integration needs sustained layering throughput, contact support+luma-agents-api@lumalabs.ai so headroom can be sized for your account.

  • Image generation — Generate new images from text
  • Image editing — Modify existing images with text prompts
  • Files API — Upload a source once, reference it by file_id
  • Models — Model capabilities and limitations
  • Pricing — Pay-as-you-go and Provisioned Throughput plans
  • Error handling — Every error code with troubleshooting steps
  • API Reference — Complete endpoint specifications