Retouch4me Cloud AI Retouching API

for Retouch4me AI Image Retouching

This documentation describes an AI-powered retouching platform for teams that need an automated photo retouching API and a cloud-based AI retouching service for portrait retouching, batch processing, and photo post-production workflows. Start with the token instructions below, review the task format, use job status polling as the baseline integration approach, check the webhook integration guide only if you need asynchronous callbacks, and jump to the examples.

General Information

The media server is available at retoucher.hz.labs.retouch4.me.

All API requests are made to /api/v1/<route>, for example:

https://retoucher.hz.labs.retouch4.me/api/v1/retoucher/getFile/s0me-very-l0ng-1d

Retouch Token

Obtain the Retouch token by visiting https://retouch4.me/token_page with an authorized and verified Retouch4me account.

The token is required for all cloud retouching requests that submit or query user work.

Common Error Codes

These error codes can appear across cloud retouching requests when the token is invalid, the task is rejected, or the service cannot complete the requested operation.

The general retouching pipeline is as follows:

  1. The image processing task is submitted via /retoucher/start
  1. While processing is pending, you can request the current status at /retoucher/status/{id}
  1. If the process completes successfully, the result can be fetched from /retoucher/getFile/{id}

Retrieve Balance https://3dlutcreator.com/api/retouch/v1/balance

Before submitting a processing task, you can check how many cloud retouch credits remain for the current user.

Protocol HTTP
Method POST
contentType multipart/form-data

The request must be sent to:

https://3dlutcreator.com/api/retouch/v1/balance

The following fields are expected in the request body:

Example request:

curl --location 'https://3dlutcreator.com/api/retouch/v1/balance' \
--header 'Accept: application/json' \
--form 'retouchtoken="reto_x7K2mQ9Lp4Nz8Vb1cR5Ty0Hs"' \
--form 'modes[]="professional"'

Successful response:

{
  "status": 200,
  "remaining": {
    "professional": 5
  }
}

If the token is invalid or expired, the endpoint returns a 401 error with an explanatory message.


Register Task /retoucher/start

Request Description

Protocol HTTP
Method POST
contentType multipart/form-data

The following fields are expected in the request body:

Processing

  1. The task is registered on the server and receives a unique ID
  1. User token is verified
  1. The task is queued for processing and returns the task ID

Successful Response

If the request is successful, the task is queued, and the server returns

a JSON object with the following fields:

Possible Errors

If the request is missing a file, the server returns a 400 error with message="No file uploaded"

If there are issues on the server, it returns a 500 error with an error message.

If the CRM returns a 4xx error, a 4xx error code and message="Token issue" are returned.

If the server cannot communicate with the CRM or returns a 200 status, processing continues.


Retouch Status Request /retoucher/status/{id}

Protocol HTTP
Method GET

Request Description

GET request, id is passed in the URL.

Example request:

https://retoucher.hz.labs.retouch4.me/api/v1/retoucher/status/s0me-very-l0ng-1d

Successful Response

In case of a successful request, the server returns JSON with the following fields:

Possible Errors

If no task with the given id is found, the server returns a 404 error

If there is a server error, a 500 error is returned

Notes

It's better not to request status updates too frequently, such as using a 1-second interval


Get Retouch Result /retoucher/getFile/{id}

Request Description

GET request, id is passed as a param in the URL (similar to the status request).

Successful Response

Depending on the task, this endpoint returns:

This documentation covers tasks with mode=professional, so the response is expected to be a ZIP archive.

Possible Errors

If no task with the given id is found, the server returns a 404 error

If there is a server error, a 500 error is returned

Notes

The /retoucher/getFile request should be made only after receiving a status with state="completed". Even if progress=100, the result may not yet be saved in a file, and the server won’t be able to return it.

It’s also not possible to request old files, as the results are stored for only 24 hours.

Limitations

Before submitting a retouch request, you should check the file (photo or archive) for limitations. The list of limitations can be obtained with a GET request to /info/limits

This endpoint returns JSON in the following format:

{

image: {

formats: ["png", "jpg", "jpeg"],

maxFileSizeInMB: 100,

maxMegapixels: 250

},

archive: {

formats: ["zip"]

}

}

The JSON above indicates that the allowed image formats are png, jpg, jpeg, the maximum file size is 100 MB, and the image resolution should not exceed 250 megapixels.

If these limitations are violated, the task may not be processed.

At the moment, this endpoint is not available in production.

FAQ

How do I get a retouch token?

Use the token acquisition instructions above to obtain a valid token for every cloud retouch request.

How do I submit a retouching task?

Send a multipart request to /retoucher/start with the source image, token, and JSON payload. The payload structure is described on the task format page.

How do I check processing progress?

Poll /retoucher/status/{id} until the task reaches completed or failed.

How do I download the result?

After completion, download the final file or layered archive from /retoucher/getFile/{id}.

Which formats are supported?

The service accepts common image formats such as JPEG and PNG and can return either a flat retouched image or a ZIP archive with layers, depending on the payload.

Complete Examples

These examples use one source photo and two task payloads: one returns a final retouched JPEG, and the other returns a layered ZIP archive.

Example 1 - All-In-One Retouching

This example sends a flat task and receives one final JPEG file.

Important: the final look depends on the JSON payload. The same source image can produce a lighter, balanced, or stronger retouch depending on the plugin parameters you choose.

Source image

Sample source image

Download source image

Payload presets: use the same /retoucher/start request and replace only the JSON in the payload field.

Balanced retouching JSON: a moderate preset for a clean, commercial result.

Note: Dodge Burn uses Scale: 2 in this example for more detailed work.

{
  "mode": "professional",
  "tasks": [
    {"Plugin": "Heal", "Scale": 0, "Alpha1": 1.0},
    {"Plugin": "Fabric", "Scale": 0, "Alpha1": 0.39},
    {"Plugin": "Eye Vessels", "Scale": 0, "Alpha1": 1.0},
    {"Plugin": "Eye Brilliance", "Scale": 0, "Alpha1": 0.5},
    {"Plugin": "White Teeth", "Scale": 0, "Alpha1": 0.25, "Alpha2": 0.25},
    {"Plugin": "Dodge Burn", "Scale": 2, "Alpha1": 1.0, "Alpha2": 0.2},
    {"Plugin": "Skin Tone", "Scale": 0, "Alpha1": 1.0, "Alpha2": 1.0},
    {"Plugin": "Portrait Volumes", "Scale": 0, "Alpha1": 0.5}
  ]
}

Slight retouching JSON: lower values for a softer result that keeps more of the original skin texture and contrast.

{
  "mode": "professional",
  "tasks": [
    {"Plugin": "Heal", "Scale": 0, "Alpha1": 0.8},
    {"Plugin": "Eye Vessels", "Scale": 0, "Alpha1": 0.35},
    {"Plugin": "White Teeth", "Scale": 0, "Alpha1": 0.1, "Alpha2": 0.08},
    {"Plugin": "Dodge Burn", "Scale": 2, "Alpha1": 0.35, "Alpha2": 0.08},
    {"Plugin": "Skin Tone", "Scale": 0, "Alpha1": 0.35, "Alpha2": 0.35},
    {"Plugin": "Portrait Volumes", "Scale": 0, "Alpha1": 0.18}
  ]
}

Heavy retouching JSON: higher values for a stronger polished look with more visible cleanup and shaping.

{
  "mode": "professional",
  "tasks": [
    {"Plugin": "Heal", "Scale": 0, "Alpha1": 0.9},
    {"Plugin": "Fabric", "Scale": 0, "Alpha1": 0.75},
    {"Plugin": "Eye Vessels", "Scale": 0, "Alpha1": 0.9},
    {"Plugin": "Eye Brilliance", "Scale": 0, "Alpha1": 0.85},
    {"Plugin": "White Teeth", "Scale": 0, "Alpha1": 0.65, "Alpha2": 0.55},
    {"Plugin": "Dodge Burn", "Scale": 2, "Alpha1": 1.35, "Alpha2": 0.35},
    {"Plugin": "Skin Tone", "Scale": 0, "Alpha1": 1.15, "Alpha2": 1.15},
    {"Plugin": "Portrait Volumes", "Scale": 0, "Alpha1": 0.9}
  ]
}

Start request: submit the source image, token, and inline JSON payload. Replace the payload with whichever preset matches your preferred look.

Baseline approach: submit the task, then poll /retoucher/status/{id} until the job is complete.

Webhook option: if you want asynchronous completion callbacks instead of relying only on polling, add the optional hook form field and follow the webhook integration guide. Before using webhooks, send the list of webhook domains to relu@retouch4.me so they can be approved.

curl --location 'https://retoucher.hz.labs.retouch4.me/api/v1/retoucher/start' \
  --form 'file=@"DSC_6229_Sample.jpg"' \
  --form 'token="retoexampletokenvaluex83n4j2k9q7m5p1"' \
  --form-string 'payload={"mode":"professional","tasks":[{"Plugin":"Heal","Scale":0,"Alpha1":1.0},{"Plugin":"Fabric","Scale":0,"Alpha1":0.39},{"Plugin":"Eye Vessels","Scale":0,"Alpha1":1.0},{"Plugin":"Eye Brilliance","Scale":0,"Alpha1":0.5},{"Plugin":"White Teeth","Scale":0,"Alpha1":0.25,"Alpha2":0.25},{"Plugin":"Dodge Burn","Scale":2,"Alpha1":1.0,"Alpha2":0.2},{"Plugin":"Skin Tone","Scale":0,"Alpha1":1.0,"Alpha2":1.0},{"Plugin":"Portrait Volumes","Scale":0,"Alpha1":0.5}]}'
curl --location "https://retoucher.hz.labs.retouch4.me/api/v1/retoucher/start" --form "file=@DSC_6229_Sample.jpg" --form "token=retoexampletokenvaluex83n4j2k9q7m5p1" --form-string "payload={\"mode\":\"professional\",\"tasks\":[{\"Plugin\":\"Heal\",\"Scale\":0,\"Alpha1\":1.0},{\"Plugin\":\"Fabric\",\"Scale\":0,\"Alpha1\":0.39},{\"Plugin\":\"Eye Vessels\",\"Scale\":0,\"Alpha1\":1.0},{\"Plugin\":\"Eye Brilliance\",\"Scale\":0,\"Alpha1\":0.5},{\"Plugin\":\"White Teeth\",\"Scale\":0,\"Alpha1\":0.25,\"Alpha2\":0.25},{\"Plugin\":\"Dodge Burn\",\"Scale\":2,\"Alpha1\":1.0,\"Alpha2\":0.2},{\"Plugin\":\"Skin Tone\",\"Scale\":0,\"Alpha1\":1.0,\"Alpha2\":1.0},{\"Plugin\":\"Portrait Volumes\",\"Scale\":0,\"Alpha1\":0.5}]}"

Start response: the API returns a task id that is later used for polling and file download.

{
  "status": 200,
  "id": "jpeg-example-job-id",
  "retouchQuota": 999
}

Status request: poll the task id until the state becomes completed.

curl --location 'https://retoucher.hz.labs.retouch4.me/api/v1/retoucher/status/jpeg-example-job-id'

Status response: real in-progress example.

{
  "status": 200,
  "state": "active",
  "progress": 5,
  "reason": "",
  "attempt": 1,
  "currentStep": "downloading",
  "maxAttempts": 3,
  "pluginName": "",
  "expireDate": "2026-03-18T21:58:47.836Z"
}

Status response: real completed example.

{
  "status": 200,
  "state": "completed",
  "progress": 100,
  "reason": "",
  "attempt": 1,
  "currentStep": "uploading",
  "maxAttempts": 3,
  "pluginName": "",
  "expireDate": "2026-03-18T21:29:16.144Z"
}

Note: in the current API, currentStep may keep the last internal stage name even when state is already completed.

Download request: fetch the finished JPEG file by task id.

curl --location 'https://retoucher.hz.labs.retouch4.me/api/v1/retoucher/getFile/jpeg-example-job-id' \
  --output DSC_6229_Cloud_Retouch.jpg
curl --location "https://retoucher.hz.labs.retouch4.me/api/v1/retoucher/getFile/jpeg-example-job-id" --output DSC_6229_Cloud_Retouch.jpg

Complete Workflow Scripts

These examples cover the whole photo retouching flow: submit the source image, poll the job status until completion, and download the final JPEG.

Set RETOUCH_TOKEN before running them. Each example uses the balanced all-in-one payload shown above and writes the result file next to the sample image.

Runtime: PHP with cURL enabled.

Download PHP example

<?php
declare(strict_types=1);

const API_BASE = 'https://retoucher.hz.labs.retouch4.me/api/v1/retoucher';

$token = getenv('RETOUCH_TOKEN') ?: '<your_token_here>';
$sourceFile = __DIR__ . '/../DSC_6229_Sample.jpg';
$outputFile = __DIR__ . '/../retouch_result_php.jpg';

$payload = [
    'mode' => 'professional',
    'tasks' => [
        ['Plugin' => 'Heal', 'Scale' => 0, 'Alpha1' => 1.0],
        ['Plugin' => 'Fabric', 'Scale' => 0, 'Alpha1' => 0.39],
        ['Plugin' => 'Eye Vessels', 'Scale' => 0, 'Alpha1' => 1.0],
        ['Plugin' => 'Eye Brilliance', 'Scale' => 0, 'Alpha1' => 0.5],
        ['Plugin' => 'White Teeth', 'Scale' => 0, 'Alpha1' => 0.25, 'Alpha2' => 0.25],
        ['Plugin' => 'Dodge Burn', 'Scale' => 2, 'Alpha1' => 1.0, 'Alpha2' => 0.2],
        ['Plugin' => 'Skin Tone', 'Scale' => 0, 'Alpha1' => 1.0, 'Alpha2' => 1.0],
        ['Plugin' => 'Portrait Volumes', 'Scale' => 0, 'Alpha1' => 0.5],
    ],
];

$jobId = startJob($token, $sourceFile, $payload);
$status = waitForCompletion($jobId);
downloadResult($jobId, $outputFile);

function startJob(string $token, string $sourceFile, array $payload): string
{
    $response = requestJson(
        API_BASE . '/start',
        [
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => [
                'file' => new CURLFile($sourceFile),
                'token' => $token,
                'payload' => json_encode($payload, JSON_UNESCAPED_SLASHES),
            ],
        ]
    );

    return (string) $response['id'];
}

function waitForCompletion(string $jobId): array
{
    while (true) {
        $response = requestJson(API_BASE . '/status/' . rawurlencode($jobId));

        if (($response['state'] ?? '') === 'completed') {
            return $response;
        }

        if (($response['state'] ?? '') === 'failed') {
            throw new RuntimeException('Job failed: ' . ($response['reason'] ?? 'unknown'));
        }

        sleep(5);
    }
}

function downloadResult(string $jobId, string $outputFile): void
{
    $fp = fopen($outputFile, 'wb');
    $ch = curl_init(API_BASE . '/getFile/' . rawurlencode($jobId));
    curl_setopt_array($ch, [CURLOPT_FILE => $fp, CURLOPT_FOLLOWLOCATION => true]);
    curl_exec($ch);
    curl_close($ch);
    fclose($fp);
}

function requestJson(string $url, array $extraOptions = []): array
{
    $ch = curl_init($url);
    curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true] + $extraOptions);
    $body = curl_exec($ch);
    curl_close($ch);
    return json_decode((string) $body, true);
}

Runtime: Python 3 standard library only.

Download Python example

import json
import mimetypes
import os
import time
import urllib.request
import uuid

API_BASE = "https://retoucher.hz.labs.retouch4.me/api/v1/retoucher"
SOURCE_FILE = os.path.join(os.path.dirname(__file__), "..", "DSC_6229_Sample.jpg")
OUTPUT_FILE = os.path.join(os.path.dirname(__file__), "..", "retouch_result_python.jpg")
TOKEN = os.environ.get("RETOUCH_TOKEN", "<your_token_here>")

PAYLOAD = {
    "mode": "professional",
    "tasks": [
        {"Plugin": "Heal", "Scale": 0, "Alpha1": 1.0},
        {"Plugin": "Fabric", "Scale": 0, "Alpha1": 0.39},
        {"Plugin": "Eye Vessels", "Scale": 0, "Alpha1": 1.0},
        {"Plugin": "Eye Brilliance", "Scale": 0, "Alpha1": 0.5},
        {"Plugin": "White Teeth", "Scale": 0, "Alpha1": 0.25, "Alpha2": 0.25},
        {"Plugin": "Dodge Burn", "Scale": 2, "Alpha1": 1.0, "Alpha2": 0.2},
        {"Plugin": "Skin Tone", "Scale": 0, "Alpha1": 1.0, "Alpha2": 1.0},
        {"Plugin": "Portrait Volumes", "Scale": 0, "Alpha1": 0.5},
    ],
}

def start_job():
    boundary = f"----RetouchBoundary{uuid.uuid4().hex}"
    body = build_multipart_body(
        boundary,
        [("token", TOKEN), ("payload", json.dumps(PAYLOAD, separators=(",", ":")))],
        [("file", SOURCE_FILE)],
    )
    request = urllib.request.Request(
        f"{API_BASE}/start",
        data=body,
        method="POST",
        headers={"Content-Type": f"multipart/form-data; boundary={boundary}"},
    )
    with urllib.request.urlopen(request) as response:
        return json.loads(response.read().decode("utf-8"))["id"]

def wait_for_completion(job_id):
    while True:
        with urllib.request.urlopen(f"{API_BASE}/status/{job_id}") as response:
            data = json.loads(response.read().decode("utf-8"))
        if data.get("state") == "completed":
            return
        if data.get("state") == "failed":
            raise RuntimeError(data.get("reason", "unknown"))
        time.sleep(5)

def download_result(job_id):
    with urllib.request.urlopen(f"{API_BASE}/getFile/{job_id}") as response:
        with open(OUTPUT_FILE, "wb") as f:
            f.write(response.read())

def build_multipart_body(boundary, fields, files):
    chunks = []
    for name, value in fields:
        chunks += [
            f"--{boundary}\r\n".encode(),
            f'Content-Disposition: form-data; name="{name}"\r\n\r\n'.encode(),
            str(value).encode(),
            b"\r\n",
        ]
    for field_name, file_path in files:
        filename = os.path.basename(file_path)
        content_type = mimetypes.guess_type(filename)[0] or "application/octet-stream"
        with open(file_path, "rb") as f:
            file_content = f.read()
        chunks += [
            f"--{boundary}\r\n".encode(),
            f'Content-Disposition: form-data; name="{field_name}"; filename="{filename}"\r\n'.encode(),
            f"Content-Type: {content_type}\r\n\r\n".encode(),
            file_content,
            b"\r\n",
        ]
    chunks.append(f"--{boundary}--\r\n".encode())
    return b"".join(chunks)

job_id = start_job()
wait_for_completion(job_id)
download_result(job_id)

Runtime: Node.js 18+ with native fetch, FormData, and Blob.

Download JavaScript example

const fs = require('node:fs/promises');
const path = require('node:path');

const API_BASE = 'https://retoucher.hz.labs.retouch4.me/api/v1/retoucher';
const sourceFile = path.join(__dirname, '..', 'DSC_6229_Sample.jpg');
const outputFile = path.join(__dirname, '..', 'retouch_result_js.jpg');
const token = process.env.RETOUCH_TOKEN || '<your_token_here>';

const payload = {
  mode: 'professional',
  tasks: [
    { Plugin: 'Heal', Scale: 0, Alpha1: 1.0 },
    { Plugin: 'Fabric', Scale: 0, Alpha1: 0.39 },
    { Plugin: 'Eye Vessels', Scale: 0, Alpha1: 1.0 },
    { Plugin: 'Eye Brilliance', Scale: 0, Alpha1: 0.5 },
    { Plugin: 'White Teeth', Scale: 0, Alpha1: 0.25, Alpha2: 0.25 },
    { Plugin: 'Dodge Burn', Scale: 2, Alpha1: 1.0, Alpha2: 0.2 },
    { Plugin: 'Skin Tone', Scale: 0, Alpha1: 1.0, Alpha2: 1.0 },
    { Plugin: 'Portrait Volumes', Scale: 0, Alpha1: 0.5 },
  ],
};

async function startJob() {
  const fileBuffer = await fs.readFile(sourceFile);
  const formData = new FormData();
  formData.append('file', new Blob([fileBuffer]), path.basename(sourceFile));
  formData.append('token', token);
  formData.append('payload', JSON.stringify(payload));

  const response = await fetch(`${API_BASE}/start`, { method: 'POST', body: formData });
  const data = await response.json();
  if (!response.ok) throw new Error(JSON.stringify(data));
  return data.id;
}

async function waitForCompletion(jobId) {
  while (true) {
    const response = await fetch(`${API_BASE}/status/${encodeURIComponent(jobId)}`);
    const data = await response.json();
    if (data.state === 'completed') return;
    if (data.state === 'failed') throw new Error(data.reason || 'unknown');
    await new Promise((resolve) => setTimeout(resolve, 5000));
  }
}

async function downloadResult(jobId) {
  const response = await fetch(`${API_BASE}/getFile/${encodeURIComponent(jobId)}`);
  const buffer = Buffer.from(await response.arrayBuffer());
  await fs.writeFile(outputFile, buffer);
}

(async () => {
  const jobId = await startJob();
  await waitForCompletion(jobId);
  await downloadResult(jobId);
})();

Example 2 - Retouching with Layers

This example sends a layered task and receives a ZIP archive with separate PNG layers that can be composited in an editor.

Note: Mattifier and Clean Backdrop are not included in this layered example.

Source image

Sample source image for layered retouching

Download source image

Download layered ZIP archive

Payload JSON: layered retouching task definition.

Note: Dodge Burn uses Scale: 2 in this example for more detailed work.

{
  "mode": "professional",
  "tasks": [
    {"Plugin": "Skin Mask", "Scale": 0, "Alpha1": 1.0, "Layer": 1},
    {"Plugin": "Heal", "Scale": 0, "Alpha1": 1.0, "Layer": 1},
    {"Plugin": "Fabric", "Scale": 0, "Alpha1": 0.39, "Layer": 1},
    {"Plugin": "Eye Vessels", "Scale": 0, "Alpha1": 1.0, "Layer": 1},
    {"Plugin": "Eye Brilliance", "Scale": 0, "Alpha1": 0.5, "Layer": 1},
    {"Plugin": "White Teeth", "Scale": 0, "Alpha1": 0.25, "Alpha2": 0.25, "Layer": 1},
    {"Plugin": "Dodge Burn", "Scale": 2, "Alpha1": 1.0, "Alpha2": 0.2, "Layer": 1},
    {"Plugin": "Skin Tone", "Scale": 0, "Alpha1": 1.0, "Alpha2": 1.0, "Layer": 1},
    {"Plugin": "Portrait Volumes", "Scale": 0, "Alpha1": 0.5, "Layer": 1}
  ]
}

Start request: submit the source image, token, and layered payload with Layer: 1.

Baseline approach: submit the layered task, then poll /retoucher/status/{id} until the archive is ready.

Webhook option: the same optional hook form field can be used for layered jobs when you want a completion callback instead of polling only. Before using webhooks, send the list of webhook domains to relu@retouch4.me so they can be approved.

curl --location 'https://retoucher.hz.labs.retouch4.me/api/v1/retoucher/start' \
  --form 'file=@"DSC_6229_Sample.jpg"' \
  --form 'token="retoexampletokenvaluex83n4j2k9q7m5p1"' \
  --form-string 'payload={"mode":"professional","tasks":[{"Plugin":"Skin Mask","Scale":0,"Alpha1":1.0,"Layer":1},{"Plugin":"Heal","Scale":0,"Alpha1":1.0,"Layer":1},{"Plugin":"Fabric","Scale":0,"Alpha1":0.39,"Layer":1},{"Plugin":"Eye Vessels","Scale":0,"Alpha1":1.0,"Layer":1},{"Plugin":"Eye Brilliance","Scale":0,"Alpha1":0.5,"Layer":1},{"Plugin":"White Teeth","Scale":0,"Alpha1":0.25,"Alpha2":0.25,"Layer":1},{"Plugin":"Dodge Burn","Scale":2,"Alpha1":1.0,"Alpha2":0.2,"Layer":1},{"Plugin":"Skin Tone","Scale":0,"Alpha1":1.0,"Alpha2":1.0,"Layer":1},{"Plugin":"Portrait Volumes","Scale":0,"Alpha1":0.5,"Layer":1}]}'
curl --location "https://retoucher.hz.labs.retouch4.me/api/v1/retoucher/start" --form "file=@DSC_6229_Sample.jpg" --form "token=retoexampletokenvaluex83n4j2k9q7m5p1" --form-string "payload={\"mode\":\"professional\",\"tasks\":[{\"Plugin\":\"Skin Mask\",\"Scale\":0,\"Alpha1\":1.0,\"Layer\":1},{\"Plugin\":\"Heal\",\"Scale\":0,\"Alpha1\":1.0,\"Layer\":1},{\"Plugin\":\"Fabric\",\"Scale\":0,\"Alpha1\":0.39,\"Layer\":1},{\"Plugin\":\"Eye Vessels\",\"Scale\":0,\"Alpha1\":1.0,\"Layer\":1},{\"Plugin\":\"Eye Brilliance\",\"Scale\":0,\"Alpha1\":0.5,\"Layer\":1},{\"Plugin\":\"White Teeth\",\"Scale\":0,\"Alpha1\":0.25,\"Alpha2\":0.25,\"Layer\":1},{\"Plugin\":\"Dodge Burn\",\"Scale\":2,\"Alpha1\":1.0,\"Alpha2\":0.2,\"Layer\":1},{\"Plugin\":\"Skin Tone\",\"Scale\":0,\"Alpha1\":1.0,\"Alpha2\":1.0,\"Layer\":1},{\"Plugin\":\"Portrait Volumes\",\"Scale\":0,\"Alpha1\":0.5,\"Layer\":1}]}"

Start response: the API returns a task id for the layered archive job.

{
  "status": 200,
  "id": "layers-example-job-id",
  "retouchQuota": 999
}

Check Processing State

Status request: poll the layered task until the archive is ready.

curl --location 'https://retoucher.hz.labs.retouch4.me/api/v1/retoucher/status/layers-example-job-id'

Status response: real completed layered-job example.

{
  "status": 200,
  "state": "completed",
  "progress": 100,
  "reason": "",
  "attempt": 1,
  "currentStep": "uploading",
  "maxAttempts": 3,
  "pluginName": "",
  "expireDate": "2026-03-18T21:29:19.055Z"
}

Download Result File

Download request: fetch the finished ZIP archive by task id.

curl --location 'https://retoucher.hz.labs.retouch4.me/api/v1/retoucher/getFile/layers-example-job-id' \
  --output DSC_6229_Cloud_Retouch_Layers.zip
curl --location "https://retoucher.hz.labs.retouch4.me/api/v1/retoucher/getFile/layers-example-job-id" --output DSC_6229_Cloud_Retouch_Layers.zip

Layer Previews

The layered archive contains separate PNG files that can be composited in Photoshop or another editor. Use the blend mode from the file name when applicable.

Skin Mask

Skin Mask layer

Use this mask as a selection helper to confine color and texture work to skin areas.

Download layer

Heal

Heal layer

Use this normal layer for blemish cleanup and removal of small skin distractions.

Download layer

Fabric

Fabric layer

Use this normal layer to soften wrinkles and clean texture on clothing and fabric details.

Download layer

Eye Vessels

Eye Vessels layer

Use this normal layer to reduce visible veins and redness in the whites of the eyes.

Download layer

Eye Brilliance

Eye Brilliance layer

Use this normal layer to enhance iris detail and add subtle brightness to the eyes.

Download layer

White Teeth

White Teeth layer

Use this normal layer to whiten and slightly brighten teeth while keeping the effect adjustable.

Download layer

Dodge Burn

Dodge Burn layer

Use this soft-light layer for local light and shadow shaping on skin and facial features.

Download layer

Skin Tone

Skin Tone layer

Use this soft-light layer to unify skin color and reduce uneven tone transitions.

Download layer

Portrait Volumes

Portrait Volumes layer

Use this soft-light layer to emphasize shape and volume in the face and portrait contours.

Download layer