API Reference

Virtual Try-On API

Send a photo of a person and a photo of a garment — get back a photorealistic image of that person wearing that garment. One synchronous call, powered by Google Gemini.

POSThttps://api.benitoai.com/v1/tryon

You need an API key to get started

API keys are issued manually. Contact us to request a key — tell us a bit about your use case and expected volume, and we'll set you up with a key and pricing that fits. Keys are shown once at creation time, so store yours securely.

01

Key concepts

Read these first — they shape how you integrate.

  • Synchronous & long-running. The request does everything in one call — fetches your two images, runs the AI generation, stores the result, and returns the final image URL. There is no queue, job id, or polling.
  • Generation takes ~10–60 seconds. The server keeps the connection alive up to 120s. Raise your HTTP client's read timeout (e.g. 180s) or it will give up before the image is ready.
  • You send image URLs, not file uploads. Both input images must be publicly reachable over http/https. The server downloads them itself.
  • Output is a hosted PNG URL. The API never returns base64 — you get a permanent URL to the generated .png.
02

Authentication

Every request requires a Bearer API key in the Authorization header:

http
Authorization: Bearer bnto_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  • Keys look like bnto_live_<random>.
  • Keys are shown once, at creation time — store yours securely.
  • A missing, malformed, revoked, or unknown key returns 401.
  • Treat the key as a secret: never embed it in client-side/browser code or commit it to source control. Call the API from your backend.
Don't have a key yet? Contact us and we'll issue one for your account.
03

Request

Send a JSON body to the endpoint with your two image URLs.

POSThttps://api.benitoai.com/v1/tryon

Body schema:

json
{
  "model_name": "tryon-v1.6",
  "inputs": {
    "model_image": "https://example.com/person.jpg",
    "garment_image": "https://example.com/garment.jpg"
  }
}
FieldTypeRequiredDescription
model_namestringNoLogical model identifier. Defaults to tryon-v1.6. Echoed back in the response.
inputs.model_imageURLYesPublic URL of the person/model photo. Defines the output's identity, pose, background, and aspect ratio.
inputs.garment_imageURLYesPublic URL of the garment photo. Used as a reference for fabric, cut, and color only — its background is ignored.
Order matters conceptually: model_image is the person; garment_image is the clothing. The person's face, body, pose, and background are preserved; the garment is transferred onto them.
04

Image requirements

Both images must satisfy all of the following, or the request fails with image_fetch_failed (400):

RequirementLimit / Rule
Schemehttp or https only
FormatPNG, JPEG, WebP, or GIF
Content-TypeThe server must receive an image/* content type
Max size10 MB per image
ReachabilityURL must return HTTP 200 within 10 seconds
RedirectsAt most 2 redirects are followed
HostMust resolve to a public IP address
SSRF protection: URLs that resolve to private, loopback, link-local, reserved, multicast, or unspecified addresses are rejected — including cloud metadata endpoints (169.254.169.254), 127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, ::1, and fc00::/7. Every redirect hop is re-validated. Use public image hosting (your own CDN, object storage with public read, etc.).

Output aspect ratio

The output's aspect ratio matches the model_image, snapped to the nearest supported ratio (e.g. 1:1, 16:9, 9:16, 4:3, 3:4, 4:5). For predictable framing, crop your person photo to the aspect ratio you want before submitting.

Tips for best results

  • Use a clear, well-lit, front-facing photo of the person.
  • Use a clean garment reference (flat-lay or on a model) where the item is fully visible. The garment's background is discarded, so it doesn't need to be plain.
  • If the garment image includes accessories (shoes, hats, belts, glasses, bags, jewelry), they may also be applied.
  • A full-body garment (dress/jumpsuit) replaces both top and bottom; a "top" is layered appropriately.
05

Response

Success → 200 OK

json
{
  "id": "tryon_V1StGXR8Z5jdHi6BmyT8x",
  "model_name": "tryon-v1.6",
  "output": {
    "image_url": "https://pub-xxxx.r2.dev/outputs/tryon_V1StGXR8Z5jdHi6BmyT8x.png"
  },
  "created_at": "2026-06-21T12:00:00Z"
}
FieldDescription
idUnique try-on id (tryon_…). Also the output filename.
model_nameThe model identifier you sent (or the default).
output.image_urlPublic URL of the generated PNG.
created_atUTC timestamp (ISO 8601).
Every response includes an X-Request-ID header — include it when reporting issues. You can also set your own X-Request-ID on the request and it will be echoed back.
06

Errors

All errors share one envelope:

json
{ "error": { "code": "invalid_api_key", "message": "Invalid API key." } }

Validation errors (422) additionally include a details array describing which fields failed.

HTTPcodeMeaning / cause
401missing_api_keyNo / malformed Authorization header
401invalid_api_keyUnknown or revoked key
422validation_errorRequest body failed schema validation
422generation_failedThe model could not produce an image
422content_blockedGeneration blocked by safety filters
400image_fetch_failedAn input image could not be fetched/validated
429rate_limitedPer-key rate limit exceeded. Includes a Retry-After header
502storage_failedGenerated image could not be stored
500internal_errorUnexpected server error

Handling guidance

  • 429 — read the Retry-After response header (seconds) and back off before retrying.
  • generation_failed / content_blocked — usually input-related. Try a clearer person photo or a different garment; retrying an identical content_blocked request rarely helps.
  • image_fetch_failed — verify the URL is public, returns an image, is under 10 MB, and resolves to a public host.
  • internal_error / storage_failed — transient; safe to retry with backoff.
07

Rate limits

  • Default: 60 requests per minute per API key (some keys may have a custom limit).
  • Enforced with a rolling 60-second window.
  • Exceeding it returns 429 with a Retry-After header telling you how many seconds to wait.
08

Examples

The generation can take up to ~60s — every example sets a generous client timeout (~180s) so the connection stays open until the image is ready.

curl --max-time 180 -X POST https://api.benitoai.com/v1/tryon \
  -H "Authorization: Bearer bnto_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
        "model_name": "tryon-v1.6",
        "inputs": {
          "model_image": "https://example.com/person.jpg",
          "garment_image": "https://example.com/garment.jpg"
        }
      }'
09

Other endpoints

EndpointPurpose
GET /healthLiveness check. Returns 200 {"status":"ok","mongo":true} when healthy, 503 otherwise. No auth required.
GET /docsInteractive Swagger/OpenAPI UI for exploring and testing the API in the browser.
10

Quick checklist before you call

  • ☐ Bearer API key set in the Authorization header.
  • ☐ Both image URLs are public http/https and return a PNG/JPEG/WebP/GIF.
  • ☐ Each image is under 10 MB and loads within 10s.
  • ☐ Person photo cropped to your desired output aspect ratio.
  • ☐ HTTP client read timeout set to ~180s.
  • ☐ Retry/backoff logic for 429 (honor Retry-After) and 5xx.

Ready to start?

Contact us to get your API key and go live.

Get an API key