curl --request POST \
--url https://api.moda.app/v1/media/layerize-assets \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"image": "<string>",
"mode": "full",
"idempotency_key": "<string>",
"callback_url": "<string>"
}
'import requests
url = "https://api.moda.app/v1/media/layerize-assets"
payload = {
"image": "<string>",
"mode": "full",
"idempotency_key": "<string>",
"callback_url": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
image: '<string>',
mode: 'full',
idempotency_key: '<string>',
callback_url: '<string>'
})
};
fetch('https://api.moda.app/v1/media/layerize-assets', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.moda.app/v1/media/layerize-assets",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'image' => '<string>',
'mode' => 'full',
'idempotency_key' => '<string>',
'callback_url' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.moda.app/v1/media/layerize-assets"
payload := strings.NewReader("{\n \"image\": \"<string>\",\n \"mode\": \"full\",\n \"idempotency_key\": \"<string>\",\n \"callback_url\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.moda.app/v1/media/layerize-assets")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"image\": \"<string>\",\n \"mode\": \"full\",\n \"idempotency_key\": \"<string>\",\n \"callback_url\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.moda.app/v1/media/layerize-assets")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"image\": \"<string>\",\n \"mode\": \"full\",\n \"idempotency_key\": \"<string>\",\n \"callback_url\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"id": "task_01HT9WK8N3M2J4A5Z6P7Q8R9TV",
"kind": "design",
"status": "queued",
"attempt": 123,
"max_attempts": 123,
"attempts_started": 123,
"links": {
"self": "<string>",
"events": "<string>",
"cancel": "<string>",
"canvas": "<string>"
},
"created_at": "<string>",
"started_at": "<string>",
"completed_at": "<string>",
"progress": {
"percent": 123,
"step": "<string>",
"message": "<string>"
},
"first_started_at": "<string>",
"input": {},
"result": {
"canvas_id": "<string>",
"canvas_url": "<string>",
"canvas_name": "<string>",
"conversation_id": "<string>",
"source_canvas_id": "<string>",
"source_canvas_url": "<string>",
"theme_canvas_id": "<string>",
"export": {
"url": "<string>",
"format": "<string>",
"status": "<string>",
"page_count": 123
}
},
"error": {},
"credits": {
"credits_used": 123,
"credits_remaining": 123
},
"retry_after_ms": 123
}{
"type": "invalid_request",
"code": "<string>",
"message": "<string>",
"doc_url": "<string>",
"request_id": "<string>",
"causes": [
"<unknown>"
],
"details": {},
"retry_after_ms": 123,
"retryable": true
}{
"type": "invalid_request",
"code": "<string>",
"message": "<string>",
"doc_url": "<string>",
"request_id": "<string>",
"causes": [
"<unknown>"
],
"details": {},
"retry_after_ms": 123,
"retryable": true
}{
"type": "invalid_request",
"code": "<string>",
"message": "<string>",
"doc_url": "<string>",
"request_id": "<string>",
"causes": [
"<unknown>"
],
"details": {},
"retry_after_ms": 123,
"retryable": true
}{
"type": "invalid_request",
"code": "<string>",
"message": "<string>",
"doc_url": "<string>",
"request_id": "<string>",
"causes": [
"<unknown>"
],
"details": {},
"retry_after_ms": 123,
"retryable": true
}{
"type": "invalid_request",
"code": "<string>",
"message": "<string>",
"doc_url": "<string>",
"request_id": "<string>",
"causes": [
"<unknown>"
],
"details": {},
"retry_after_ms": 123,
"retryable": true
}{
"type": "invalid_request",
"code": "<string>",
"message": "<string>",
"doc_url": "<string>",
"request_id": "<string>",
"causes": [
"<unknown>"
],
"details": {},
"retry_after_ms": 123,
"retryable": true
}{
"type": "invalid_request",
"code": "<string>",
"message": "<string>",
"doc_url": "<string>",
"request_id": "<string>",
"causes": [
"<unknown>"
],
"details": {},
"retry_after_ms": 123,
"retryable": true
}{
"type": "invalid_request",
"code": "<string>",
"message": "<string>",
"doc_url": "<string>",
"request_id": "<string>",
"causes": [
"<unknown>"
],
"details": {},
"retry_after_ms": 123,
"retryable": true
}Layerize Assets
Turn an image into downloadable full-size PNG layers and linked text metadata.
Returns a task immediately; poll its links.self or supply callback_url for a signed terminal webhook. Requires media:generate; polling uses tasks:read. No canvas-write/export scope or rollout flag is required. Billing uses the normal Layerize credit precheck and usage. Some effects may be delivered as composite layers with explicit partial-result warnings. PNG/JPEG/WebP only; EXIF orientation is normalized before reconstruction.
curl --request POST \
--url https://api.moda.app/v1/media/layerize-assets \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"image": "<string>",
"mode": "full",
"idempotency_key": "<string>",
"callback_url": "<string>"
}
'import requests
url = "https://api.moda.app/v1/media/layerize-assets"
payload = {
"image": "<string>",
"mode": "full",
"idempotency_key": "<string>",
"callback_url": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
image: '<string>',
mode: 'full',
idempotency_key: '<string>',
callback_url: '<string>'
})
};
fetch('https://api.moda.app/v1/media/layerize-assets', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.moda.app/v1/media/layerize-assets",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'image' => '<string>',
'mode' => 'full',
'idempotency_key' => '<string>',
'callback_url' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.moda.app/v1/media/layerize-assets"
payload := strings.NewReader("{\n \"image\": \"<string>\",\n \"mode\": \"full\",\n \"idempotency_key\": \"<string>\",\n \"callback_url\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.moda.app/v1/media/layerize-assets")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"image\": \"<string>\",\n \"mode\": \"full\",\n \"idempotency_key\": \"<string>\",\n \"callback_url\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.moda.app/v1/media/layerize-assets")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"image\": \"<string>\",\n \"mode\": \"full\",\n \"idempotency_key\": \"<string>\",\n \"callback_url\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"id": "task_01HT9WK8N3M2J4A5Z6P7Q8R9TV",
"kind": "design",
"status": "queued",
"attempt": 123,
"max_attempts": 123,
"attempts_started": 123,
"links": {
"self": "<string>",
"events": "<string>",
"cancel": "<string>",
"canvas": "<string>"
},
"created_at": "<string>",
"started_at": "<string>",
"completed_at": "<string>",
"progress": {
"percent": 123,
"step": "<string>",
"message": "<string>"
},
"first_started_at": "<string>",
"input": {},
"result": {
"canvas_id": "<string>",
"canvas_url": "<string>",
"canvas_name": "<string>",
"conversation_id": "<string>",
"source_canvas_id": "<string>",
"source_canvas_url": "<string>",
"theme_canvas_id": "<string>",
"export": {
"url": "<string>",
"format": "<string>",
"status": "<string>",
"page_count": 123
}
},
"error": {},
"credits": {
"credits_used": 123,
"credits_remaining": 123
},
"retry_after_ms": 123
}{
"type": "invalid_request",
"code": "<string>",
"message": "<string>",
"doc_url": "<string>",
"request_id": "<string>",
"causes": [
"<unknown>"
],
"details": {},
"retry_after_ms": 123,
"retryable": true
}{
"type": "invalid_request",
"code": "<string>",
"message": "<string>",
"doc_url": "<string>",
"request_id": "<string>",
"causes": [
"<unknown>"
],
"details": {},
"retry_after_ms": 123,
"retryable": true
}{
"type": "invalid_request",
"code": "<string>",
"message": "<string>",
"doc_url": "<string>",
"request_id": "<string>",
"causes": [
"<unknown>"
],
"details": {},
"retry_after_ms": 123,
"retryable": true
}{
"type": "invalid_request",
"code": "<string>",
"message": "<string>",
"doc_url": "<string>",
"request_id": "<string>",
"causes": [
"<unknown>"
],
"details": {},
"retry_after_ms": 123,
"retryable": true
}{
"type": "invalid_request",
"code": "<string>",
"message": "<string>",
"doc_url": "<string>",
"request_id": "<string>",
"causes": [
"<unknown>"
],
"details": {},
"retry_after_ms": 123,
"retryable": true
}{
"type": "invalid_request",
"code": "<string>",
"message": "<string>",
"doc_url": "<string>",
"request_id": "<string>",
"causes": [
"<unknown>"
],
"details": {},
"retry_after_ms": 123,
"retryable": true
}{
"type": "invalid_request",
"code": "<string>",
"message": "<string>",
"doc_url": "<string>",
"request_id": "<string>",
"causes": [
"<unknown>"
],
"details": {},
"retry_after_ms": 123,
"retryable": true
}{
"type": "invalid_request",
"code": "<string>",
"message": "<string>",
"doc_url": "<string>",
"request_id": "<string>",
"causes": [
"<unknown>"
],
"details": {},
"retry_after_ms": 123,
"retryable": true
}Authorizations
API key from Settings > Developer > REST API
Headers
Calendar-dated API version pin. New integrations should pin 2026-05-01 to opt into the newest response shapes. For back-compat the server also accepts requests with no header and resolves them to the current default (today: 2026-04-12); that default advances on each sunset date. Any unsupported value returns 400 unsupported_version.
2026-04-12, 2026-05-01 "2026-05-01"
Body
Accessible file_ upload reference or HTTP(S) raster image URL.
1 - 8192Full reconstruction, or text separation over the remaining artwork.
full, text 1 - 2551 - 2048Response
Successful Response
Canonical wire-format for every async design operation.
All consumers -- REST, webhooks, SSE, MCP -- serialize through
Task.from_db() so the shape is always consistent.
Prefixed task_... identifier.
^task_[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$"task_01HT9WK8N3M2J4A5Z6P7Q8R9TV"
Discriminator for the kind-specific result payload.
design, export, remix, brand_kit_extract, layerize_assets Current lifecycle status.
queued, running, succeeded, failed, canceled, expired Current attempt number (1-based).
Maximum attempts before dead-lettering.
Number of attempts STARTED (claimed by a worker) — never attempts completed. 0 means the task has never been claimed. The claim itself increments the counter, so a task on its first attempt reports 1 while RUNNING and stays at 1 through that attempt's retry backoff. The retry signal is therefore status == "queued" && attempts_started >= 1 (a queued task that has already burned an attempt), NOT >= 2. Unlike attempt, this is the raw counter and is not floored to 1.
HATEOAS links for this task.
Show child attributes
Show child attributes
ISO 8601 timestamp.
ISO 8601 timestamp.
ISO 8601 timestamp.
Live progress for running tasks. Null when not applicable.
Show child attributes
Show child attributes
ISO 8601 timestamp of when the FIRST attempt was claimed. null means unknown — either the task has never started, or it predates this field being recorded. started_at remains the CURRENT attempt's start, so on a retried task the two differ and the gap is the real wall-clock age of the work.
Sanitized echo of the original request.
Result payload of a design or remix task.
Populated when status is succeeded, and partially populated for
some in-flight tasks (a remix surfaces its source canvas before the design
task finishes). Extra keys are permitted so synchronous-completion payloads
pass through without schema churn.
- TaskResult
- PublicLayerizeAssetsResult
Show child attributes
Show child attributes
Error info: {message, retryable, attempt}. Present for failed tasks, and also for a NON-terminal task that carries an error from an earlier attempt — on a non-terminal task this always describes the PREVIOUS, already-dead attempt, never the one currently in flight. attempt is the attempts_started value the error is tied to (0 when the failure happened before any claim).
Credit usage. Present only for completed tasks when billing is enabled.
Show child attributes
Show child attributes
Suggested milliseconds to wait before the next poll. Null for terminal tasks.