Quickstart
Three steps to your first generated try-on:
- Create a FashClick account and grab a test API key from the API Keys page.
- Upload a person photo and a garment photo using the upload endpoints.
- Send the two returned IDs to
/api/b2b/v1/tryonand poll the result (or subscribe to a webhook).
All calls go to:
https://api.fashclick.ioAuthentication
FashClick uses API keys sent via the X-Api-Key header (or Authorization: Bearer fck_... if you prefer). Every request to the B2B data plane must include exactly one key.
Keys look like fck_test_xxxxx... or fck_live_xxxxx.... Never expose them in client-side code — they belong on your server only.
curl https://api.fashclick.io/api/b2b/v1/me \
-H "X-Api-Key: fck_test_YOUR_KEY_HERE"Test mode vs Live mode
Every key carries an environment label. The same endpoints, but separated request logs, credits and webhooks.
| Key prefix | Mode | Charges credits | Use for |
|---|---|---|---|
fck_test_ | Test | Yes (from your test wallet) | Local development & CI |
fck_live_ | Live | Yes (from your live wallet) | Production traffic |
Account · GET /me
Confirms your API key is valid and returns the owning account's name, plan, and remaining credit balance. Useful as a "ping" during integration testing.
curl https://api.fashclick.io/api/b2b/v1/me \
-H "X-Api-Key: fck_test_YOUR_KEY_HERE"200 response:
{
"accountName": "Acme Fashion",
"email": "ops@acme.example",
"planName": "Pro",
"creditBalance": 408,
"totalCredits": 565,
"b2bApiEnabled": true
}Upload a person image · POST /person-images
Multipart upload. The photo must be a JPG or PNG of one clearly visible person. The response gives you a personImageId you can re-use across many try-ons.
Person images are auto-deleted from FashClick storage 30 days after upload for GDPR compliance.
curl https://api.fashclick.io/api/b2b/v1/person-images \
-H "X-Api-Key: fck_test_YOUR_KEY_HERE" \
-F "file=@/path/to/person.jpg"201 response:
{
"personImageId": "5f9c9d7a-3b7b-4d6a-8c2e-9b8a5d4e3f12",
"createdAtUtc": "2026-05-29T10:15:22Z",
"expiresAtUtc": "2026-06-28T10:15:22Z"
}Upload a garment image · POST /garment-images
Similar to person upload, but with a required category form field. The category tells the AI how to drape the garment.
| category | Use for |
|---|---|
UpperBody | Shirts, tops, jackets |
LowerBody | Trousers, skirts, shorts |
FullBody | Dresses, jumpsuits, outfits |
Accessories | Bags, hats, jewellery |
curl https://api.fashclick.io/api/b2b/v1/garment-images \
-H "X-Api-Key: fck_test_YOUR_KEY_HERE" \
-F "file=@/path/to/shirt.jpg" \
-F "category=UpperBody" \
-F "title=Linen shirt — sky blue"201 response:
{
"garmentImageId": "a3b4c5d6-7e8f-4a9b-8c0d-1e2f3a4b5c6d",
"category": "UpperBody",
"title": "Linen shirt — sky blue",
"createdAtUtc": "2026-05-29T10:18:01Z"
}Single try-on · POST /tryon
One person + one garment → one image. Costs 1 credit. Use this for the common case (e.g. "show this customer wearing this product").
curl https://api.fashclick.io/api/b2b/v1/tryon \
-H "X-Api-Key: fck_test_YOUR_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{
"personImageId": "5f9c9d7a-3b7b-4d6a-8c2e-9b8a5d4e3f12",
"garmentImageId": "a3b4c5d6-7e8f-4a9b-8c0d-1e2f3a4b5c6d",
"metadata": "order:1234"
}'202 response (the request is queued):
{
"requestId": "11111111-2222-3333-4444-555555555555",
"status": "queued",
"totalCombinations": 1,
"creditsReserved": 1,
"estimatedSeconds": 35,
"createdAtUtc": "2026-05-29T10:20:00Z",
"links": {
"status": "/api/b2b/v1/tryon/11111111-2222-3333-4444-555555555555",
"results": "/api/b2b/v1/tryon/11111111-2222-3333-4444-555555555555/results"
}
} Poll /tryon/{requestId}/results every few seconds until status is completed — or, much better, subscribe to the TryOn.Completedwebhook.
Multi try-on · POST /tryon/multi
One person + N garments → N images. Each garment produces its own image. Reserves N credits up-front; only successful images are actually charged. Up to 25 garments per request.
curl https://api.fashclick.io/api/b2b/v1/tryon/multi \
-H "X-Api-Key: fck_test_YOUR_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{
"personImageId": "5f9c9d7a-3b7b-4d6a-8c2e-9b8a5d4e3f12",
"garments": [
{ "garmentImageId": "shirt-uuid" },
{ "garmentImageId": "trousers-uuid" },
{ "garmentImageId": "jacket-uuid" }
],
"metadata": "order:1234"
}'202 response:
{
"requestId": "22222222-3333-4444-5555-666666666666",
"status": "queued",
"totalCombinations": 3,
"creditsReserved": 3,
"estimatedSeconds": 65,
"createdAtUtc": "2026-05-29T10:21:00Z",
"links": {
"status": "/api/b2b/v1/tryon/22222222-3333-4444-5555-666666666666",
"results": "/api/b2b/v1/tryon/22222222-3333-4444-5555-666666666666/results"
}
} With multi try-on you'll often want streaming results. Subscribe to TryOn.ResultReady and you'll get one webhook per image as it finishes, instead of waiting for the whole request.
Batch try-on · POST /tryon/batch
Submit many independent try-on items in one call. Each item maps to one B2BTryOnRequest internally. Up to 100 items per batch, each item up to 25 garments.
All items share the same batchId so you can either:
- Wait for the
Batch.Completedwebhook (one event at the end), or - React to each
TryOn.Completedwebhook as items finish, plus aBatch.Progresssnapshot after every one.
curl https://api.fashclick.io/api/b2b/v1/tryon/batch \
-H "X-Api-Key: fck_test_YOUR_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{
"items": [
{
"personImageId": "person-1-uuid",
"garments": [{ "garmentImageId": "shirt-uuid" }]
},
{
"personImageId": "person-2-uuid",
"garments": [
{ "garmentImageId": "dress-uuid" },
{ "garmentImageId": "jacket-uuid" }
]
}
],
"metadata": "campaign:spring-2026"
}'202 response:
{
"batchId": "33333333-4444-5555-6666-777777777777",
"status": "queued",
"totalItems": 2,
"totalCombinations": 3,
"creditsReserved": 3,
"estimatedSeconds": 65,
"createdAtUtc": "2026-05-29T10:23:00Z",
"items": [
{
"requestId": "...",
"personImageId": "person-1-uuid",
"totalCombinations": 1,
"links": { "status": "...", "results": "..." }
},
{
"requestId": "...",
"personImageId": "person-2-uuid",
"totalCombinations": 2,
"links": { "status": "...", "results": "..." }
}
],
"links": { "status": "/api/b2b/v1/tryon/batch/33333333-..." }
}Status & results
Two read endpoints per request, plus a batch-level status endpoint:
| Endpoint | Returns |
|---|---|
GET /tryon/{requestId} | Aggregate status, counts, credits charged |
GET /tryon/{requestId}/results | Array of per-combination results with image URLs |
GET /tryon/batch/{batchId} | Batch-level roll-up plus a list of child requests |
curl https://api.fashclick.io/api/b2b/v1/tryon/REQUEST_ID/results \
-H "X-Api-Key: fck_test_YOUR_KEY_HERE"200 response:
{
"status": "completed",
"results": [
{
"resultId": "...",
"garmentImageId": "shirt-uuid",
"status": "completed",
"imageUrl": "https://cdn.fashclick.io/.../shirt-result.jpg",
"durationMs": 9342,
"completedAtUtc": "2026-05-29T10:23:42Z"
}
]
}Webhooks — setup & signing
Polling works, but webhooks are faster and cheaper. Create an endpoint in your Developer dashboard — we'll POST event payloads there with HMAC-SHA256 signatures so you can verify they came from FashClick.
Each request carries three headers:
| Header | Meaning |
|---|---|
X-FashClick-Event | The event type, e.g. TryOn.Completed |
X-FashClick-Timestamp | Unix epoch seconds of delivery |
X-FashClick-Signature | Hex HMAC-SHA256 of timestamp + "." + body using your signing secret |
Verify a signature:
# Verification is server-side only — not a curl one-liner.
# See the JavaScript / Python / C# tabs.Failed deliveries are retried with exponential backoff: 30s, 2m, 10m, 1h, 6h. After the fifth failure the delivery is abandoned and the endpoint is flagged in the dashboard.
Webhook event reference
Subscribe to whichever events your integration cares about. They split into three families: per-request terminal, batch roll-up, and streaming progress.
| Event | Fires when |
|---|---|
TryOn.Completed | A request finishes — all combinations succeeded |
TryOn.PartiallyCompleted | A request finishes — some succeeded, some failed |
TryOn.Failed | A request finishes — all combinations failed |
TryOn.ResultReady | One image inside a multi or batch request finishes (streaming) |
Batch.Completed | Last item of a batch finishes, all items succeeded |
Batch.PartiallyCompleted | Last item of a batch finishes, mixed outcomes |
Batch.Failed | Last item of a batch finishes, every item failed |
Batch.Progress | One child request of a batch finishes (streaming) |
Credits.Low | Wallet balance drops below your low-balance threshold |
Credits.Exhausted | Wallet balance hits zero |
ApiKey.Rotated | An API key was rotated in the dashboard |
TryOn.Completed payload
Fires once per request when all its images are done. The results array contains every generated image so you don't need a follow-up /results call.
{
"event": "TryOn.Completed",
"deliveredAtUtc": "2026-05-29T10:24:08Z",
"data": {
"requestId": "...",
"batchId": null,
"personImageId": "person-1-uuid",
"mode": "multiple_garments",
"status": "completed",
"totalCombinations": 3,
"successCount": 3,
"failedCount": 0,
"creditsCharged": 3,
"creditsRemaining": 405,
"completedAtUtc": "2026-05-29T10:24:07Z",
"results": [
{
"resultId": "...",
"garmentImageId": "shirt-uuid",
"status": "completed",
"imageUrl": "https://cdn.fashclick.io/.../shirt.jpg",
"failureCode": null,
"failureMessage": null,
"completedAtUtc": "2026-05-29T10:23:42Z"
},
{ "...": "two more results" }
]
},
"metadata": "order:1234"
}Streaming progress webhooks
For long-running multi or batch try-ons, two extra events let you render results as they arrive:
TryOn.ResultReady
Fires every time one image inside a multi or batch request lands a terminal state. Skipped for plain single try-ons (the final TryOn.Completed already has the same info).
{
"event": "TryOn.ResultReady",
"data": {
"requestId": "...",
"batchId": null,
"mode": "multiple_garments",
"result": {
"resultId": "...",
"personImageId": "person-1-uuid",
"garmentImageId": "shirt-uuid",
"status": "completed",
"imageUrl": "https://cdn.fashclick.io/.../shirt.jpg",
"failureCode": null,
"failureMessage": null,
"completedAtUtc": "2026-05-29T10:23:42Z"
},
"progress": {
"totalCombinations": 25,
"completedCount": 3,
"failedCount": 0,
"remainingCount": 22
},
"creditsRemaining": 397
}
}Batch.Progress
Fires after each child request in a batch finishes, with batch-level counters. Perfect for a real-time progress bar.
{
"event": "Batch.Progress",
"data": {
"batchId": "...",
"request": {
"requestId": "...",
"mode": "single",
"status": "completed",
"totalCombinations": 1,
"successCount": 1,
"failedCount": 0,
"creditsCharged": 1
},
"progress": {
"totalItems": 10,
"completedItems": 4,
"partiallyCompletedItems": 0,
"failedItems": 0,
"remainingItems": 6,
"totalCombinations": 10,
"successCount": 4,
"failedCount": 0
},
"creditsRemaining": 396
}
}Errors
Validation errors return HTTP 400 with a structured body. Auth errors are 401; plan/permission errors are 403; rate-limited requests are 429.
Example: insufficient credits
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"statusCode": 400,
"message": "Validation failed.",
"errors": {
"credits": [
"Insufficient credits for this batch. This batch needs 15 credits, your wallet has 10. You are short by 5. Top up your wallet and resubmit."
]
}
}Example: unknown person image
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"statusCode": 400,
"message": "Validation failed.",
"errors": {
"personImageId": [
"Person image not found or not owned by this account."
]
}
}Credits & billing
Each successful image charges one credit. Failed images are free. Credits come from your subscription plan or one-off credit packs — top up from the My Plan page.
Every TryOn.* and Batch.* webhook includes creditsCharged and creditsRemaining, so your backend can reconcile balances without an extra API call.
Changelog
TryOn.ResultReady and Batch.Progress so you can render images one at a time instead of waiting for the whole multi/batch request. /tryon into a strict single endpoint (one person + one garment) and a new /tryon/multi for the N-garment case. The webhook payload now includes a mode field plus the full results[] array with image URLs. Batch.Completed, Batch.PartiallyCompleted, and Batch.Failed. Insufficient-credit errors now include the exact shortfall.