API Endpoints
| Environment | Base URL |
|-------------|----------|
| Non-production | https://api-nonprod.thg.dev/agentic-commerce/v1/vto |
| Production | https://api.thg.dev/agentic-commerce/v1/vto |
All endpoints require an X-API-Key header (forwarded to Vertex AI / internal
services via Apigee). Pass x-session-id on subsequent requests after upload
to keep analytics, history, and cache coherent.
POST /upload-photo
Section titled “POST /upload-photo”Upload and process a person photo for virtual try-on.
{ "personImageBase64": "base64-encoded-jpeg", "processBackground": false}| Field | Type | Required | Description |
|-------|------|----------|-------------|
| personImageUrl | string | Yes* | Public URL of the person photo |
| personImageBase64 | string | Yes* | Base64-encoded person photo |
| processBackground | boolean | No | Replace background with studio gray. Default: false |
*Provide either personImageUrl or personImageBase64, not both.
Client-side validation (SDK, before upload): file type jpeg|png|webp|heic|heif,
size ≤ 10 MB, min dimension 512 px, max aspect ratio 4:1.
Server-side validation: format/size, Cloud Vision SafeSearch moderation, and a Gemini photo-suitability check that can return warnings and suggestions.
{ "ref": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "sessionId": "uuid", "processedImageBase64": "base64-processed-image", "validation": { "warnings": ["Photo is slightly dark"], "suggestion": "Try better lighting for best results" }}The ref is a UUID. Pass it as personImageRef in POST /try-on. Processed
photos are stored in GCS and auto-deleted after 24 hours.
400 Bad Request
{ "error": "Missing required field: personImageUrl or personImageBase64" }422 Validation Failed (code is one of PHOTO_VALIDATION_FAILED)
{ "error": "Photo must show a full person", "code": "PHOTO_VALIDATION_FAILED", "validation": { "errors": ["Photo must show a full person"] }}500 Internal Server Error — Returned when photo processing fails (e.g. all Gemini models exhausted).
GET /try-on/check
Section titled “GET /try-on/check”Lightweight cache check — does a try-on result already exist for this
(person, product) pair under the active pipeline config? No image data is
transferred.
GET /try-on/check?person=<ref>&model=<imageUrl>&productName=<name>| Query param | Required | Description |
|-------------|----------|-------------|
| person | Yes | personImageRef from /upload-photo (or a model ID like model-01) |
| model | Yes | Product image URL |
| productName | No | Included in cache key when provided |
| productDescription | No | Included in cache key when provided |
| productCategory | No | Included in cache key when provided |
{ "cached": true, "imageUrl": "https://.../share/<id>/image" }When cached: false, only the boolean is returned.
POST /try-on
Section titled “POST /try-on”Generate a virtual try-on image.
{ "personImageRef": "uuid-from-upload", "modelImageUrl": "https://cdn.example.com/product.jpg", "productName": "Blue Oxford Shirt", "productUrl": "https://example.com/p/blue-oxford", "productDescription": "100% cotton regular fit shirt", "productCategory": "shirts"}| Field | Type | Required | Description |
|-------|------|----------|-------------|
| personImageRef | string | Yes | UUID from POST /upload-photo, or a model ID (model-01 …) |
| modelImageUrl | string | Yes* | Product/garment image URL |
| candidateImageUrls | string[] | Yes* | Up to 5 gallery URLs — server AI-picks the best |
| productName | string | No | Enriches the garment description prompt |
| productUrl | string | No | Link to PDP (used in share page) |
| productDescription | string | No | PDP metadata — enriches description step |
| productCategory | string | No | PDP metadata — enriches description step |
*Provide modelImageUrl or candidateImageUrls (at least one).
Pipeline config is not accepted in the body — it is controlled by Apigee
per API key (via the X-VTO-Pipeline-Config header injected from the API
Product’s custom attributes).
{ "requestId": "uuid", "imageBase64": "data:image/png;base64,...", "shareUrl": "https://api-nonprod.thg.dev/agentic-commerce/v1/vto/share/<id>"}400 Bad Request
{ "error": "Missing required fields: personImageRef and modelImageUrl (or candidateImageUrls)" }{ "error": "Invalid personImageRef format" }500 Internal Server Error
{ "error": "Failed to generate try-on image" }GET /models
Section titled “GET /models”List available predefined models.
{ "models": [ { "id": "model-01", "thumbnailUrl": "/models/model-01/thumbnail", "label": "Model A" } ]}GET /models/:id/thumbnail
Section titled “GET /models/:id/thumbnail”Returns the model thumbnail as image/jpeg.
GET /share/:id
Section titled “GET /share/:id”HTML share page with OpenGraph tags for social previews. Linked from the modal’s share dropdown.
GET /share/:id/image
Section titled “GET /share/:id/image”Raw PNG of the shared result — used as a source for cached-result rendering.
POST /feedback
Section titled “POST /feedback”Submit quality feedback on a try-on result.
{ "requestId": "uuid-from-try-on", "value": "up", "reason": null}value: "up" or "down". When "down", include reason:
"garment_wrong", "body_mismatch", "quality", or "other".
Pipeline
Section titled “Pipeline”The try-on pipeline is composable. Each step can be independently toggled per client, with model overrides:
| Step | Default | Description |
|------|---------|-------------|
| Image selection | ON | Pick the best product image from candidateImageUrls. |
| Product flat-lay | ON | Strip the model from the product image → garment on white. Cached per product. |
| Product description | ON | Detailed garment description (enriched with PDP metadata). Cached per product. |
| Generation | always | Nano Banana 2 (gemini-3.1-flash-image-preview) produces the try-on image. |
| Quality scoring | OFF | Score result against inputs; retry on fail. |
Flat-lay and description run in parallel. Results are cached per product (SHA256 of URL + metadata + active config) so expensive steps run once per product.