> ## Documentation Index
> Fetch the complete documentation index at: https://docs.genlook.app/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Introduction

> Add AI-powered virtual try-on to any platform — one or two API calls per generation.

The Genlook Virtual Try-On API lets you add AI-powered virtual try-on to any e-commerce platform, mobile app, or custom flow. **The minimal integration is two HTTP calls**: upload the customer photo, run the try-on. Products are managed for you — no catalog sync, no cleanup loop.

## Base URL

```
https://api.genlook.app/tryon/v1
```

## Authentication

Every request needs the `x-api-key` header.

```bash theme={null}
curl -H "x-api-key: gk_your_api_key" \
  https://api.genlook.app/tryon/v1/products?limit=1
```

Grab your API key by creating an account on [app.genlook.app](https://app.genlook.app)

## TypeScript SDK

For Node 20+, Deno, Bun, or edge runtimes, install [`@genlook/api`](https://www.npmjs.com/package/@genlook/api) — every endpoint on this page has a typed method, automatic retries, and a one-line generation poller.

```bash theme={null}
pnpm add @genlook/api    # or npm i / yarn add
```

```ts theme={null}
import { Genlook } from "@genlook/api";

const client = new Genlook({ apiKey: process.env.GENLOOK_API_KEY! });
```

The endpoint pages below show the SDK call alongside the raw HTTP example. Browser usage is intentionally unsupported — keep the API key on your server. See the [SDK guide](/tryon-api/sdk) for configuration, error handling, and the `waitFor` poller, or clone the [Next.js example app](https://github.com/GenlookLabs/virtual-try-on-api-example) for a full working integration.

## Credits

Each try-on consumes **1 credit**. Credits don't expire. Out of credits → the call returns `402 Payment Required` with code `INSUFFICIENT_CREDITS`. Read your remaining balance with [`GET /account/credits`](/tryon-api/endpoints/check-credits); top-ups are done from the Genlook dashboard.

<Tip>
  **Building a new product?** We run a [startup program](/tryon-api/startup-program) (including free credits) for new products integrating
  Genlook — email [thibault@genlook.app](mailto:thibault@genlook.app) to learn more.
</Tip>

## Rate limits

Default **100 requests/minute** per account. Over the limit returns `429 Too Many Requests` with code `RATE_LIMITED`.

## Errors

Every error response uses the same shape — `{ code, message, status }` (plus `details` for validation). Branch on the `code` string. See [Errors](/tryon-api/errors) for the full catalog.

## How a try-on flows

```mermaid theme={null}
sequenceDiagram
    participant Client
    participant API as Genlook API
    Client->>API: 1. POST /images/upload (customer photo)
    API-->>Client: imageId
    Client->>API: 2. POST /try-on (product + imageId)
    API-->>Client: generationId (PENDING)
    loop Poll every 2s
        Client->>API: 3. GET /generations/:id
        API-->>Client: status
    end
    API-->>Client: COMPLETED + resultImageUrl
```

**The inline `products[]` field is the recommended path.** `/try-on` creates or refreshes the product and runs the generation in a single call — no separate "create product" step, no catalog sync loop. `products` is an array that holds **exactly one item for now** (multi-product try-on is on the roadmap). Three shapes per item:

* **Inline (default for first-time products)** — `{ products: [{ externalId, title, description, images: [...] }] }`. Creates the product if it doesn't exist, updates it if it does. Lives 15 days from last use; every generation refreshes the timer, so actively-used products never expire.
* **Reference (cheap repeat call)** — `{ products: [{ externalId: "shirt-42" }] }`. Once a product exists, subsequent generations just send the ID.
* **One-shot** — `{ products: [{ title, description, images: [...] }] }` (no `externalId`). The response includes a generated `productExternalId` you can re-use to reference the same product later. One-shot products live 7 days from last use.

<Tip>
  Most integrations only need the inline path. [`POST /products`](/tryon-api/endpoints/create-product) exists as an
  opt-in alternative for callers who want explicit catalog management — lifetime TTL by default, visible in [`GET
      /products`](/tryon-api/endpoints/list-products) and the dashboard. You don't need it to get started.
</Tip>

## Person image options

`POST /try-on` takes a `person` object whose `image.source` holds exactly one of three fields:

| Field                         | When to use                                                                                                                                                                                        |
| ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `person.image.source.id`      | **Recommended.** Image id from a prior [`POST /images/upload`](/tryon-api/endpoints/upload-image). Reusable across generations, and the only path that controls cropping (`crop=false` on upload). |
| `person.image.source.url`     | Quick one-shot from a remote URL. Server downloads + 4:5-crops + processes on every call.                                                                                                          |
| `person.image.source.fileKey` | Ship the bytes in the same `/try-on` request (multipart). Always 4:5-cropped.                                                                                                                      |

Pre-uploading wins for repeat use — the upload happens once and the same `id` can power many generations. The inline `url` / `fileKey` paths always apply the person-aware 4:5 crop; if you need a raw image, go through `/images/upload` with `crop=false`.

<Note>The previous request shape — a top-level singular `product`, a `customer` object, top-level `customerId`, and top-level `useWatermark` / `retentionDays` — is still accepted but **deprecated** (not a breaking change). Migrate to `products: [...]`, `person.image.source`, `externalUserId`, and `output.watermark` / `output.keepForDays`. See the [Changelog](/tryon-api/changelog#1-4-0-2026-06-17).</Note>

## Response format

JSON. Errors use a stable `{ code, message, status }` shape:

```json theme={null}
{
  "code": "INSUFFICIENT_CREDITS",
  "message": "Insufficient credits. Top up the account balance and retry.",
  "status": 402
}
```

Switch on `code` (a documented enum) — full catalog at [Errors](/tryon-api/errors).

## Recommended workflow

The shortest version: **upload the customer photo once, reference products by `externalId`, fall back to an inline upsert if you hit `PRODUCT_NOT_FOUND`.**

See [Full Example (Python)](/tryon-api/full-example) for a runnable template, and the [Quickstart](/tryon-api/quickstart) for a 5-minute walkthrough.

## Next steps

<CardGroup cols={2}>
  <Card title="Quickstart" icon="rocket" href="/tryon-api/quickstart">
    Two-call try-on in 5 minutes
  </Card>

  <Card title="TypeScript SDK" icon="cube" href="/tryon-api/sdk">
    Typed client for Node, Deno, Bun & edge
  </Card>

  <Card title="Example app (Next.js)" icon="github" href="https://github.com/GenlookLabs/virtual-try-on-api-example">
    Clone a full working integration
  </Card>

  <Card title="Full Example (Python)" icon="code" href="/tryon-api/full-example">
    Ref-first / upsert-on-miss template
  </Card>

  <Card title="Try-On endpoint" icon="image" href="/tryon-api/endpoints/create-try-on">
    Every option on /try-on
  </Card>

  <Card title="Watermark" icon="stamp" href="/tryon-api/watermark">
    Brand every result with your logo
  </Card>

  <Card title="Changelog" icon="list-check" href="/tryon-api/changelog">
    Release notes — currently v1.0.0
  </Card>

  <Card title="Migrating from the alpha" icon="triangle-exclamation" href="/tryon-api/breaking-changes">
    Recipes for upgrading alpha integrations
  </Card>
</CardGroup>
