Style Soul API
Add a "Use my Style Soul" button to your store or app. A shopper who has a ZukMe Style Soul connects it in a few taps, chooses exactly what to share and for how long, and arrives already understood: their palette, their style, what they love and what they always pass on. No upload, no quiz, and you never handle their photo.
Quickstart
Ask
POST /souls/connect
freeShopper says yes
on their own phone
Read the Style Soul
GET /souls/profile
freeVerdict
POST /souls/verdict
1 look- 1Create an API key in the API Dashboard. Connecting and reading Style Souls is free; only verdicts use looks.
- 2Call
POST /api/v1/souls/connectwith your business name and what you'd like to see. Show the returned QR code, or openconnectUrlin a new window. - 3Poll
GET /api/v1/souls/connect?requestId=…every 2 to 3 seconds. When the shopper approves, the response carries asoulToken, exactly once. Store it server-side. - 4Call
GET /api/v1/souls/profilewith the token to style, sort or recommend for them, andPOST /api/v1/souls/verdictto ask whether a piece suits them.
User experience flow
Taps “Use my Style Soul” on your site, or scans your QR code in store
You show a QR code or open a ZukMe window. Nothing about the shopper is shared yet.
→ POST /api/v1/souls/connect
Decides on ZukMe, on their own phone
They sign in, pick one of their Style Souls, see your business name and each thing you asked for, untick anything they don't want to share, and choose how long: this visit, 30 days, or until they revoke it.
Comes back already understood
Their palette, style and what their Style Soul has learned shape what you show them first.
→ GET /api/v1/souls/profile
Asks “is this me?” on any piece
An honest answer, tied to their palette and taste. It is allowed to say no.
→ POST /api/v1/souls/verdict
Buys (or returns), and their Style Soul learns
Only with the separate "events" permission. They see your entries in their Style Soul's Journal and can remove them.
→ POST /api/v1/souls/events
Base URL
https://zukme.comAll endpoints below are relative to this base URL.
Authentication
Every request needs your API key as a bearer token. Create and manage keys in the API Dashboard. The raw key is shown once; only its hash is stored.
Authorization: Bearer zk_live_<your key>Missing, malformed, or revoked key → 401:
{ "error": "Invalid or missing API key. Pass it as \"Authorization: Bearer zk_live_...\"." }Rate limits
30 requests per minute per key (submit and poll both count). Over the limit → 429:
{ "error": "Rate limit exceeded.", "retryAfterSeconds": 12 }What you can and can't see
| Field | Type | Description |
|---|---|---|
profile | scope | Style title and subtitle, palette (hex + name), style keywords, a few lines of their style reading, and how deep the Style Soul is (Seed, Sprout, Formed, Deep). Always included. |
taste | scope | Adds their style categories and what their Style Soul has learned from their own choices: colours, pieces and silhouettes they say yes to or pass on, each with how often it was seen. |
fit | scope | Adds a size band (for example "M" or "Petite"). Never height or measurements. |
events | scope | Lets you send back what they tried, liked, bought or returned in your store, so their Style Soul learns. Granted separately from reading. |
Never shared at any scope: the shopper's photo, name, face, age, gender, body details, price comfort, their Journal, or anything about other stores. The shopper may grant fewer scopes than you asked for, and can revoke your access at any time; your next call then returns 401 SOUL_TOKEN_INVALID. A token only works with the ZukMe account whose API key asked for it.
Step 1: Ask for a Style Soul
/api/v1/souls/connect| Field | Type | Description |
|---|---|---|
businessNamerequired | string | Shown to the shopper when they decide. Up to 80 characters. |
scopes | string[] | Any of profile, taste, fit, events. Defaults to ["profile"]. |
curl https://zukme.com/api/v1/souls/connect \
-X POST \
-H "Authorization: Bearer zk_live_..." \
-H "Content-Type: application/json" \
-d '{ "businessName": "Rosa Boutique", "scopes": ["profile", "taste", "fit"] }'
# {
# "ok": true,
# "requestId": "rq_7qZ1OahnyJSW",
# "connectUrl": "https://zukme.com/souls/connect/rq_7qZ1OahnyJSW",
# "qrDataUrl": "data:image/png;base64,...",
# "scopes": ["profile", "taste", "fit"],
# "expiresAt": "2026-10-10T18:15:00.000Z"
# }A request lasts 15 minutes. After that, ask again.
Step 2: Collect the token
/api/v1/souls/connect?requestId=rq_...curl "https://zukme.com/api/v1/souls/connect?requestId=rq_7qZ1OahnyJSW" \
-H "Authorization: Bearer zk_live_..."
# while waiting: { "ok": true, "status": "pending" }
# shopper said no: { "ok": true, "status": "declined" }
# too late: { "ok": true, "status": "expired" }
# approved (first read only):
# {
# "ok": true,
# "status": "approved",
# "soulToken": "st_9f2c...",
# "scopes": ["profile", "taste"],
# "tokenExpiresAt": "2026-11-09T18:01:12.000Z",
# "tokenAlreadyCollected": false
# }The token is returned once. Later reads say "tokenAlreadyCollected": true without it, so keep it server-side; never put it in a URL or a browser cookie.
Step 3: Read the Style Soul
/api/v1/souls/profilecurl https://zukme.com/api/v1/souls/profile \
-H "Authorization: Bearer zk_live_..." \
-H "X-Soul-Token: st_9f2c..."
# {
# "ok": true,
# "soul": {
# "styleTitle": "Quiet Luxe Minimalist",
# "styleSubtitle": "Clean lines, warm neutrals",
# "tags": ["minimal", "tailored"],
# "palette": [{ "hex": "#C8B79E", "name": "Sand" }],
# "reading": ["You dress like you already know..."],
# "depth": "Formed",
# "personality": [{ "trait": "Modern Classic", "description": "..." }], // taste
# "taste": [{ "kind": "leans", "text": "Leans towards grey", "evidence": 6 }] // taste
# },
# "sizeHint": "M", // fit
# "scopes": ["profile", "taste", "fit"],
# "tokenExpiresAt": "2026-11-09T18:01:12.000Z"
# }Verdict on a piece
/api/v1/souls/verdict| Field | Type | Description |
|---|---|---|
product.titlerequired | string | The piece’s name. Or send product.url alone and we read the page. |
product.imageUrl | string | A public https photo of the piece. Much better verdicts with it. |
product.category | string | e.g. dress, sneakers. |
product.price | string | e.g. "USD 89". |
product.description | string | Optional, up to 400 characters. |
product.url | string | Alternative to the fields above: the product page. |
curl https://zukme.com/api/v1/souls/verdict \
-X POST \
-H "Authorization: Bearer zk_live_..." \
-H "X-Soul-Token: st_9f2c..." \
-H "Content-Type: application/json" \
-d '{ "product": { "title": "Camel wool coat", "imageUrl": "https://yourstore.com/coat.jpg", "price": "USD 189" } }'
# {
# "ok": true,
# "verdict": "suits", // suits | maybe | not_for_you
# "headline": "A warm neutral that sits right in their palette.",
# "reasons": ["Camel echoes their Sand and Cocoa tones", "Clean tailoring matches how they dress"],
# "product": { "title": "Camel wool coat" }
# }One look per verdict, from your account's bonus looks (the same balance every /api/v1 call uses). If a verdict can't be made, the look comes straight back. Out of looks → 402 CREDITS_EXHAUSTED.
Send back what happened
/api/v1/souls/events| Field | Type | Description |
|---|---|---|
events[]required | array | Up to 20 per call. |
events[].kindrequired | string | tried_on, liked, bought or returned. |
events[].product.titlerequired | string | The piece. |
events[].product.id / category / price / imageUrl / url / size | string | Optional details. Size helps their Style Soul learn your sizing. |
curl https://zukme.com/api/v1/souls/events \
-X POST \
-H "Authorization: Bearer zk_live_..." \
-H "X-Soul-Token: st_9f2c..." \
-H "Content-Type: application/json" \
-d '{ "events": [ { "kind": "bought", "product": { "id": "sku-118", "title": "Camel wool coat", "price": "USD 189", "size": "M" } } ] }'
# { "ok": true, "recorded": 1, "rejected": [] }Entries appear in the shopper's Journal under your business name. They count for a little less than the shopper's own choices, and the shopper can remove any of them.
Give a token back
/api/v1/souls/tokencurl https://zukme.com/api/v1/souls/token \
-X DELETE \
-H "Authorization: Bearer zk_live_..." \
-H "X-Soul-Token: st_9f2c..."
# { "ok": true, "revoked": true }Errors
| Field | Type | Description |
|---|---|---|
400 | Bad Request | Missing or invalid fields. |
401 | Unauthorized | Bad API key, or SOUL_TOKEN_MISSING / SOUL_TOKEN_INVALID (expired, revoked, or granted to a different account). |
402 | Payment Required | Verdict only: CREDITS_EXHAUSTED, with your balance in the body. |
403 | Forbidden | SOUL_SCOPE_MISSING: the shopper didn’t grant what this call needs. The body lists the scopes you have. |
404 | Not Found | Unknown requestId, or SOUL_GONE (the shopper deleted that Style Soul). |
422 | Unprocessable | Verdict by URL: the product page couldn’t be read. |
429 | Too Many Requests | Rate limit exceeded. See retryAfterSeconds. |
Want to dress the shopper too?