1
Create a job
POST /try-on/generate with the garment URL(s). You get back a job_id and a
202 Accepted.2
Wait for it to finish
Stream the job over SSE (preferred) or poll it until
status is completed.3
Display the result
Read
generated_image_url from the final event and show it to your user.Before you start
Every endpoint on this page requires both authentication headers, and the user must already have a usable base image.Headers on every request
Send your tenant key as
x-api-key and the user’s session token as
Authorization: Bearer <access_token>. See the
API Overview.A ready base image
The user must have a base image whose status is not
processing or
rejected. Upload and confirm it first — see User & Image.Throughout this page,
BASE_URL is the Souldi API base URL, https://api.souldi.io.Create a job
Creates an asynchronous try-on job. Returns202 Accepted immediately — the
image is generated in the background.
Required headers
Body parameters
string[]
required
One to three public garment image URLs. URLs must be unique. A single URL
runs one virtual try-on; two or three URLs compose multiple garments into one
job.
string | null
The
job_id of a previous completed try-on to layer this garment onto
(sequential outfit combinator). When set, only one
garment URL is allowed. Pass null for a fresh try-on.string | null
Pass
"no_bg" to run against the background-removed version of the user’s base
image, or null to use the original.string
The identifier you’ll use to stream or poll the job.
string | null
The result image URL once the job is
completed. null until then.Behavior & limits
Base image must be usable
Base image must be usable
The user must have a base image whose status is not
processing (still
preprocessing) or rejected (unusable). Otherwise the request is rejected —
upload and confirm a photo first via User & Image.Duplicate garment URLs are rejected
Duplicate garment URLs are rejected
Every URL in
garment_image_urls must be unique. Repeating a URL fails
validation.Identical jobs are de-duplicated
Identical jobs are de-duplicated
If an identical job already exists (same garments, base image, and mode),
Souldi returns that existing job instead of creating a duplicate — so retrying
the same request is safe and won’t burn extra generations.
Rate limit: 5 requests / 60s per user
Rate limit: 5 requests / 60s per user
Exceeding the limit returns
429 Too Many Requests. Back off before
retrying.Stream the job (SSE)
Streams job status in real time over Server-Sent Events. This is the preferred way to await a result — you get updates the moment they happen, with no polling loop. Required headers
Path parameter
string
required
The
job_id returned by POST /try-on/generate.- Each
data:event is a JSON object:{ "job_id", "status", "generated_image_url" }— the same shape as the polling response. - A heartbeat comment (
:) is sent about every 15 seconds while the job is still running, to keep the connection alive. - When
statusbecomescompleted,generated_image_urlis a signed URL to the result image. Whenfailed, generation did not succeed. - The server closes the stream after a 120-second timeout.
- If the job is already terminal (
completedorfailed) when you connect, you receive a single event and the stream closes immediately.
Poll the job
Returns the current job status. Use this as a fallback when you can’t hold an SSE connection open (for example, a serverless function or a constrained client). Required headers
Path parameter
string
required
The
job_id returned by POST /try-on/generate.status is completed or failed.
The official widget polls every 3 seconds for up to roughly 20 attempts
(about a minute) before giving up. Tune the interval and cap to fit your UX.
Statuses
Every stream event and poll response carries astatus. The first two are
transient; the last two are terminal.
Outfit combinator
Want to stack garments into a layered look — a shirt, then a jacket over it? Build the outfit sequentially by feeding each completed job into the next.1
Generate the first garment
POST /try-on/generate with the first garment URL and reference_job_id: null.2
Wait for completed
Stream or poll until that job’s
status is completed. Note its job_id.3
Layer the next garment
POST /try-on/generate again with the next garment URL and
reference_job_id set to the previous job’s job_id. Remember: with a
reference_job_id, only one garment URL is allowed.4
Repeat to keep stacking
Each new job layers onto the one before it. Repeat for as many garments as you
want in the outfit.
This is exactly the mechanism the widget’s
mode: 'oc' (outfit combinator) uses
under the hood — chaining jobs via reference_job_id so each garment renders on
top of the previous result.Next steps
Review the full flow
See how authentication, image upload, and generation fit together end to end.
Let the widget do it for you
The official drop-in widget runs this entire flow — auth, upload, streaming,
and outfit combinator — out of the box.