Pixazo · Internal API Reference

Figuroos Portrait API

One call turns a customer photo into a Figuroos-style portrait and the matching die-cut figurine templates.

Base URL
https://figuroos-api.appypie.workers.dev
Auth header
X-API-Key
Status
Live · v1
00 — Quick start

Make your first call

Send a photo, get three PNGs back. Everything is a normal HTTPS request; the key goes in the X-API-Key header.

curl · full pipeline
# photo in → style portrait + 2 die-cut templates out
curl -X POST https://figuroos-api.appypie.workers.dev/v1/portrait \
  -H "X-API-Key: figuroos_live_dd8992f2d2c11cf854d7c01a" \
  -F image=@customer.jpg \
  -o result.json
Heads up: a full /v1/portrait call takes about 45 s – 3 min. Set your client timeout to at least 240 s. Images come back as short https://…/img/… URLs on our domain — open or download them directly (they auto-expire after 48 h).
01 — Authentication

API key

Send your key on every request in the X-API-Key header. Authorization: Bearer <key> is also accepted. /health is the only route that needs no key.

HeaderValue
X-API-Keyfiguroos_live_dd8992f2d2c11cf854d7c01a ← QA test key
Keep the test key internal. It’s a per-partner key and is rotatable on request — don’t publish it outside the QA team. A missing or wrong key returns 401.
02 — Endpoints

Three routes

GET/healthno key required

Liveness probe. Returns instantly.

200 OK
{ "status": "ok", "service": "Figuroos Portrait API" }
POST/v1/portraitphoto → style + both templates

The full pipeline. Send a customer photo; get back the Figuroos-style portrait plus both die-cut templates. The service reads the photo (gender, age, facial hair, headwear) so the output is faithful to the actual person.

Request — application/json or multipart/form-data

Send the photo either as a JSON body (base64) or as a file upload — both work.

JSON body
{ "image_base64": "<base64 of the photo — raw or a data: URI>",
  "strength": 0.85, "scale": 2.4 }
FieldTypeDefaultNotes
imagefilethe customer photo (JPG / PNG / WebP). Either this or image_base64.
image_base64stringraw base64 or a data: URI, as an alternative to image
strengthfloat0.85how far to push toward the illustration (0.7 truer to photo ↔ 0.95 flatter)
scalefloat2.4style strength (≈2.0–2.6 clean flat-vector; >3 distorts)
guidancefloat4.0prompt adherence
stepsint30refinement steps

Response — 200

body
{
  "style_face":       "https://figuroos-api.appypie.workers.dev/img/<id>/style_face.png",
  "template_die_cut": "https://figuroos-api.appypie.workers.dev/img/<id>/template_die_cut.png",
  "template_net":     "https://figuroos-api.appypie.workers.dev/img/<id>/template_net.png",
  "meta": {
    "subject": "an elderly man with a full white beard, a black beanie, fair skin",
    "hair_rgb": [38, 40, 47], "aniso": 1.12, "bg_fill_pct": 18.9
  }
}

meta.subject is how the service read the photo — a fast way for QA to check the input was understood correctly (right gender / age / beard).

POST/v1/diecutstyled face → both templates

Skip generation. Send an already Figuroos-styled face and get just the two die-cut templates back. Fast (~1–3 s).

FieldTypeNotes
image / image_base64file / stringa styled portrait on a plain background

Returns template_die_cut, template_net, and meta — same shape as above, minus style_face.

03 — Working with the images

The outputs

FieldWhat it is
style_faceFiguroos-style portrait, flat vector on white
template_die_cutface panel cut to the oval — transparent outside the cut line, keyline included
template_nethead net; crown/side panels filled in the sitter’s hair colour, ear-holes & glue tabs preserved

All three are PNG, print-resolution (~1600 px on the long edge). Each field is a URL on our domain; the links auto-expire after 48 h.

use a field
// each field is a URL — open it, drop it in an <img>, or download it
const data = await res.json();
img.src = data.template_die_cut;    // <img src> works as-is

# or save to a file (curl + jq)
curl -o face.png "$(jq -r .style_face result.json)"
04 — Errors

Status codes

200Success. JSON body with the images.
401Unauthorized. Missing or wrong X-API-Key. Fix the key.
422Bad image. No usable face, or the upload wasn’t a valid image. Send a clear front-facing photo.
502Generation failed. Upstream hiccup — safe to retry once.
404Not found. Unknown path (only /health, /v1/portrait, /v1/diecut exist).

Every response is JSON — success and error alike. Error bodies are always { "error": "…" }, deliberately generic so they never expose anything about the backend.

05 — Limits & timing

Good to know

ItemValue
Input photofront-facing, face clearly visible, min ~512 px; JPG / PNG / WebP; ≤ 20 MB
/v1/portrait latency~45 s – 3 min (first call after idle is slower — the service wakes on demand)
/v1/diecut latency~1–3 s
Client timeoutset ≥ 240 s for /v1/portrait
OutputPNG, ~1600 px long edge, print-ready — returned as /img/… URLs that auto-expire after 48 h
Determinismgenerative — the same photo twice gives two valid but different results
06 — QA test checklist

What to verify

Grouped by area. The right-hand note is the expected result. Faithfulness (§Generation) is the one that matters most — the output must be the same person.

Auth & health

  • GET /health with no key200 · ok
  • POST /v1/portrait with no key401
  • POST with a wrong key401
  • POST with the valid key200

Happy path

  • Clean front-facing selfieopen all three returned URLs → valid, non-empty PNGs200 · 3 URLs
  • image_base64 instead of a file uploadsame photo, same result shape200
  • /v1/diecut with an already-styled face200 · 2 PNGs

Generation faithfulness — the key one

  • Elderly man with a beardoutput is an old bearded man — not a young/clean-shaven facematches
  • Woman, long hairgender, hair length & colour preservedmatches
  • Range: young/old, fair/dark skin, with & without glasses/hatmatches
  • Check meta.subject reflects the actual photoquick signal the input was read correctlyaccurate
  • No invented accessories (sunglasses, hats not in the photo)none

Output validity

  • style_face — recognisable, flat-vector, white background
  • template_die_cut — face-only oval, keyline, transparent outside the cut
  • template_net — panels in hair colour, ear-holes & tabs intact, face seated
  • All outputs ~1600 px long edgeprint-res

Edge cases (should fail gracefully, never crash)

  • Image with no face (landscape, object)422 / 502
  • Non-image file (e.g. a .txt renamed .jpg)422
  • Very small (<512 px) and very large (~20 MB) photoshandled
  • Busy / cluttered backgroundoutput is still a single clean subjectsingle
  • Group photo (multiple faces)picks the main subjectone face

Timing & leakage

  • Portrait completes within ~3 min; no premature client timeout≤ 240 s
  • Second call after idle (cold start) still succeeds200
  • Responses & error bodies expose no internal/provider names or URLsclean