DETERMINISTIC · NON-GENERATIVE

Documentation

Every operation is documented pixel math. The same call always returns the same image - byte for byte, and no AI ever invents content. This page is rendered from the engine's own catalog, so it can never drift from the code.

Quick start

# One call: upload, adjust, download. Output is JPEG, EXIF stripped.
curl -X POST https://retouchengine.com/v1/edit \
  -H "X-API-Key: rte_..." \
  -F "image=@photo.jpg" \
  -F 'ops=[{"op":"autotone"},{"op":"clarity","amount":0.5}]' \
  -o edited.jpg

Response headers tell you exactly what happened: X-Ops-Applied (the applied chain), X-Elapsed-Ms, X-Output-Size, X-Key-Usage (today's usage / your daily limit).

Authentication

Send your key in the X-API-Key header. Create a profile to get a trial key instantly (25 requests/day): upgrade any time on Pricing. Missing/invalid key → 401 · over daily limit → 429 (resets midnight UTC).

The edit call

POST /v1/edit, multipart form: image (JPEG/PNG/WebP, ≤ 40 MB, ≤ 40 MP), ops (JSON list, up to 20 operations, applied in order), optional preset (runs before ops), quality (50–100, default 92) and max_edge (downscale the long edge, e.g. 2000 for web delivery). Nothing is ever stored on our servers.

Operations

Tone

exposure

Exposure in EV stops (-2..2) with a soft highlight roll-off, never blows out.

paramrangedefault
ev-2.0 … 2.00.0Exposure in EV stops; + never blows out

contrast

Contrast -1..1 as an S-curve around the midpoint (0.5).

paramrangedefault
amount-1.0 … 1.00.0S-curve around the midpoint

highlights

Highlights -1..1: negative recovers blown areas, positive lifts them.

paramrangedefault
amount-1.0 … 1.00.0− recovers blown areas, + lifts them

shadows

Shadows -1..1: positive opens dark areas without greying true black.

paramrangedefault
amount-1.0 … 1.00.0+ opens dark areas without greying black

blackpoint

Black point 0..0.25: adds depth to flat images (0.06 is the classic).

paramrangedefault
amount0.0 … 0.250.0Depth for flat images

autotone

Darkroom baseline: careful levels (1.6x cap, flat scenes skipped),

paramrangedefault
strength0.0 … 1.01.0Darkroom baseline: levels+gamma+S-curve+vibrance

gamma

Raw gamma 0.5..2.0 (1 = unchanged).

paramrangedefault
value0.5 … 2.01.0Raw gamma

Color

saturation

Saturation -1..1 (-1 = black & white).

paramrangedefault
amount-1.0 … 1.00.0-1 = black & white

vibrance

Vibrance -1..1: boosts ONLY muted colors, skin and saturated areas are barely touched.

paramrangedefault
amount-1.0 … 1.00.0Boosts only muted colors

warmth

Warmth -1..1: + toward golden, − toward cool. Channel gains, luma-preserving.

paramrangedefault
amount-1.0 … 1.00.0+ golden, − cool (luma-preserving)

tint

Tint -1..1: + toward magenta, − toward green (luma-preserving).

paramrangedefault
amount-1.0 … 1.00.0+ magenta, − green

mono

Classic black & white with a gentle tone curve.

paramrangedefault
enabledboolTrueClassic black & white

Detail

clarity

Darkroom clarity v2: luminance-only, midtone-weighted, delta cap

paramrangedefault
amount0.0 … 1.00.5Luminance clarity with shadow protection and halo cap

sharpen

Sharpen 0..1 (unsharp mask on luminance, fine radius).

paramrangedefault
amount0.0 … 1.00.3Unsharp mask on luminance

denoise

Denoise 0..1 (edge-preserving bilateral, mild).

paramrangedefault
amount0.0 … 1.00.3Edge-preserving denoise

Geometry

crop

Crop [x0,y0,x1,y1] in pixels (clamped; min 100×100).

paramrangedefault
rectrectNone[x0,y0,x1,y1] in pixels

aspect

Crop to aspect ('3:2','2:3','1:1','4:5','16:9'), anchor center/top.

paramrangedefault
ratio3:2,2:3,1:1,4:5,16:93:2Crop to aspect ratio
anchorcenter,topcenterAnchor

rotate

Free rotation -15..15°: auto-cropped to content (no black wedges).

paramrangedefault
degrees-15.0 … 15.00.0Free rotation, auto-cropped

flip

Mirror: horizontal | vertical.

paramrangedefault
directionhorizontal,verticalhorizontalMirror

Finish

vignette

Vignette 0..1: softly darkened corners, the subject untouched.

paramrangedefault
amount0.0 … 1.00.3Darkened corners

grain

Film grain 0..1: deterministic (fixed seed), luminance grain.

paramrangedefault
amount0.0 … 1.00.2Deterministic film grain
seed0 … 99997Fixed seed = identical grain

Branding

text

Poster-style caps overlay in white with a soft dark fade, reads on any background.

paramrangedefault
textstrThe text (caps, ≤80 chars)
positionbottom,top,top-left,top-right,bottom-left,bottom-rightbottomPlacement
size0.0 … 0.150.0Text height vs. width (0 = auto)

watermark

Tiled diagonal watermark, visible enough to protect, light enough to ignore.

paramrangedefault
textstrWatermark text (≤60 chars)
opacity0.03 … 0.50.16Strength
size0.012 … 0.080.028Text height vs. width
angle-45.0 … 45.0-22.0Tile angle

logo

Overlay an uploaded PNG logo (its alpha is the artwork) in a corner or centered.

paramrangedefault
positionbottom,top,top-left,top-right,bottom-left,bottom-rightbottom-rightPlacement
size0.0 … 0.30.0Logo height vs. width (0 = auto)
opacity0.1 … 1.00.95Opacity
modewhite,originalwhitewhite = monochrome w. shadow · original = the PNG's own colors

People

person_light

Brighten only the person: alpha-bounded screen curve, by construction

paramrangedefault
ev0.0 … 1.00.35Light ONLY on the person (model mask)

Cutout

cutout

Cut the subject out and place it on a clean background. Removes only, never invents.

paramrangedefault
modelu2net,isnet-general-use,silueta,u2net_human_segu2netWhich mask model finds the subject
backgroundstrwhiteColour name or hex, or 'transparent' with format=png
edge0.0 … 1.00.5Pushes the half-transparent grey haze to zero; keeps real soft edges
shrink0.0 … 6.01.0Pulls the edge in by N pixels so no old background is left in the rim
feather0.0 … 8.01.0Softens the cut so it does not look stamped out
despill0.0 … 1.00.8Removes the old background colour from edge pixels (no grey halo)
keep_parts0.0 … 1.00.15Drops loose blobs smaller than this share of the main subject; 0 keeps everything

fit

Pad to a marketplace format so the subject fills a set share of the frame.

paramrangedefault
ratiostr1:1Target frame, e.g. 1:1, 4:5, 3:2, 16:9
fill0.3 … 1.00.85How much of the frame the subject fills
backgroundstrwhitePadding colour, name or hex
anchorcenter,top,bottomcenterWhere the subject sits in the frame

Presets

Named recipes, run alone or as a starting point before your own ops.

baseline

autotone

punchy

autotone → clarity amount=0.5 → vibrance amount=0.2

soft_portrait

autotone strength=0.6 → warmth amount=0.15 → shadows amount=0.15 → denoise amount=0.2

classic_bw

autotone → mono → clarity amount=0.35 → grain amount=0.25 → vignette amount=0.25

golden_hour

autotone → warmth amount=0.3 → vibrance amount=0.15 → vignette amount=0.2

subject_pop

autotone → person_light ev=0.35 → clarity amount=0.4

Read with AI

AI for inspection, old school code for retouch. The model looks at your photo and a style brief, then recommends concrete catalog settings. It never touches a pixel: the recommendation is a plain ops chain, and the edit that runs it is fully deterministic. Note the honest split, the recommendation may vary between calls (it is advice); the edit of a given chain never does.

# Get a recommendation (JSON chain you can inspect, store, replay)
curl -X POST https://retouchengine.com/v1/analyze -H "X-API-Key: rte_..."   -F "image=@photo.jpg"   -F "prompt=candid style editing with a bit of glamour"

# Or apply it in the same call and get the finished JPEG
curl -X POST https://retouchengine.com/v1/analyze -H "X-API-Key: rte_..."   -F "image=@photo.jpg" -F "prompt=warm editorial look"   -F "apply=true" -o edited.jpg
# X-Ops-Applied shows exactly which deterministic chain ran

Your presets

Save your own named chains and use them exactly like built-in presets.

# Save (or replace) a preset, chains may include your custom ops
curl -X POST https://retouchengine.com/v1/presets -H "X-API-Key: rte_..."   -H "Content-Type: application/json"   -d '{"name":"my_look","chain":[{"op":"autotone"},{"op":"warmth","amount":0.2}]}'

# Use it
curl -X POST https://retouchengine.com/v1/edit -H "X-API-Key: rte_..."   -F "image=@photo.jpg" -F "preset=my_look" -o edited.jpg

GET /v1/presets lists yours · DELETE /v1/presets/<name> removes one. Your presets shadow built-ins with the same name.

Custom operations (AI-written, human-owned)

Need something the catalog doesn't have, say, highlight beards? Describe it and the engine's AI writes the operation as code you can read. Every version is stored, inspectable and callable forever, and the code passes three gates before it can ever run: a static allow-list (only numpy/cv2/math, no file or network access, no reflection), a resource-capped sandbox process, and a determinism check, the op must produce byte-identical output on repeated runs.

# 1. Create an operation from natural language
curl -X POST https://retouchengine.com/v1/custom-ops -H "X-API-Key: rte_..."   -H "Content-Type: application/json"   -d '{"name":"beard_glow","request":"gently brighten beard areas on faces"}'

# 2. Use it in any chain (v optional, defaults to latest)
curl -X POST https://retouchengine.com/v1/edit -H "X-API-Key: rte_..."   -F "image=@photo.jpg"   -F 'ops=[{"op":"autotone"},{"op":"custom:beard_glow","strength":0.5}]' -o out.jpg

# 3. Iterate, every request becomes a NEW version; old ones stay callable
curl -X POST https://retouchengine.com/v1/custom-ops/beard_glow/versions   -H "X-API-Key: rte_..." -H "Content-Type: application/json"   -d '{"request":"softer edges and a touch stronger"}'
# pin an old version in a chain: {"op":"custom:beard_glow","v":1}

Custom ops receive ctx["person_alpha"] (a person mask) and ctx["face_boxes"] (face rectangles) so they can target people and faces - deterministically, never generatively. GET /v1/custom-ops lists yours with all versions; GET /v1/custom-ops/<name>/code returns the code itself. Codegen has its own daily allowance (trial 5 · starter 25 · pro 100).

Machine-readable

GET /v1/ops returns this whole catalog as JSON (params, ranges, defaults, presets, limits) - build UIs against it. OpenAPI schema at /openapi.json, interactive explorer at /api-explorer.

Errors

400Bad ops JSON, unknown op, or empty chain, message says exactly what
401Missing/invalid API key
413File over 40 MB or image over 40 MP
415Not a decodable image
429Daily limit reached (see X-Key-Usage)
503A model-backed op (person_light) is temporarily unavailable