Skip to main content
This is where it all comes together: you send Souldi one or more garment image URLs, and it returns a photorealistic image of your user wearing them. Generation is asynchronous — you create a job, wait for it to finish, then show the result.
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. Returns 202 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.
Response fields
string
The identifier you’ll use to stream or poll the job.
string
The job status. Starts as pending.
string | null
The result image URL once the job is completed. null until then.

Behavior & limits

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.
Every URL in garment_image_urls must be unique. Repeating a URL fails validation.
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.
Exceeding the limit returns 429 Too Many Requests. Back off before retrying.
Garment URLs must be publicly reachable — Souldi fetches them server-side during generation. URLs behind authentication or on private networks will fail.

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.
How the stream behaves
  • 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 status becomes completed, generated_image_url is a signed URL to the result image. When failed, generation did not succeed.
  • The server closes the stream after a 120-second timeout.
  • If the job is already terminal (completed or failed) when you connect, you receive a single event and the stream closes immediately.
The official widget streams with @microsoft/fetch-event-source — which lets it send the auth headers EventSource can’t. It retries the connection up to 3 times with 1s / 2s / 4s backoff, then falls back to polling so a result is never lost to a flaky connection.
The signed generated_image_url is short-lived. Display or download it promptly rather than caching the URL for later.

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.
Poll on an interval until 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 a status. 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.