# Getting Started

Get going in under 2 minutes

### :closed\_lock\_with\_key: Authentication

We use a simple API key authentication scheme. After purchasing your Enterprise plan on [our website](https://virtualstagingai.app) you will have access to your personal API key under [Settings](https://virtualstagingai.app/settings).&#x20;

You can authenticate all requests by including an Authorization Header with the value&#x20;

`Authorization: Api-Key {your_api_key_here}`

### 💻 Best Practices for Building Applications around this API

This API does one thing well: generate images. Auxiliary infrastructure has to be built by you:

1. **Store your own images**

   While we do return image urls from our endpoints, they are not suited to be directly embedded in your own applications. They are signed links which are generated each time you call the Get Render request and will expire within two weeks. That's why we recommend to download the images to your own cloud storage. Accordingly, we can't guarantee inbound-access to the images for any extended period of time after the initial generation (>1h)
2. **Store your own user profiles**\
   If you're building a product around our API, you'll likely want to allow multiple users to manage their own images on your platform. As you may have noticed, we do not offer any type of multi-tenant use of our API. All images are accessible with your single API key. Therefore, you should store the API key on your own backend, use it to retrieve/generate images, save the results and generation parameters into your own database, and have your own authentication system that grants your users access to their images, but not to the images of other users.<br>

### :post\_office: Postman Example Calls

We've created a [Postman workspace](https://www.postman.com/virtualstaging-ai/workspace/virtual-staging-ai-api/collection/6355387-724643b9-cbe2-4b05-b243-286d1445fcf7?action=share\&creator=6355387\&active-environment=6355387-2f176fce-cd09-41e2-ab8c-2fe92870105c) with example calls for each endpoint. Just plug in your API key as an environment variable (`vsai_api_key`) and try out the endpoints.&#x20;

You'll need to copy around Render IDs from endpoint to endpoint to try some of the features.

There you can also generate code snippets.

[**Check out the Postman workspace**](https://www.postman.com/virtualstaging-ai/workspace/virtual-staging-ai-api/collection/6355387-724643b9-cbe2-4b05-b243-286d1445fcf7?action=share\&creator=6355387\&active-environment=6355387-2f176fce-cd09-41e2-ab8c-2fe92870105c)


# Endpoints

A directory of all Virtual Staging AI API endpoints.

## Test your setup

<mark style="color:blue;">`GET`</mark> `https://api.virtualstagingai.app/v1/ping`

Use this endpoint to test that your setup is working correctly. Returns some data about your account.

#### Headers

| Name          | Type   | Description                             |
| ------------- | ------ | --------------------------------------- |
| Authorization | String | Set to "Api-Key {your\_api\_key\_here}" |

{% tabs %}
{% tab title="200: OK Success" %}
Returns:

```
{
    userObj: {
        email: "...",
        uid: "..."
    },
    "photoLimit": 123,
    "photosUsedThisPeriod": 19
}
```

{% endtab %}
{% endtabs %}

## Create a new render

<mark style="color:green;">`POST`</mark> `https://api.virtualstagingai.app/v1/render/create`

This is the main endpoint of the API. It allows you to perform the following actions:

1. **Create a staging render**: Add virtual furniture to an image.
2. **Create a decluttered render**: Remove existing furniture from an image.
3. **Create a decluttered + staging render**: Remove existing furniture and add new virtual furniture to the same image.

#### How to Use:

1. **To create a staging render** (adding virtual furniture):
   * Set the required fields: `image_url`, `room_type`, `style`.
   * Set the `declutter_mode` parameter to `'off'` (default).
   * The image will be virtually staged with new furniture based on the provided style and room type.
2. **To create a decluttered render** (removing existing furniture without adding new furniture):
   * Set the required field: `image_url`.
   * Set the `declutter_mode` to `'on'`.
   * Set the `add_furniture` parameter to `false`.
   * This will only remove existing furniture, and the output will include the decluttered image.
3. **To create a decluttered + staging render** (removing existing furniture and adding new furniture):
   * Set the required fields: `image_url`, `room_type`, `style`.
   * Set the `declutter_mode` to `'on'` or `'auto'`.
   * Ensure the `add_furniture` parameter is `true` (default).
   * The output will include two images: one with the furniture removed and another with the new furniture added.

Maximum concurrency per API account: 50.

#### Headers

| Name                                            | Type   | Description                             |
| ----------------------------------------------- | ------ | --------------------------------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Set to "Api-Key {your\_api\_key\_here}" |

#### Request Body

| Name                                         | Type    | Description                                                                                                                                                                                                                                                                                                                                                           |
| -------------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| image\_url<mark style="color:red;">\*</mark> | String  | URL of the image to add furniture to. If not provided, use the "file" parameter for form data uploads.                                                                                                                                                                                                                                                                |
| room\_type<mark style="color:red;">\*</mark> | String  | <p>The type of room in the uploaded photo. Must be one of: </p><p></p><p><code>\[ "living", "bed", "kitchen", "dining", "home\_office", "outdoor", "kids\_room" ]</code></p><p></p>                                                                                                                                                                                   |
| style<mark style="color:red;">\*</mark>      | String  | The desired style of furnishing. Must be one of the following: `["modern", "scandinavian", "industrial", "midcentury", "luxury", "farmhouse", "coastal", "standard"]`                                                                                                                                                                                                 |
| resolution                                   | String  | Resolution of the output image. Must be `4k` or `full-hd`                                                                                                                                                                                                                                                                                                             |
| file                                         | File    | Form data field to pass an image directly (if not using `image_url`). If you're using this, the other arguments have to be sent via URL query parameters.                                                                                                                                                                                                             |
| wait\_for\_completion                        | Boolean | If `false`, the response will include `{render_id}` instantly, and you can check render status via `GET /v1/render`. Default: `true`.                                                                                                                                                                                                                                 |
| add\_virtually\_staged\_watermark            | String  | Adds a small "Virtually Staged" disclaimer in the lower right corner of the rendered image                                                                                                                                                                                                                                                                            |
| declutter\_mode                              | String  | <p>Decluttering options:<br>- <code>'off'</code> (default): No decluttering.<br>- <code>'auto'</code>: Automatically declutter if furniture is detected.<br>- <code>'on'</code>: Always perform decluttering. If decluttering occurs, two outputs are created: a staged image and a decluttered image. Subsequent variations are staged on the decluttered image.</p> |
| declutter\_mask\_url                         | String  | URL of a black-and-white image to use as a mask for decluttering instead of automatically generating a mask. Use this if you want to allow your users to draw their own mask to decide which furniture gets removed and which doesn't.                                                                                                                                |
| add\_furniture                               | Boolean | <p>If <code>declutter\_mode</code> is <code>'on'</code>, this parameter controls whether to add new furniture:<br>- If <code>false</code>, only the decluttered image will be created without adding new furniture.<br>- Default: <code>true</code>.</p>                                                                                                              |

{% tabs %}
{% tab title="200: OK Success" %}
Returns:

```json5
{
    result_image_url: string, // only if "wait_for_completion" was set to true
    render_id: string,
    removal_output: string // only if "wait_for_completion" was set to true and decluttering was performed
}
```

Store the Render ID if you wish to create further variations for this photo, or look up the render state using `GET /v1/render`
{% endtab %}

{% tab title="405: Method Not Allowed When using an HTTP method different than POST" %}

{% endtab %}

{% tab title="401: Unauthorized Either your API key is invalid, or an error occurred during authentication" %}

{% endtab %}

{% tab title="403: Forbidden Authentication succeeded but you don't have a plan with API access, or have used up your renders." %}

{% endtab %}

{% tab title="400: Bad Request Invalid value for some parameter (body will contain an explanation)" %}

{% endtab %}
{% endtabs %}

## Get an existing render

<mark style="color:blue;">`GET`</mark> `https://api.virtualstagingai.app/v1/render`

Use this to retrieve information about an existing render (e.g. show your users progress after starting a render with `wait_for_completion=false`).&#x20;

This is available right after a render is created, even if the render status is `rendering`, so you can get the render info even if the render isn't done yet.

#### Query Parameters

| Name                                         | Type   | Description                                     |
| -------------------------------------------- | ------ | ----------------------------------------------- |
| render\_id<mark style="color:red;">\*</mark> | String | The render ID returned from `/v1/render/create` |

#### Headers

| Name                                            | Type   | Description                             |
| ----------------------------------------------- | ------ | --------------------------------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Set to "Api-Key {your\_api\_key\_here}" |

{% tabs %}
{% tab title="200: OK Success" %}
Returns:

```json5
{
    "render_id": "...",
    "status": "rendering" | "done" | "error",
    "created_at": 1685742540902, // epoch timestamp
    "outputs": string[], // will contain output image urls if status == "done". Will an entry for each new variation.
    "progress": 0.7432000000000001 // number 0-1
    "outputs_room_types": string[],
    "outputs_styles": string[]
}
```

{% endtab %}

{% tab title="405: Method Not Allowed Using different method than GET" %}

{% endtab %}

{% tab title="401: Unauthorized API key invalid or not provided" %}

{% endtab %}

{% tab title="403: Forbidden Authentication succeeded but your account doesn't have a plan with API access" %}

{% endtab %}

{% tab title="404: Not Found Render not found" %}

{% endtab %}

{% tab title="400: Bad Request No Render ID provided" %}

{% endtab %}
{% endtabs %}

## Create a variation for an existing render

<mark style="color:green;">`POST`</mark> `https://api.virtualstagingai.app/v1/render/create-variation`

Creates a variation for an existing render. The render has to have been created using `/v1/render/create` beforehand.&#x20;

All the same settings (`room_type`, etc.) from the first call will be used.

The render has to be in status `done` to start a new variation. The maximum amount of variations per render is 20.

#### Query Parameters

| Name       | Type   | Description                                     |
| ---------- | ------ | ----------------------------------------------- |
| render\_id | String | The render ID returned from `/v1/render/create` |

#### Headers

| Name                                            | Type   | Description                             |
| ----------------------------------------------- | ------ | --------------------------------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Set to "Api-Key {your\_api\_key\_here}" |

#### Request Body

| Name                              | Type    | Description                                                                                                                                                                                                                                                                                                                                                      |
| --------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| wait\_for\_completion             | Boolean | <p>If false, you'll get a response like <code>{render\_id}</code>  instantly and the result output will be added to the <code>outputs</code> array in the render object. </p><p></p><p>So when you retrieve the render object using <code>GET /v1/render</code>, the last element of <code>outputs</code> will contain the url to your new variation.</p><p></p> |
| roomType                          | String  | The type of room for the new variations. Must be one of: `living`, `bed`, `kitchen`, `dining`, `home_office`, `outdoor`, `kids_room`.                                                                                                                                                                                                                            |
| style                             | String  | The desired style of furnishing for the new variation. Must be in the following array: `["standard", "modern", "scandinavian", "industrial", "mid-century modern", "coastal", "american", "southwestern", "farmhouse", "luxury"]`                                                                                                                                |
| add\_virtually\_staged\_watermark | boolean |                                                                                                                                                                                                                                                                                                                                                                  |
| switch\_to\_queued\_immediately   | boolean | If true, will immediately switch render into "queued" status, then into "rendering" once the photo starts rendering.                                                                                                                                                                                                                                             |

{% tabs %}
{% tab title="200: OK " %}
Returns:

```json5
{
    result_image_url: string, // only if "wait_for_completion" was set to true
    render_id: string
}
```

Store the Render ID if you wish to create further variations for this photo, or look up the render state using `GET /v1/render`.&#x20;

If `wait_for_completion` was `false`, only the `render_id` will be returned and you'll have to look up the render state using `GET /v1/render`. Then, the output image of your variation will be appended to the `outputs` array and `status` will be `rendering` until the variation is done.
{% endtab %}

{% tab title="405: Method Not Allowed You're using a method other than POST" %}

{% endtab %}

{% tab title="401: Unauthorized API Key invalid or not provided" %}

{% endtab %}

{% tab title="403: Forbidden Authentication succeeded but your account doesn't have a plan with API access" %}

{% endtab %}

{% tab title="400: Bad Request render\_id not provided, or an invalid parameter provided in the request body" %}

{% endtab %}

{% tab title="404: Not Found Render with the passed ID not found " %}

{% endtab %}

{% tab title="500: Internal Server Error Unknown Error; reach out to support" %}

{% endtab %}
{% endtabs %}

## Get available room types & styles

<mark style="color:blue;">`GET`</mark> `https://api.virtualstagingai.app/v1/options`

Returns the available styles and room types. They need to be passed into other endpoints exactly as the same strings as returned here.

#### Headers

| Name                                            | Type   | Description                             |
| ----------------------------------------------- | ------ | --------------------------------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Set to "Api-Key {your\_api\_key\_here}" |

{% tabs %}
{% tab title="200: OK " %}
Returns:

```json5
{
    "styles": [
        "modern",
        "scandinavian",
        "industrial",
        "midcentury",
        "luxury",
        "farmhouse",
        "coastal",
        "standard"
    ],
    "roomTypes": [
        "living",
        "bed",
        "kitchen",
        "dining",
        "home_office",
        "outdoor",
        "kids_room"
    ]
}
```

{% endtab %}
{% endtabs %}


# Snippets

Customizable code snippets for our endpoints

Find more in the [Postman Workspace](/#postman-example-calls)

### Python - Create Render (from Image URL)

```python
import requests
import json

url = "https://api.virtualstagingai.app/v1/render/create"
VSAI_API_KEY = "..."

payload = json.dumps({
  "image_url": "https://firebasestorage.googleapis.com/v0/b/furniture-ai.appspot.com/o/users%2FX5AvCT5OUcaflJkXefQofEkDcW42%2Ffootage%2F6aec0ecf-8a52-4b49-a81d-031e91ce33e5-0001-022_181_HDR_4143.jpg?alt=media&token=28136001-ad8e-4c97-afe7-5f5b68054a1c",
  "room_type": "bed",
  "style": "modern",
  "wait_for_completion": False
})
headers = {
  'Authorization': 'Api-key ' + VSAI_API_KEY,
  'Content-Type': 'application/json'
}

response = requests.request("POST", url, headers=headers, data=payload)

print(response.text)

```

### Python - Create Render (from file, using multipart form-data)

```python

import requests
import json
from urllib.parse import urlencode, urljoin

url = "https://api.virtualstagingai.app/v1/render/create"
VSAI_API_KEY = "..."

def add_url_params(url, params):
    return url + '?' + urlencode(params).lower() if params else url

image_path = "/path/to/your/image.jpg"  # replace with your image's path

payload = {
  "room_type": "bed",
  "style": "modern",
  "wait_for_completion": False
}

headers = {
  'Authorization': 'Api-key ' + VSAI_API_KEY,
}

# we need to add payload as url params if we're using request body for the image
url = add_url_params(url, payload)

with open(image_path, 'rb') as image_file:
    files = {
        # important: 'file' has to be the key
        'file': (image_path, image_file),
    }
    response = requests.post(url, headers=headers, data=payload, files=files)

print(response.text)

```

### Node JS w/ Axios - Create Render

```javascript
const axios = require('axios');
const VSAI_API_KEY = "...";

const image_url = "...";
let data = JSON.stringify({
  "image_url": image_url,
  "room_type": "bed",
  "style": "modern",
  "wait_for_completion": false
});

const url = 'https://api.virtualstagingai.app/v1/render/create';
let config = {
  method: 'post',
  maxBodyLength: Infinity,
  url,
  headers: { 
    'Authorization': 'Api-key ' + VSAI_API_KEY, 
    'Content-Type': 'application/json'
  },
  data : data
};

axios.request(config)
.then((response) => {
  console.log(JSON.stringify(response.data));
})
.catch((error) => {
  console.log(error);
});

```


# Help & Support

We're here to support you

If you have any questions or suggestions, please don't hesitate to reach out to <info@virtualstagingai.app>, or in the live chat on [our website](https://virtualstagingai.app).

We're actively working on the API design and are happy to receive your feedback or adapt to your needs.

## Known Issues

#### Synchronous execution times out after 60s

This is a temporary issue with our hosting provider. If you use a configuration which incurrs a rendering time over 60s (e.g. Photorealism mode + decluttering) with `wait_for_completion: true`, the function will time out after 60 seconds.

Workaround: Use the following endpoints which bypass our hosting providers:\
\
**v1 API:**

* `/v1/render/create` -> `https://us-central1-furniture-ai.cloudfunctions.net/apiCreateRender`
* `/v1/render/create-variation` -> `https://us-central1-furniture-ai.cloudfunctions.net/apiCreateRenderVariation`

**v2 API:**

* `https://api.virtualstagingai.app/v2` -> `https://us-central1-furniture-ai.cloudfunctions.net/apiV2`


# Status

You can check the up-to-date status of our API on our [monitoring dashboard](https://vsai.checkly-dashboards.com/)

{% embed url="<https://vsai.checkly-dashboards.com/>" %}


# Core Concepts

## Renders & Variations

A **Render** represents a processing job for a single source image. When you create a Render, you specify:

* The source image URL(s)
* The type of processing you want (staging, day-to-dusk, or enhancement)
* How many Variations you want generated

A **Variation** is an individual result generated from that Render. For example, if you request 3 Variations of a virtual staging Render, you'll get 3 different furniture arrangements using the same style and room type.

## Processing Types

### Virtual Staging

Virtual staging allows you to add furniture and décor to empty rooms. When creating a staging Render, you specify:

* Room type (living room, bedroom, kitchen, etc.)
* Furniture style (modern, scandinavian, farmhouse, etc.)
* Whether to automatically remove existing furniture

The API will generate unique furniture arrangements based on your specifications. You can create multiple Variations to get different furniture layouts and arrangements.

### Day-to-Dusk

Day-to-dusk processing transforms daytime exterior photos into evening scenes. You can specify different sky styles:

* **Dusk** - Deep twilight tones
* **Golden** - Warm sunset lighting
* **Blue** - Early evening blue hour

### Image Enhancement

Enhancement processing improves the overall quality of your photos by:

* Adjusting brightness and contrast
* Enhancing colors
* Improving sharpness

## Creating Multiple Variations

There are two ways to create multiple Variations:

1. **Initial Render**: Specify `variation_count` when creating a new Render to generate multiple Variations immediately.
2. **Add Later**: Create additional Variations for an existing Render using the Variations endpoint. This is useful when you want to use the same source image but use a different configuration, such as creating another Staging Variation with a different furniture style, or creating a new Day to Dusk Variation with a different sky style

{% hint style="info" %}
Variation limits: Up to 20 Variations can be generated for each Render. Attempting to generate Variations beyond this limit will result in an error response from the API
{% endhint %}

## Furniture Analysis

Before creating a Staging Render, you can use the furniture analysis endpoint to:

1. Determine if furniture exists in the room
2. Generate a mask showing where existing furniture is located
3. Get a percentage of the image covered by furniture

This is useful for:

* Deciding whether to enable furniture removal
* Creating targeted removal masks for specific pieces
* Providing a base removal mask that can be edited by the user in your UI to show what furniture to remove

## Base Variations in Virtual Staging

A Base Variation represents an intermediate state where furniture has been removed from an image, serving as the foundation for subsequent furniture staging operations. Base Variations are not a special type of Variation, they are simply Removal Variations that can be used as the underlying image when generating future Staging Variations. Specifying Base Variations as part of your workflow provides greater control over the end result, as it ensures that furniture is staged onto a specific underlying image.

### How Base Variations are Generated

There are 2 cases in which Base Removal Variations will be automatically created:

* During initial Render creation when furniture Removal and Staging are both enabled
  * Note: If removal mode is "auto" and no furniture is detected, no removal variation will be created
* During additional Variation creation when furniture Removal and Staging are both enabled
  * Only occurs when no `base_variation_id` is specified

{% hint style="info" %}
**Example**: If creating a new Render with 3 Variations and using both Removal and Staging options, 6 Variations will be created. 3 final results that are staged with furniture, and 3 intermediate Variations where only the furniture has been removed.

If a further 2 Variations are created on this Render and the `base_variation_id` is not specified then 4 more Variations will be created: 2 for Removal and 2 for Staging.
{% endhint %}

Each Removal Variation will have been created independently as this method is more efficient and results in faster image generation. Thus a Removal Variation will be created for each Staging Variation, which can be retrieved and stored like any other type of Variation. If a Base Variation has been generated, its ID will be available as `base_variation_id` on the related Staging Variation response (either via the Webhook payload or via a <mark style="color:blue;">`GET`</mark> request).

### Specifying a Base Variation ID

Base Variations can be specified when generating new Variations via <mark style="color:orange;">`POST`</mark>` `` ``/renders/{render_id}/variations.` For example:

```json
{
    "config": {
        "type": "staging",
        "add_furniture": {
            "style": "modern",
            "room_type": "living",
            "base_variation_id": "existing-variation-id"  // Reference to existing removal variation
        }
    },
    "variation_count": 1
}
```

In the example above, we are creating a new Staging Render using a specific Base Variation. It is important to note that this Base Variation could have either been created automatically by one of the methods discussed above, or manually - there is no distinction between the two.

{% hint style="info" %}
**Example:** If creating a new Render with 2 Variations using only Removal options, 2 Removal Variations will be generated. Once these are complete, their IDs can be used as the `base_variation_id` for Staging Variations. If 2 new Staging Variations are created, each using the same Removal Variation as the base, then 4 Variations will have been generated in total: 2 Removal Variations, and 2 Staging Variations that have the same underlying image.
{% endhint %}

### Important Notes

* Base Variations can only be referenced within the same render. You cannot specify an ID from another Render
* You cannot specify a `base_variation_id` during initial Render creation as no Variations will be available yet. They can only be specified when creating more Variation via <mark style="color:orange;">`POST`</mark>`  ``/renders/{render_id}/variations`

### Best Practices with Base Variations

* If precise control of furniture removal is required, consider generating multiple Removal Variations with different masks and then creating Staging Variations using the best result
* If planning to create multiple Staging Variations after removing furniture from an image, store the Base Variation IDs to ensure that the underlying image will be consistent

## Asynchronous Processing & Webhooks

The v2 API supports webhooks to deliver payloads to any defined URL upon completion of Variations (as well as any error states).&#x20;

While the API supports synchronous processing via `wait_for_completion`, there's a current limitation with our hosting provider that causes requests to time out after 60 seconds. For operations that might take longer:

* Use webhooks (recommended for production use)
* Or use the direct v2 API endpoint if you must use synchronous processing:`https://us-central1-furniture-ai.cloudfunctions.net/apiV2`

#### Benefits of Webhooks

* Avoid timeout issues with longer renders
* Process multiple renders concurrently
* More resilient to network issues
* Better handling of retries and failures
* Reduced infrastructure cost by avoiding long running server requests


# Endpoints

The v2 API is available at the base URL `https://api.virtualstagingai.app/v2`.

The same API key can be used for both the v1 and v2 API. You can find or generate your API key in the [Settings](https://www.virtualstagingai.app/settings) section of your Virtual Staging AI account.&#x20;

Authenticate all requests by including an Authorization Header with the value (case sensitive):

`Authorization: Api-Key {your_api_key_here}`

## Check API status

> Returns 200 OK if the API is running

```json
{"openapi":"3.1.0","info":{"title":"Virtual Staging AI API","version":"2.0.0"},"servers":[{"url":"https://api.virtualstagingai.app/v2","description":"Production base URL."},{"url":"https://us-central1-furniture-ai.cloudfunctions.net/apiV2","description":"Long-running operations endpoint."}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"Authorization","description":"API key authentication. Use the format: Api-Key ${key}."}}},"paths":{"/status":{"get":{"summary":"Check API status","description":"Returns 200 OK if the API is running","responses":{"200":{"description":"API is operational"}}}}}}
```

## Get current user details

> Returns information about the authenticated user including their usage limits

```json
{"openapi":"3.1.0","info":{"title":"Virtual Staging AI API","version":"2.0.0"},"servers":[{"url":"https://api.virtualstagingai.app/v2","description":"Production base URL."},{"url":"https://us-central1-furniture-ai.cloudfunctions.net/apiV2","description":"Long-running operations endpoint."}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"Authorization","description":"API key authentication. Use the format: Api-Key ${key}."}},"responses":{"AuthError":{"description":"Authentication error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}},"UnexpectedError":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}}}},"paths":{"/user":{"get":{"summary":"Get current user details","description":"Returns information about the authenticated user including their usage limits","responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"user":{"type":"object","properties":{"email":{"type":"string"},"uid":{"type":"string"}}},"photoLimit":{"type":"object","properties":{"staging":{"oneOf":[{"type":"number"},{"type":"string","enum":["UNLIMITED"]}],"description":"The virtual staging photo limit. Can be a number or \"UNLIMITED\"."},"imageEditing":{"oneOf":[{"type":"number"},{"type":"string","enum":["UNLIMITED"]}],"description":"The image editing photo limit. Can be a number or \"UNLIMITED\"."}},"description":"The user's photo limit. Can be a number or the string \"UNLIMITED\" for unlimited plans."},"photosUsedThisPeriod":{"type":"object","properties":{"staging":{"type":"number","description":"Number of virtual staging photos used in the current period."},"imageEditing":{"type":"number","description":"Number of image editing photos used in the current period."}},"description":"Count of photos used in the current billing period by type."}}}}}},"401":{"$ref":"#/components/responses/AuthError"},"500":{"$ref":"#/components/responses/UnexpectedError"}}}}}}
```

## Get all renders

> Returns all renders for the authenticated user

```json
{"openapi":"3.1.0","info":{"title":"Virtual Staging AI API","version":"2.0.0"},"servers":[{"url":"https://api.virtualstagingai.app/v2","description":"Production base URL."},{"url":"https://us-central1-furniture-ai.cloudfunctions.net/apiV2","description":"Long-running operations endpoint."}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"Authorization","description":"API key authentication. Use the format: Api-Key ${key}."}},"schemas":{"Render":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for this render."},"created_at":{"type":"number","description":"Creation timestamp (epoch milliseconds)."},"queued_at":{"type":["number","null"],"description":"Timestamp when the render was queued for processing (epoch milliseconds)."},"variations":{"type":"object","properties":{"total_count":{"type":"number","description":"Total number of completed variations for this render."},"next_cursor":{"type":["string","null"],"description":"Cursor to use to get the next page of variations."},"items":{"type":"array","description":"List of variations for this render.","items":{"$ref":"#/components/schemas/Variation"}}},"required":["total_count"]},"eta":{"type":["number","null"],"description":"Estimated time remaining for the first variation to complete (epoch milliseconds timestamp)."}},"required":["id","created_at","variations","eta"]},"Variation":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for this variation."},"type":{"type":"string","enum":["staging","removal","enhancement","daytodusk","multi-view-staging"],"description":"Type of variation (staging, removal, etc.)."},"render_id":{"type":"string","description":"ID of the parent render this variation belongs to."},"created_at":{"type":"number","description":"Creation timestamp (epoch milliseconds)."},"status":{"type":"string","enum":["queued","rendering","done","error","idle","deleted"],"description":"Current status of the variation."},"result":{"oneOf":[{"$ref":"#/components/schemas/ImageResult"},{"type":"array","items":{"$ref":"#/components/schemas/ImageResult"}}],"description":"Result images (only present when status is 'done')."},"base_variation_id":{"description":"ID of the removal variation used as base, if this staging variation used a removal variation as its base.","type":"string"},"eta":{"type":["number","null"],"description":"Estimated time remaining for the variation to complete (epoch milliseconds timestamp)."},"config":{"oneOf":[{"$ref":"#/components/schemas/LegacyStagingConfig"},{"$ref":"#/components/schemas/VariationStagingConfigRead"},{"$ref":"#/components/schemas/DayToDuskConfig"},{"$ref":"#/components/schemas/EnhancementConfig"}],"description":"Configuration used to generate this variation."}},"required":["id","render_id","created_at","status","eta"]},"ImageResult":{"type":"object","properties":{"url":{"type":"string","description":"Original image URL."},"optimized_url":{"type":["string","null"],"description":"Optimized (compressed) version URL."},"thumbnail_url":{"type":["string","null"],"description":"Thumbnail version URL."}},"required":["url"]},"LegacyStagingConfig":{"type":"object","properties":{"type":{"type":"string","enum":["legacy_staging"]},"room_type":{"$ref":"#/components/schemas/AnyRoomType"},"style":{"$ref":"#/components/schemas/FurnitureStyles"}},"required":["room_type","style","type"]},"AnyRoomType":{"oneOf":[{"$ref":"#/components/schemas/RoomType"},{"type":"string","enum":["bathroom"],"deprecated":true,"description":"Deprecated. Not accepted for new staging requests; may appear in historical variation data."}],"description":"Room type (active or deprecated). Use for reading variation/config output only."},"RoomType":{"type":"string","enum":["living","bed","kitchen","dining","home_office","outdoor","kids_room"],"description":"Room types accepted for new staging requests (bathroom excluded)."},"FurnitureStyles":{"oneOf":[{"type":"string","enum":["standard","modern","scandinavian","industrial","midcentury","luxury","farmhouse","coastal"],"description":"Available furniture styles for staging."},{"type":"string","enum":["american","southwestern","hamptons"],"deprecated":true,"description":"Deprecated styles. These will be mapped to the closest existing style and are available only for backwards compatibility."}]},"VariationStagingConfigRead":{"type":"object","properties":{"type":{"type":"string","enum":["staging"]},"output_resolution":{"$ref":"#/components/schemas/OutputResolution"},"add_virtually_staged_watermark":{"type":["boolean","null"],"description":"Whether to add a 'virtually staged' watermark to the output image."},"add_furniture":{"type":"object","properties":{"style":{"$ref":"#/components/schemas/FurnitureStyles"},"room_type":{"$ref":"#/components/schemas/AnyRoomType"},"base_variation_id":{"description":"ID of an existing removal variation that is being used as the base for this staging variation. This should be used to create multiple staging variations from a single removal variation.","type":"string"}},"required":["style","room_type"],"description":"Configuration for adding furniture to the image."},"remove_furniture":{"type":"object","properties":{"mode":{"type":"string","enum":["on","off","auto"],"description":"Furniture removal mode to use."},"mask_url":{"$ref":"#/components/schemas/ImageUrl","description":"URL of the mask image indicating areas to remove furniture from."}},"required":["mode"],"description":"Configuration for removing furniture from the image."}},"required":["type"]},"OutputResolution":{"oneOf":[{"type":"integer","enum":[1536],"description":"Force output to 1536px resolution regardless of input size"},{"type":"string","enum":["default"],"description":"Smart resolution: For Staging renders, upscale to 1536px minimum, or 3072px if input is larger than 1536px. For Enhancements and Day to Dusk renders, return size as-is to a maximum of 3072px."}],"default":"default","description":"Output image resolution. Use 'default' for smart resolution handling or 1536 to force 1536px output. Defaults to 'default' when omitted."},"ImageUrl":{"type":"string","pattern":"^(https?:\\/\\/[^\\s]+|data:image\\/[a-zA-Z+]+;base64,[A-Za-z0-9+/=]+)$","description":"URL for an image, either HTTP/HTTPS URL or base64 encoded data URL."},"DayToDuskConfig":{"type":"object","properties":{"type":{"type":"string","enum":["daytodusk"]},"output_resolution":{"$ref":"#/components/schemas/OutputResolution"},"sky_style":{"$ref":"#/components/schemas/SkyStyle"}},"required":["sky_style","type"]},"SkyStyle":{"type":"string","enum":["dusk","golden","blue"],"description":"Available sky styles for day-to-dusk transformations."},"EnhancementConfig":{"type":"object","properties":{"type":{"type":"string","enum":["enhancement"]},"output_resolution":{"$ref":"#/components/schemas/OutputResolution"}},"required":["type"]}},"responses":{"ValidationError":{"description":"Validation error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"errors":{"type":"array","items":{"type":"string"}}},"required":["message"]}}}},"AuthError":{"description":"Authentication error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}},"UnexpectedError":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}}}},"paths":{"/renders":{"get":{"summary":"Get all renders","description":"Returns all renders for the authenticated user","parameters":[{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"in":"query","name":"cursor","schema":{"type":"string"},"description":"Render ID to start after"},{"in":"query","name":"order","description":"The order in which to display renders. Based on their creation date.","schema":{"type":"string","enum":["asc","desc"],"default":"desc"}}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"total_count":{"type":"number","description":"The total number of completed variations for this render."},"next_cursor":{"type":["string","null"],"description":"The cursor to use to get the next page of renders."},"items":{"type":"array","items":{"$ref":"#/components/schemas/Render","description":"A list of renders."}}}}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/AuthError"},"500":{"$ref":"#/components/responses/UnexpectedError"}}}}}}
```

{% hint style="warning" %}
**Deprecated styles:** Please note that the `hamptons`, `american`, and `southwestern` styles have been deprecated, and now are mapped to other existing styles. The API will continue to support their use, but they may be removed in future versions
{% endhint %}

## Create a new render

> Create a new render with either a single configuration or multiple configurations.\
> \
> \*\*Single Config Format\*\*: Use this for creating a single render with one configuration.\
> \*\*Multi Config Format\*\*: Use this for creating a single render with multiple configurations. This can be used to generate variations with different room styles, furniture etc. without having to make a new request.\
> \
> \## Examples\
> \
> \### Single Config (Staging)\
> \`\`\`json\
> {\
> &#x20; "config": {\
> &#x20;   "type": "staging",\
> &#x20;   "add\_furniture": {\
> &#x20;     "room\_type": "living",\
> &#x20;     "style": "modern"\
> &#x20;   }\
> &#x20; },\
> &#x20; "image\_url": "<https://example.com/image.jpg",\\>
> &#x20; "variation\_count": 3,\
> &#x20; "wait\_for\_completion": false\
> }\
> \`\`\`\
> \
> \### Multi Config (Multiple Staging Variations)\
> \`\`\`json\
> {\
> &#x20; "configs": \[\
> &#x20;   {\
> &#x20;     "type": "staging",\
> &#x20;     "add\_furniture": {\
> &#x20;       "room\_type": "living",\
> &#x20;       "style": "modern"\
> &#x20;     },\
> &#x20;     "variation\_count": 2\
> &#x20;   },\
> &#x20;   {\
> &#x20;     "type": "staging",\
> &#x20;     "add\_furniture": {\
> &#x20;       "room\_type": "living",\
> &#x20;       "style": "scandinavian"\
> &#x20;     },\
> &#x20;     "variation\_count": 1\
> &#x20;   }\
> &#x20; ],\
> &#x20; "image\_url": "<https://example.com/image.jpg",\\>
> &#x20; "wait\_for\_completion": true\
> }\
> \`\`\`\
> \
> \### Single Config (Day to Dusk)\
> \`\`\`json\
> {\
> &#x20; "config": {\
> &#x20;   "type": "daytodusk",\
> &#x20;   "sky\_style": "golden"\
> &#x20; },\
> &#x20; "image\_url": "<https://example.com/image.jpg",\\>
> &#x20; "variation\_count": 1\
> }\
> \`\`\`<br>

````json
{"openapi":"3.1.0","info":{"title":"Virtual Staging AI API","version":"2.0.0"},"servers":[{"url":"https://api.virtualstagingai.app/v2","description":"Production base URL."},{"url":"https://us-central1-furniture-ai.cloudfunctions.net/apiV2","description":"Long-running operations endpoint."}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"Authorization","description":"API key authentication. Use the format: Api-Key ${key}."}},"schemas":{"RenderStagingConfig":{"type":"object","properties":{"type":{"type":"string","enum":["staging"]},"output_resolution":{"$ref":"#/components/schemas/OutputResolution"},"add_virtually_staged_watermark":{"type":["boolean","null"],"description":"Whether to add a 'virtually staged' watermark to the output image."},"add_furniture":{"type":"object","properties":{"style":{"$ref":"#/components/schemas/FurnitureStyles"},"room_type":{"$ref":"#/components/schemas/RoomType"}},"required":["style","room_type"],"description":"Configuration for adding furniture to the image."},"remove_furniture":{"type":"object","properties":{"mode":{"type":"string","enum":["on","off","auto"],"description":"Furniture removal mode to use."},"mask_url":{"$ref":"#/components/schemas/ImageUrl","description":"URL of the mask image indicating areas to remove furniture from."}},"required":["mode"],"description":"Configuration for removing furniture from the image."}},"required":["type"]},"OutputResolution":{"oneOf":[{"type":"integer","enum":[1536],"description":"Force output to 1536px resolution regardless of input size"},{"type":"string","enum":["default"],"description":"Smart resolution: For Staging renders, upscale to 1536px minimum, or 3072px if input is larger than 1536px. For Enhancements and Day to Dusk renders, return size as-is to a maximum of 3072px."}],"default":"default","description":"Output image resolution. Use 'default' for smart resolution handling or 1536 to force 1536px output. Defaults to 'default' when omitted."},"FurnitureStyles":{"oneOf":[{"type":"string","enum":["standard","modern","scandinavian","industrial","midcentury","luxury","farmhouse","coastal"],"description":"Available furniture styles for staging."},{"type":"string","enum":["american","southwestern","hamptons"],"deprecated":true,"description":"Deprecated styles. These will be mapped to the closest existing style and are available only for backwards compatibility."}]},"RoomType":{"type":"string","enum":["living","bed","kitchen","dining","home_office","outdoor","kids_room"],"description":"Room types accepted for new staging requests (bathroom excluded)."},"ImageUrl":{"type":"string","pattern":"^(https?:\\/\\/[^\\s]+|data:image\\/[a-zA-Z+]+;base64,[A-Za-z0-9+/=]+)$","description":"URL for an image, either HTTP/HTTPS URL or base64 encoded data URL."},"DayToDuskConfig":{"type":"object","properties":{"type":{"type":"string","enum":["daytodusk"]},"output_resolution":{"$ref":"#/components/schemas/OutputResolution"},"sky_style":{"$ref":"#/components/schemas/SkyStyle"}},"required":["sky_style","type"]},"SkyStyle":{"type":"string","enum":["dusk","golden","blue"],"description":"Available sky styles for day-to-dusk transformations."},"EnhancementConfig":{"type":"object","properties":{"type":{"type":"string","enum":["enhancement"]},"output_resolution":{"$ref":"#/components/schemas/OutputResolution"}},"required":["type"]},"VariationStagingConfigWithVariationCount":{"allOf":[{"$ref":"#/components/schemas/VariationStagingConfig"},{"type":"object","properties":{"variation_count":{"type":"integer","minimum":1,"description":"Number of variations to create with this configuration."}},"required":["variation_count"]}]},"VariationStagingConfig":{"type":"object","properties":{"type":{"type":"string","enum":["staging"]},"output_resolution":{"$ref":"#/components/schemas/OutputResolution"},"add_virtually_staged_watermark":{"type":["boolean","null"],"description":"Whether to add a 'virtually staged' watermark to the output image."},"add_furniture":{"type":"object","properties":{"style":{"$ref":"#/components/schemas/FurnitureStyles"},"room_type":{"$ref":"#/components/schemas/RoomType"},"base_variation_id":{"description":"ID of an existing removal variation that is being used as the base for this staging variation. This should be used to create multiple staging variations from a single removal variation.","type":"string"}},"required":["style","room_type"],"description":"Configuration for adding furniture to the image."},"remove_furniture":{"type":"object","properties":{"mode":{"type":"string","enum":["on","off","auto"],"description":"Furniture removal mode to use."},"mask_url":{"$ref":"#/components/schemas/ImageUrl","description":"URL of the mask image indicating areas to remove furniture from."}},"required":["mode"],"description":"Configuration for removing furniture from the image."}},"required":["type"]},"DayToDuskConfigWithVariationCount":{"allOf":[{"$ref":"#/components/schemas/DayToDuskConfig"},{"type":"object","properties":{"variation_count":{"type":"integer","minimum":1,"description":"Number of variations to create with this configuration."}},"required":["variation_count"]}]},"EnhancementConfigWithVariationCount":{"allOf":[{"$ref":"#/components/schemas/EnhancementConfig"},{"type":"object","properties":{"variation_count":{"type":"integer","minimum":1,"description":"Number of variations to create with this configuration."}},"required":["variation_count"]}]},"DoneWebhookResponse":{"type":"object","properties":{"render_id":{"type":"string","description":"ID of the render that this variation belongs to."},"variation_id":{"type":"string","description":"ID of the variation that completed."},"variation_type":{"type":"string","enum":["staging","removal","enhancement","daytodusk","multi-view-staging"],"description":"Type of variation that completed."},"base_variation_id":{"type":["string","null"],"description":"ID of the removal variation used as base, if this staging variation used a removal variation as its base."},"timestamp":{"type":"number","description":"Event timestamp (epoch milliseconds)."},"event_type":{"type":"string","enum":["done"],"description":"Event type indicating successful completion."},"result":{"oneOf":[{"$ref":"#/components/schemas/ImageResult"},{"type":"array","items":{"$ref":"#/components/schemas/ImageResult"}}],"description":"Generated result images."}},"required":["event_type","result","render_id","variation_id","variation_type","timestamp","base_variation_id"]},"ImageResult":{"type":"object","properties":{"url":{"type":"string","description":"Original image URL."},"optimized_url":{"type":["string","null"],"description":"Optimized (compressed) version URL."},"thumbnail_url":{"type":["string","null"],"description":"Thumbnail version URL."}},"required":["url"]},"ErrorWebhookResponse":{"type":"object","properties":{"render_id":{"type":"string","description":"ID of the render that this variation belongs to."},"variation_id":{"type":"string","description":"ID of the variation that failed."},"variation_type":{"type":"string","enum":["staging","removal","enhancement","daytodusk","multi-view-staging"],"description":"Type of variation that failed."},"timestamp":{"type":"number","description":"Event timestamp (epoch milliseconds)."},"event_type":{"type":"string","enum":["error"],"description":"Event type indicating an error occurred."},"error_message":{"type":"string","description":"Detailed error message explaining the failure."}},"required":["event_type","error_message","render_id","variation_id","variation_type","timestamp"]},"UpdateWebhookResponse":{"type":"object","properties":{"render_id":{"type":"string","description":"ID of the render that this variation belongs to."},"variation_id":{"type":"string","description":"ID of the variation that was updated."},"variation_type":{"type":"string","enum":["staging","removal","enhancement","daytodusk","multi-view-staging"],"description":"Type of variation that was updated."},"timestamp":{"type":"number","description":"Event timestamp (epoch milliseconds)."},"event_type":{"type":"string","enum":["update"],"description":"Event type indicating a status update."},"variation_status":{"type":"string","enum":["queued","rendering","done","error","idle","deleted"],"description":"Current status of the variation."},"eta":{"type":"number","description":"Estimated time remaining for the variation to complete (epoch milliseconds timestamp)."}},"required":["event_type","variation_status","eta","render_id","variation_id","variation_type","timestamp"]},"Render":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for this render."},"created_at":{"type":"number","description":"Creation timestamp (epoch milliseconds)."},"queued_at":{"type":["number","null"],"description":"Timestamp when the render was queued for processing (epoch milliseconds)."},"variations":{"type":"object","properties":{"total_count":{"type":"number","description":"Total number of completed variations for this render."},"next_cursor":{"type":["string","null"],"description":"Cursor to use to get the next page of variations."},"items":{"type":"array","description":"List of variations for this render.","items":{"$ref":"#/components/schemas/Variation"}}},"required":["total_count"]},"eta":{"type":["number","null"],"description":"Estimated time remaining for the first variation to complete (epoch milliseconds timestamp)."}},"required":["id","created_at","variations","eta"]},"Variation":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for this variation."},"type":{"type":"string","enum":["staging","removal","enhancement","daytodusk","multi-view-staging"],"description":"Type of variation (staging, removal, etc.)."},"render_id":{"type":"string","description":"ID of the parent render this variation belongs to."},"created_at":{"type":"number","description":"Creation timestamp (epoch milliseconds)."},"status":{"type":"string","enum":["queued","rendering","done","error","idle","deleted"],"description":"Current status of the variation."},"result":{"oneOf":[{"$ref":"#/components/schemas/ImageResult"},{"type":"array","items":{"$ref":"#/components/schemas/ImageResult"}}],"description":"Result images (only present when status is 'done')."},"base_variation_id":{"description":"ID of the removal variation used as base, if this staging variation used a removal variation as its base.","type":"string"},"eta":{"type":["number","null"],"description":"Estimated time remaining for the variation to complete (epoch milliseconds timestamp)."},"config":{"oneOf":[{"$ref":"#/components/schemas/LegacyStagingConfig"},{"$ref":"#/components/schemas/VariationStagingConfigRead"},{"$ref":"#/components/schemas/DayToDuskConfig"},{"$ref":"#/components/schemas/EnhancementConfig"}],"description":"Configuration used to generate this variation."}},"required":["id","render_id","created_at","status","eta"]},"LegacyStagingConfig":{"type":"object","properties":{"type":{"type":"string","enum":["legacy_staging"]},"room_type":{"$ref":"#/components/schemas/AnyRoomType"},"style":{"$ref":"#/components/schemas/FurnitureStyles"}},"required":["room_type","style","type"]},"AnyRoomType":{"oneOf":[{"$ref":"#/components/schemas/RoomType"},{"type":"string","enum":["bathroom"],"deprecated":true,"description":"Deprecated. Not accepted for new staging requests; may appear in historical variation data."}],"description":"Room type (active or deprecated). Use for reading variation/config output only."},"VariationStagingConfigRead":{"type":"object","properties":{"type":{"type":"string","enum":["staging"]},"output_resolution":{"$ref":"#/components/schemas/OutputResolution"},"add_virtually_staged_watermark":{"type":["boolean","null"],"description":"Whether to add a 'virtually staged' watermark to the output image."},"add_furniture":{"type":"object","properties":{"style":{"$ref":"#/components/schemas/FurnitureStyles"},"room_type":{"$ref":"#/components/schemas/AnyRoomType"},"base_variation_id":{"description":"ID of an existing removal variation that is being used as the base for this staging variation. This should be used to create multiple staging variations from a single removal variation.","type":"string"}},"required":["style","room_type"],"description":"Configuration for adding furniture to the image."},"remove_furniture":{"type":"object","properties":{"mode":{"type":"string","enum":["on","off","auto"],"description":"Furniture removal mode to use."},"mask_url":{"$ref":"#/components/schemas/ImageUrl","description":"URL of the mask image indicating areas to remove furniture from."}},"required":["mode"],"description":"Configuration for removing furniture from the image."}},"required":["type"]}},"responses":{"ValidationError":{"description":"Validation error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"errors":{"type":"array","items":{"type":"string"}}},"required":["message"]}}}},"AuthError":{"description":"Authentication error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}},"ForbiddenError":{"description":"Forbidden error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}},"UnexpectedError":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}}}},"paths":{"/renders":{"post":{"summary":"Create a new render","description":"Create a new render with either a single configuration or multiple configurations.\n\n**Single Config Format**: Use this for creating a single render with one configuration.\n**Multi Config Format**: Use this for creating a single render with multiple configurations. This can be used to generate variations with different room styles, furniture etc. without having to make a new request.\n\n## Examples\n\n### Single Config (Staging)\n```json\n{\n  \"config\": {\n    \"type\": \"staging\",\n    \"add_furniture\": {\n      \"room_type\": \"living\",\n      \"style\": \"modern\"\n    }\n  },\n  \"image_url\": \"https://example.com/image.jpg\",\n  \"variation_count\": 3,\n  \"wait_for_completion\": false\n}\n```\n\n### Multi Config (Multiple Staging Variations)\n```json\n{\n  \"configs\": [\n    {\n      \"type\": \"staging\",\n      \"add_furniture\": {\n        \"room_type\": \"living\",\n        \"style\": \"modern\"\n      },\n      \"variation_count\": 2\n    },\n    {\n      \"type\": \"staging\",\n      \"add_furniture\": {\n        \"room_type\": \"living\",\n        \"style\": \"scandinavian\"\n      },\n      \"variation_count\": 1\n    }\n  ],\n  \"image_url\": \"https://example.com/image.jpg\",\n  \"wait_for_completion\": true\n}\n```\n\n### Single Config (Day to Dusk)\n```json\n{\n  \"config\": {\n    \"type\": \"daytodusk\",\n    \"sky_style\": \"golden\"\n  },\n  \"image_url\": \"https://example.com/image.jpg\",\n  \"variation_count\": 1\n}\n```\n","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"type":"object","required":["config","image_url","variation_count"],"additionalProperties":false,"properties":{"config":{"oneOf":[{"$ref":"#/components/schemas/RenderStagingConfig"},{"$ref":"#/components/schemas/DayToDuskConfig"},{"$ref":"#/components/schemas/EnhancementConfig"}]},"image_url":{"$ref":"#/components/schemas/ImageUrl"},"variation_count":{"type":"integer","minimum":1,"description":"Number of variations to create with this configuration"},"webhook_url":{"type":["string","null"],"format":"uri"},"wait_for_completion":{"type":["boolean","null"],"default":false}}},{"type":"object","required":["configs","image_url"],"additionalProperties":false,"properties":{"configs":{"oneOf":[{"type":"array","items":{"$ref":"#/components/schemas/VariationStagingConfigWithVariationCount"},"minItems":1,"description":"Array of staging configurations, each with its own variation count"},{"type":"array","items":{"$ref":"#/components/schemas/DayToDuskConfigWithVariationCount"},"minItems":1,"description":"Array of day-to-dusk configurations, each with its own variation count"},{"type":"array","items":{"$ref":"#/components/schemas/EnhancementConfigWithVariationCount"},"minItems":1,"description":"Array of enhancement configurations, each with its own variation count"}]},"image_url":{"$ref":"#/components/schemas/ImageUrl"},"webhook_url":{"type":["string","null"],"format":"uri"},"wait_for_completion":{"type":["boolean","null"],"default":false}}}]}}}},"callbacks":{"renderWebhook":{"{$request.body.webhook_url}":{"post":{"description":"Webhook response sent upon the completion of each variation that is part of the render","requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/DoneWebhookResponse"},{"$ref":"#/components/schemas/ErrorWebhookResponse"},{"$ref":"#/components/schemas/UpdateWebhookResponse"}]}}}},"responses":{"200":{"description":"Webhook received successfully"}}}}}},"responses":{"200":{"description":"Render created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Render"}}}},"201":{"description":"Render created and queued for processing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Render"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/AuthError"},"403":{"$ref":"#/components/responses/ForbiddenError"},"500":{"$ref":"#/components/responses/UnexpectedError"}}}}}}
````

## Get render details

> Returns details about a render including the status, variations, and result URL

```json
{"openapi":"3.1.0","info":{"title":"Virtual Staging AI API","version":"2.0.0"},"servers":[{"url":"https://api.virtualstagingai.app/v2","description":"Production base URL."},{"url":"https://us-central1-furniture-ai.cloudfunctions.net/apiV2","description":"Long-running operations endpoint."}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"Authorization","description":"API key authentication. Use the format: Api-Key ${key}."}},"schemas":{"Render":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for this render."},"created_at":{"type":"number","description":"Creation timestamp (epoch milliseconds)."},"queued_at":{"type":["number","null"],"description":"Timestamp when the render was queued for processing (epoch milliseconds)."},"variations":{"type":"object","properties":{"total_count":{"type":"number","description":"Total number of completed variations for this render."},"next_cursor":{"type":["string","null"],"description":"Cursor to use to get the next page of variations."},"items":{"type":"array","description":"List of variations for this render.","items":{"$ref":"#/components/schemas/Variation"}}},"required":["total_count"]},"eta":{"type":["number","null"],"description":"Estimated time remaining for the first variation to complete (epoch milliseconds timestamp)."}},"required":["id","created_at","variations","eta"]},"Variation":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for this variation."},"type":{"type":"string","enum":["staging","removal","enhancement","daytodusk","multi-view-staging"],"description":"Type of variation (staging, removal, etc.)."},"render_id":{"type":"string","description":"ID of the parent render this variation belongs to."},"created_at":{"type":"number","description":"Creation timestamp (epoch milliseconds)."},"status":{"type":"string","enum":["queued","rendering","done","error","idle","deleted"],"description":"Current status of the variation."},"result":{"oneOf":[{"$ref":"#/components/schemas/ImageResult"},{"type":"array","items":{"$ref":"#/components/schemas/ImageResult"}}],"description":"Result images (only present when status is 'done')."},"base_variation_id":{"description":"ID of the removal variation used as base, if this staging variation used a removal variation as its base.","type":"string"},"eta":{"type":["number","null"],"description":"Estimated time remaining for the variation to complete (epoch milliseconds timestamp)."},"config":{"oneOf":[{"$ref":"#/components/schemas/LegacyStagingConfig"},{"$ref":"#/components/schemas/VariationStagingConfigRead"},{"$ref":"#/components/schemas/DayToDuskConfig"},{"$ref":"#/components/schemas/EnhancementConfig"}],"description":"Configuration used to generate this variation."}},"required":["id","render_id","created_at","status","eta"]},"ImageResult":{"type":"object","properties":{"url":{"type":"string","description":"Original image URL."},"optimized_url":{"type":["string","null"],"description":"Optimized (compressed) version URL."},"thumbnail_url":{"type":["string","null"],"description":"Thumbnail version URL."}},"required":["url"]},"LegacyStagingConfig":{"type":"object","properties":{"type":{"type":"string","enum":["legacy_staging"]},"room_type":{"$ref":"#/components/schemas/AnyRoomType"},"style":{"$ref":"#/components/schemas/FurnitureStyles"}},"required":["room_type","style","type"]},"AnyRoomType":{"oneOf":[{"$ref":"#/components/schemas/RoomType"},{"type":"string","enum":["bathroom"],"deprecated":true,"description":"Deprecated. Not accepted for new staging requests; may appear in historical variation data."}],"description":"Room type (active or deprecated). Use for reading variation/config output only."},"RoomType":{"type":"string","enum":["living","bed","kitchen","dining","home_office","outdoor","kids_room"],"description":"Room types accepted for new staging requests (bathroom excluded)."},"FurnitureStyles":{"oneOf":[{"type":"string","enum":["standard","modern","scandinavian","industrial","midcentury","luxury","farmhouse","coastal"],"description":"Available furniture styles for staging."},{"type":"string","enum":["american","southwestern","hamptons"],"deprecated":true,"description":"Deprecated styles. These will be mapped to the closest existing style and are available only for backwards compatibility."}]},"VariationStagingConfigRead":{"type":"object","properties":{"type":{"type":"string","enum":["staging"]},"output_resolution":{"$ref":"#/components/schemas/OutputResolution"},"add_virtually_staged_watermark":{"type":["boolean","null"],"description":"Whether to add a 'virtually staged' watermark to the output image."},"add_furniture":{"type":"object","properties":{"style":{"$ref":"#/components/schemas/FurnitureStyles"},"room_type":{"$ref":"#/components/schemas/AnyRoomType"},"base_variation_id":{"description":"ID of an existing removal variation that is being used as the base for this staging variation. This should be used to create multiple staging variations from a single removal variation.","type":"string"}},"required":["style","room_type"],"description":"Configuration for adding furniture to the image."},"remove_furniture":{"type":"object","properties":{"mode":{"type":"string","enum":["on","off","auto"],"description":"Furniture removal mode to use."},"mask_url":{"$ref":"#/components/schemas/ImageUrl","description":"URL of the mask image indicating areas to remove furniture from."}},"required":["mode"],"description":"Configuration for removing furniture from the image."}},"required":["type"]},"OutputResolution":{"oneOf":[{"type":"integer","enum":[1536],"description":"Force output to 1536px resolution regardless of input size"},{"type":"string","enum":["default"],"description":"Smart resolution: For Staging renders, upscale to 1536px minimum, or 3072px if input is larger than 1536px. For Enhancements and Day to Dusk renders, return size as-is to a maximum of 3072px."}],"default":"default","description":"Output image resolution. Use 'default' for smart resolution handling or 1536 to force 1536px output. Defaults to 'default' when omitted."},"ImageUrl":{"type":"string","pattern":"^(https?:\\/\\/[^\\s]+|data:image\\/[a-zA-Z+]+;base64,[A-Za-z0-9+/=]+)$","description":"URL for an image, either HTTP/HTTPS URL or base64 encoded data URL."},"DayToDuskConfig":{"type":"object","properties":{"type":{"type":"string","enum":["daytodusk"]},"output_resolution":{"$ref":"#/components/schemas/OutputResolution"},"sky_style":{"$ref":"#/components/schemas/SkyStyle"}},"required":["sky_style","type"]},"SkyStyle":{"type":"string","enum":["dusk","golden","blue"],"description":"Available sky styles for day-to-dusk transformations."},"EnhancementConfig":{"type":"object","properties":{"type":{"type":"string","enum":["enhancement"]},"output_resolution":{"$ref":"#/components/schemas/OutputResolution"}},"required":["type"]}},"responses":{"AuthError":{"description":"Authentication error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}},"ValidationError":{"description":"Validation error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"errors":{"type":"array","items":{"type":"string"}}},"required":["message"]}}}},"UnexpectedError":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}}}},"paths":{"/renders/{render_id}":{"get":{"summary":"Get render details","description":"Returns details about a render including the status, variations, and result URL","parameters":[{"in":"path","name":"render_id","required":true,"schema":{"type":"string"},"description":"The ID of the render to get details for"},{"in":"query","name":"include_variations","schema":{"type":"boolean","default":false}},{"in":"query","name":"variations_limit","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"in":"query","name":"variations_cursor","schema":{"type":"string"},"description":"Variation ID to start after"},{"in":"query","name":"variations_order","description":"The order in which to display variations. Based on their creation date.","schema":{"type":"string","enum":["asc","desc"],"default":"asc"}}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Render"}}}},"401":{"$ref":"#/components/responses/AuthError"},"404":{"$ref":"#/components/responses/ValidationError"},"500":{"$ref":"#/components/responses/UnexpectedError"}}}}}}
```

## Get variation details

> Returns details about a variation including the status and result URL

```json
{"openapi":"3.1.0","info":{"title":"Virtual Staging AI API","version":"2.0.0"},"servers":[{"url":"https://api.virtualstagingai.app/v2","description":"Production base URL."},{"url":"https://us-central1-furniture-ai.cloudfunctions.net/apiV2","description":"Long-running operations endpoint."}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"Authorization","description":"API key authentication. Use the format: Api-Key ${key}."}},"schemas":{"Variation":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for this variation."},"type":{"type":"string","enum":["staging","removal","enhancement","daytodusk","multi-view-staging"],"description":"Type of variation (staging, removal, etc.)."},"render_id":{"type":"string","description":"ID of the parent render this variation belongs to."},"created_at":{"type":"number","description":"Creation timestamp (epoch milliseconds)."},"status":{"type":"string","enum":["queued","rendering","done","error","idle","deleted"],"description":"Current status of the variation."},"result":{"oneOf":[{"$ref":"#/components/schemas/ImageResult"},{"type":"array","items":{"$ref":"#/components/schemas/ImageResult"}}],"description":"Result images (only present when status is 'done')."},"base_variation_id":{"description":"ID of the removal variation used as base, if this staging variation used a removal variation as its base.","type":"string"},"eta":{"type":["number","null"],"description":"Estimated time remaining for the variation to complete (epoch milliseconds timestamp)."},"config":{"oneOf":[{"$ref":"#/components/schemas/LegacyStagingConfig"},{"$ref":"#/components/schemas/VariationStagingConfigRead"},{"$ref":"#/components/schemas/DayToDuskConfig"},{"$ref":"#/components/schemas/EnhancementConfig"}],"description":"Configuration used to generate this variation."}},"required":["id","render_id","created_at","status","eta"]},"ImageResult":{"type":"object","properties":{"url":{"type":"string","description":"Original image URL."},"optimized_url":{"type":["string","null"],"description":"Optimized (compressed) version URL."},"thumbnail_url":{"type":["string","null"],"description":"Thumbnail version URL."}},"required":["url"]},"LegacyStagingConfig":{"type":"object","properties":{"type":{"type":"string","enum":["legacy_staging"]},"room_type":{"$ref":"#/components/schemas/AnyRoomType"},"style":{"$ref":"#/components/schemas/FurnitureStyles"}},"required":["room_type","style","type"]},"AnyRoomType":{"oneOf":[{"$ref":"#/components/schemas/RoomType"},{"type":"string","enum":["bathroom"],"deprecated":true,"description":"Deprecated. Not accepted for new staging requests; may appear in historical variation data."}],"description":"Room type (active or deprecated). Use for reading variation/config output only."},"RoomType":{"type":"string","enum":["living","bed","kitchen","dining","home_office","outdoor","kids_room"],"description":"Room types accepted for new staging requests (bathroom excluded)."},"FurnitureStyles":{"oneOf":[{"type":"string","enum":["standard","modern","scandinavian","industrial","midcentury","luxury","farmhouse","coastal"],"description":"Available furniture styles for staging."},{"type":"string","enum":["american","southwestern","hamptons"],"deprecated":true,"description":"Deprecated styles. These will be mapped to the closest existing style and are available only for backwards compatibility."}]},"VariationStagingConfigRead":{"type":"object","properties":{"type":{"type":"string","enum":["staging"]},"output_resolution":{"$ref":"#/components/schemas/OutputResolution"},"add_virtually_staged_watermark":{"type":["boolean","null"],"description":"Whether to add a 'virtually staged' watermark to the output image."},"add_furniture":{"type":"object","properties":{"style":{"$ref":"#/components/schemas/FurnitureStyles"},"room_type":{"$ref":"#/components/schemas/AnyRoomType"},"base_variation_id":{"description":"ID of an existing removal variation that is being used as the base for this staging variation. This should be used to create multiple staging variations from a single removal variation.","type":"string"}},"required":["style","room_type"],"description":"Configuration for adding furniture to the image."},"remove_furniture":{"type":"object","properties":{"mode":{"type":"string","enum":["on","off","auto"],"description":"Furniture removal mode to use."},"mask_url":{"$ref":"#/components/schemas/ImageUrl","description":"URL of the mask image indicating areas to remove furniture from."}},"required":["mode"],"description":"Configuration for removing furniture from the image."}},"required":["type"]},"OutputResolution":{"oneOf":[{"type":"integer","enum":[1536],"description":"Force output to 1536px resolution regardless of input size"},{"type":"string","enum":["default"],"description":"Smart resolution: For Staging renders, upscale to 1536px minimum, or 3072px if input is larger than 1536px. For Enhancements and Day to Dusk renders, return size as-is to a maximum of 3072px."}],"default":"default","description":"Output image resolution. Use 'default' for smart resolution handling or 1536 to force 1536px output. Defaults to 'default' when omitted."},"ImageUrl":{"type":"string","pattern":"^(https?:\\/\\/[^\\s]+|data:image\\/[a-zA-Z+]+;base64,[A-Za-z0-9+/=]+)$","description":"URL for an image, either HTTP/HTTPS URL or base64 encoded data URL."},"DayToDuskConfig":{"type":"object","properties":{"type":{"type":"string","enum":["daytodusk"]},"output_resolution":{"$ref":"#/components/schemas/OutputResolution"},"sky_style":{"$ref":"#/components/schemas/SkyStyle"}},"required":["sky_style","type"]},"SkyStyle":{"type":"string","enum":["dusk","golden","blue"],"description":"Available sky styles for day-to-dusk transformations."},"EnhancementConfig":{"type":"object","properties":{"type":{"type":"string","enum":["enhancement"]},"output_resolution":{"$ref":"#/components/schemas/OutputResolution"}},"required":["type"]}},"responses":{"AuthError":{"description":"Authentication error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}},"ValidationError":{"description":"Validation error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"errors":{"type":"array","items":{"type":"string"}}},"required":["message"]}}}},"UnexpectedError":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}}}},"paths":{"/renders/{render_id}/variations/{variation_id}":{"get":{"summary":"Get variation details","description":"Returns details about a variation including the status and result URL","parameters":[{"in":"path","name":"render_id","required":true,"schema":{"type":"string"},"description":"The ID of the base render"},{"in":"path","name":"variation_id","required":true,"schema":{"type":"string"},"description":"The ID of the variation to get details for"}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Variation"}}}},"401":{"$ref":"#/components/responses/AuthError"},"404":{"$ref":"#/components/responses/ValidationError"},"500":{"$ref":"#/components/responses/UnexpectedError"}}}}}}
```

## Create new variations

> Create one or more variations for an existing render. Status updates will be sent to the webhook\_url specified in the render if one was provided.

```json
{"openapi":"3.1.0","info":{"title":"Virtual Staging AI API","version":"2.0.0"},"servers":[{"url":"https://api.virtualstagingai.app/v2","description":"Production base URL."},{"url":"https://us-central1-furniture-ai.cloudfunctions.net/apiV2","description":"Long-running operations endpoint."}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"Authorization","description":"API key authentication. Use the format: Api-Key ${key}."}},"schemas":{"VariationStagingConfig":{"type":"object","properties":{"type":{"type":"string","enum":["staging"]},"output_resolution":{"$ref":"#/components/schemas/OutputResolution"},"add_virtually_staged_watermark":{"type":["boolean","null"],"description":"Whether to add a 'virtually staged' watermark to the output image."},"add_furniture":{"type":"object","properties":{"style":{"$ref":"#/components/schemas/FurnitureStyles"},"room_type":{"$ref":"#/components/schemas/RoomType"},"base_variation_id":{"description":"ID of an existing removal variation that is being used as the base for this staging variation. This should be used to create multiple staging variations from a single removal variation.","type":"string"}},"required":["style","room_type"],"description":"Configuration for adding furniture to the image."},"remove_furniture":{"type":"object","properties":{"mode":{"type":"string","enum":["on","off","auto"],"description":"Furniture removal mode to use."},"mask_url":{"$ref":"#/components/schemas/ImageUrl","description":"URL of the mask image indicating areas to remove furniture from."}},"required":["mode"],"description":"Configuration for removing furniture from the image."}},"required":["type"]},"OutputResolution":{"oneOf":[{"type":"integer","enum":[1536],"description":"Force output to 1536px resolution regardless of input size"},{"type":"string","enum":["default"],"description":"Smart resolution: For Staging renders, upscale to 1536px minimum, or 3072px if input is larger than 1536px. For Enhancements and Day to Dusk renders, return size as-is to a maximum of 3072px."}],"default":"default","description":"Output image resolution. Use 'default' for smart resolution handling or 1536 to force 1536px output. Defaults to 'default' when omitted."},"FurnitureStyles":{"oneOf":[{"type":"string","enum":["standard","modern","scandinavian","industrial","midcentury","luxury","farmhouse","coastal"],"description":"Available furniture styles for staging."},{"type":"string","enum":["american","southwestern","hamptons"],"deprecated":true,"description":"Deprecated styles. These will be mapped to the closest existing style and are available only for backwards compatibility."}]},"RoomType":{"type":"string","enum":["living","bed","kitchen","dining","home_office","outdoor","kids_room"],"description":"Room types accepted for new staging requests (bathroom excluded)."},"ImageUrl":{"type":"string","pattern":"^(https?:\\/\\/[^\\s]+|data:image\\/[a-zA-Z+]+;base64,[A-Za-z0-9+/=]+)$","description":"URL for an image, either HTTP/HTTPS URL or base64 encoded data URL."},"DayToDuskConfig":{"type":"object","properties":{"type":{"type":"string","enum":["daytodusk"]},"output_resolution":{"$ref":"#/components/schemas/OutputResolution"},"sky_style":{"$ref":"#/components/schemas/SkyStyle"}},"required":["sky_style","type"]},"SkyStyle":{"type":"string","enum":["dusk","golden","blue"],"description":"Available sky styles for day-to-dusk transformations."},"EnhancementConfig":{"type":"object","properties":{"type":{"type":"string","enum":["enhancement"]},"output_resolution":{"$ref":"#/components/schemas/OutputResolution"}},"required":["type"]},"DoneWebhookResponse":{"type":"object","properties":{"render_id":{"type":"string","description":"ID of the render that this variation belongs to."},"variation_id":{"type":"string","description":"ID of the variation that completed."},"variation_type":{"type":"string","enum":["staging","removal","enhancement","daytodusk","multi-view-staging"],"description":"Type of variation that completed."},"base_variation_id":{"type":["string","null"],"description":"ID of the removal variation used as base, if this staging variation used a removal variation as its base."},"timestamp":{"type":"number","description":"Event timestamp (epoch milliseconds)."},"event_type":{"type":"string","enum":["done"],"description":"Event type indicating successful completion."},"result":{"oneOf":[{"$ref":"#/components/schemas/ImageResult"},{"type":"array","items":{"$ref":"#/components/schemas/ImageResult"}}],"description":"Generated result images."}},"required":["event_type","result","render_id","variation_id","variation_type","timestamp","base_variation_id"]},"ImageResult":{"type":"object","properties":{"url":{"type":"string","description":"Original image URL."},"optimized_url":{"type":["string","null"],"description":"Optimized (compressed) version URL."},"thumbnail_url":{"type":["string","null"],"description":"Thumbnail version URL."}},"required":["url"]},"ErrorWebhookResponse":{"type":"object","properties":{"render_id":{"type":"string","description":"ID of the render that this variation belongs to."},"variation_id":{"type":"string","description":"ID of the variation that failed."},"variation_type":{"type":"string","enum":["staging","removal","enhancement","daytodusk","multi-view-staging"],"description":"Type of variation that failed."},"timestamp":{"type":"number","description":"Event timestamp (epoch milliseconds)."},"event_type":{"type":"string","enum":["error"],"description":"Event type indicating an error occurred."},"error_message":{"type":"string","description":"Detailed error message explaining the failure."}},"required":["event_type","error_message","render_id","variation_id","variation_type","timestamp"]},"UpdateWebhookResponse":{"type":"object","properties":{"render_id":{"type":"string","description":"ID of the render that this variation belongs to."},"variation_id":{"type":"string","description":"ID of the variation that was updated."},"variation_type":{"type":"string","enum":["staging","removal","enhancement","daytodusk","multi-view-staging"],"description":"Type of variation that was updated."},"timestamp":{"type":"number","description":"Event timestamp (epoch milliseconds)."},"event_type":{"type":"string","enum":["update"],"description":"Event type indicating a status update."},"variation_status":{"type":"string","enum":["queued","rendering","done","error","idle","deleted"],"description":"Current status of the variation."},"eta":{"type":"number","description":"Estimated time remaining for the variation to complete (epoch milliseconds timestamp)."}},"required":["event_type","variation_status","eta","render_id","variation_id","variation_type","timestamp"]},"Variation":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for this variation."},"type":{"type":"string","enum":["staging","removal","enhancement","daytodusk","multi-view-staging"],"description":"Type of variation (staging, removal, etc.)."},"render_id":{"type":"string","description":"ID of the parent render this variation belongs to."},"created_at":{"type":"number","description":"Creation timestamp (epoch milliseconds)."},"status":{"type":"string","enum":["queued","rendering","done","error","idle","deleted"],"description":"Current status of the variation."},"result":{"oneOf":[{"$ref":"#/components/schemas/ImageResult"},{"type":"array","items":{"$ref":"#/components/schemas/ImageResult"}}],"description":"Result images (only present when status is 'done')."},"base_variation_id":{"description":"ID of the removal variation used as base, if this staging variation used a removal variation as its base.","type":"string"},"eta":{"type":["number","null"],"description":"Estimated time remaining for the variation to complete (epoch milliseconds timestamp)."},"config":{"oneOf":[{"$ref":"#/components/schemas/LegacyStagingConfig"},{"$ref":"#/components/schemas/VariationStagingConfigRead"},{"$ref":"#/components/schemas/DayToDuskConfig"},{"$ref":"#/components/schemas/EnhancementConfig"}],"description":"Configuration used to generate this variation."}},"required":["id","render_id","created_at","status","eta"]},"LegacyStagingConfig":{"type":"object","properties":{"type":{"type":"string","enum":["legacy_staging"]},"room_type":{"$ref":"#/components/schemas/AnyRoomType"},"style":{"$ref":"#/components/schemas/FurnitureStyles"}},"required":["room_type","style","type"]},"AnyRoomType":{"oneOf":[{"$ref":"#/components/schemas/RoomType"},{"type":"string","enum":["bathroom"],"deprecated":true,"description":"Deprecated. Not accepted for new staging requests; may appear in historical variation data."}],"description":"Room type (active or deprecated). Use for reading variation/config output only."},"VariationStagingConfigRead":{"type":"object","properties":{"type":{"type":"string","enum":["staging"]},"output_resolution":{"$ref":"#/components/schemas/OutputResolution"},"add_virtually_staged_watermark":{"type":["boolean","null"],"description":"Whether to add a 'virtually staged' watermark to the output image."},"add_furniture":{"type":"object","properties":{"style":{"$ref":"#/components/schemas/FurnitureStyles"},"room_type":{"$ref":"#/components/schemas/AnyRoomType"},"base_variation_id":{"description":"ID of an existing removal variation that is being used as the base for this staging variation. This should be used to create multiple staging variations from a single removal variation.","type":"string"}},"required":["style","room_type"],"description":"Configuration for adding furniture to the image."},"remove_furniture":{"type":"object","properties":{"mode":{"type":"string","enum":["on","off","auto"],"description":"Furniture removal mode to use."},"mask_url":{"$ref":"#/components/schemas/ImageUrl","description":"URL of the mask image indicating areas to remove furniture from."}},"required":["mode"],"description":"Configuration for removing furniture from the image."}},"required":["type"]}},"responses":{"ValidationError":{"description":"Validation error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"errors":{"type":"array","items":{"type":"string"}}},"required":["message"]}}}},"AuthError":{"description":"Authentication error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}},"ForbiddenError":{"description":"Forbidden error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}},"UnexpectedError":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}}}},"paths":{"/renders/{render_id}/variations":{"post":{"summary":"Create new variations","description":"Create one or more variations for an existing render. Status updates will be sent to the webhook_url specified in the render if one was provided.","parameters":[{"in":"path","name":"render_id","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["config","variation_count"],"additionalProperties":false,"properties":{"config":{"oneOf":[{"$ref":"#/components/schemas/VariationStagingConfig"},{"$ref":"#/components/schemas/DayToDuskConfig"},{"$ref":"#/components/schemas/EnhancementConfig"}]},"variation_count":{"type":"integer","minimum":1},"wait_for_completion":{"type":["boolean","null"],"default":false}}}}}},"callbacks":{"variationWebhook":{"{$parent_render.webhook_url}":{"post":{"requestBody":{"description":"Webhook response sent upon the completion of each variation. The response is sent to the webhook_url specified in the parent render.","required":true,"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/DoneWebhookResponse"},{"$ref":"#/components/schemas/ErrorWebhookResponse"},{"$ref":"#/components/schemas/UpdateWebhookResponse"}]}}}},"responses":{"200":{"description":"Webhook received successfully"}}}}}},"responses":{"200":{"description":"Variations created and completed successfully","content":{"application/json":{"schema":{"type":"object","properties":{"variations":{"type":"array","items":{"$ref":"#/components/schemas/Variation"}}}}}}},"201":{"description":"Variations created and processing started","content":{"application/json":{"schema":{"type":"object","properties":{"variations":{"type":"array","items":{"$ref":"#/components/schemas/Variation"}}}}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/AuthError"},"403":{"$ref":"#/components/responses/ForbiddenError"},"404":{"$ref":"#/components/responses/ValidationError"},"500":{"$ref":"#/components/responses/UnexpectedError"}}}}}}
```

## Create multiple renders in bulk

> Creates multiple renders with the specified parameters.

```json
{"openapi":"3.1.0","info":{"title":"Virtual Staging AI API","version":"2.0.0"},"servers":[{"url":"https://api.virtualstagingai.app/v2","description":"Production base URL."},{"url":"https://us-central1-furniture-ai.cloudfunctions.net/apiV2","description":"Long-running operations endpoint."}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"Authorization","description":"API key authentication. Use the format: Api-Key ${key}."}},"schemas":{"RenderStagingConfig":{"type":"object","properties":{"type":{"type":"string","enum":["staging"]},"output_resolution":{"$ref":"#/components/schemas/OutputResolution"},"add_virtually_staged_watermark":{"type":["boolean","null"],"description":"Whether to add a 'virtually staged' watermark to the output image."},"add_furniture":{"type":"object","properties":{"style":{"$ref":"#/components/schemas/FurnitureStyles"},"room_type":{"$ref":"#/components/schemas/RoomType"}},"required":["style","room_type"],"description":"Configuration for adding furniture to the image."},"remove_furniture":{"type":"object","properties":{"mode":{"type":"string","enum":["on","off","auto"],"description":"Furniture removal mode to use."},"mask_url":{"$ref":"#/components/schemas/ImageUrl","description":"URL of the mask image indicating areas to remove furniture from."}},"required":["mode"],"description":"Configuration for removing furniture from the image."}},"required":["type"]},"OutputResolution":{"oneOf":[{"type":"integer","enum":[1536],"description":"Force output to 1536px resolution regardless of input size"},{"type":"string","enum":["default"],"description":"Smart resolution: For Staging renders, upscale to 1536px minimum, or 3072px if input is larger than 1536px. For Enhancements and Day to Dusk renders, return size as-is to a maximum of 3072px."}],"default":"default","description":"Output image resolution. Use 'default' for smart resolution handling or 1536 to force 1536px output. Defaults to 'default' when omitted."},"FurnitureStyles":{"oneOf":[{"type":"string","enum":["standard","modern","scandinavian","industrial","midcentury","luxury","farmhouse","coastal"],"description":"Available furniture styles for staging."},{"type":"string","enum":["american","southwestern","hamptons"],"deprecated":true,"description":"Deprecated styles. These will be mapped to the closest existing style and are available only for backwards compatibility."}]},"RoomType":{"type":"string","enum":["living","bed","kitchen","dining","home_office","outdoor","kids_room"],"description":"Room types accepted for new staging requests (bathroom excluded)."},"ImageUrl":{"type":"string","pattern":"^(https?:\\/\\/[^\\s]+|data:image\\/[a-zA-Z+]+;base64,[A-Za-z0-9+/=]+)$","description":"URL for an image, either HTTP/HTTPS URL or base64 encoded data URL."},"DayToDuskConfig":{"type":"object","properties":{"type":{"type":"string","enum":["daytodusk"]},"output_resolution":{"$ref":"#/components/schemas/OutputResolution"},"sky_style":{"$ref":"#/components/schemas/SkyStyle"}},"required":["sky_style","type"]},"SkyStyle":{"type":"string","enum":["dusk","golden","blue"],"description":"Available sky styles for day-to-dusk transformations."},"EnhancementConfig":{"type":"object","properties":{"type":{"type":"string","enum":["enhancement"]},"output_resolution":{"$ref":"#/components/schemas/OutputResolution"}},"required":["type"]},"DoneWebhookResponse":{"type":"object","properties":{"render_id":{"type":"string","description":"ID of the render that this variation belongs to."},"variation_id":{"type":"string","description":"ID of the variation that completed."},"variation_type":{"type":"string","enum":["staging","removal","enhancement","daytodusk","multi-view-staging"],"description":"Type of variation that completed."},"base_variation_id":{"type":["string","null"],"description":"ID of the removal variation used as base, if this staging variation used a removal variation as its base."},"timestamp":{"type":"number","description":"Event timestamp (epoch milliseconds)."},"event_type":{"type":"string","enum":["done"],"description":"Event type indicating successful completion."},"result":{"oneOf":[{"$ref":"#/components/schemas/ImageResult"},{"type":"array","items":{"$ref":"#/components/schemas/ImageResult"}}],"description":"Generated result images."}},"required":["event_type","result","render_id","variation_id","variation_type","timestamp","base_variation_id"]},"ImageResult":{"type":"object","properties":{"url":{"type":"string","description":"Original image URL."},"optimized_url":{"type":["string","null"],"description":"Optimized (compressed) version URL."},"thumbnail_url":{"type":["string","null"],"description":"Thumbnail version URL."}},"required":["url"]},"ErrorWebhookResponse":{"type":"object","properties":{"render_id":{"type":"string","description":"ID of the render that this variation belongs to."},"variation_id":{"type":"string","description":"ID of the variation that failed."},"variation_type":{"type":"string","enum":["staging","removal","enhancement","daytodusk","multi-view-staging"],"description":"Type of variation that failed."},"timestamp":{"type":"number","description":"Event timestamp (epoch milliseconds)."},"event_type":{"type":"string","enum":["error"],"description":"Event type indicating an error occurred."},"error_message":{"type":"string","description":"Detailed error message explaining the failure."}},"required":["event_type","error_message","render_id","variation_id","variation_type","timestamp"]},"UpdateWebhookResponse":{"type":"object","properties":{"render_id":{"type":"string","description":"ID of the render that this variation belongs to."},"variation_id":{"type":"string","description":"ID of the variation that was updated."},"variation_type":{"type":"string","enum":["staging","removal","enhancement","daytodusk","multi-view-staging"],"description":"Type of variation that was updated."},"timestamp":{"type":"number","description":"Event timestamp (epoch milliseconds)."},"event_type":{"type":"string","enum":["update"],"description":"Event type indicating a status update."},"variation_status":{"type":"string","enum":["queued","rendering","done","error","idle","deleted"],"description":"Current status of the variation."},"eta":{"type":"number","description":"Estimated time remaining for the variation to complete (epoch milliseconds timestamp)."}},"required":["event_type","variation_status","eta","render_id","variation_id","variation_type","timestamp"]},"Render":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for this render."},"created_at":{"type":"number","description":"Creation timestamp (epoch milliseconds)."},"queued_at":{"type":["number","null"],"description":"Timestamp when the render was queued for processing (epoch milliseconds)."},"variations":{"type":"object","properties":{"total_count":{"type":"number","description":"Total number of completed variations for this render."},"next_cursor":{"type":["string","null"],"description":"Cursor to use to get the next page of variations."},"items":{"type":"array","description":"List of variations for this render.","items":{"$ref":"#/components/schemas/Variation"}}},"required":["total_count"]},"eta":{"type":["number","null"],"description":"Estimated time remaining for the first variation to complete (epoch milliseconds timestamp)."}},"required":["id","created_at","variations","eta"]},"Variation":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for this variation."},"type":{"type":"string","enum":["staging","removal","enhancement","daytodusk","multi-view-staging"],"description":"Type of variation (staging, removal, etc.)."},"render_id":{"type":"string","description":"ID of the parent render this variation belongs to."},"created_at":{"type":"number","description":"Creation timestamp (epoch milliseconds)."},"status":{"type":"string","enum":["queued","rendering","done","error","idle","deleted"],"description":"Current status of the variation."},"result":{"oneOf":[{"$ref":"#/components/schemas/ImageResult"},{"type":"array","items":{"$ref":"#/components/schemas/ImageResult"}}],"description":"Result images (only present when status is 'done')."},"base_variation_id":{"description":"ID of the removal variation used as base, if this staging variation used a removal variation as its base.","type":"string"},"eta":{"type":["number","null"],"description":"Estimated time remaining for the variation to complete (epoch milliseconds timestamp)."},"config":{"oneOf":[{"$ref":"#/components/schemas/LegacyStagingConfig"},{"$ref":"#/components/schemas/VariationStagingConfigRead"},{"$ref":"#/components/schemas/DayToDuskConfig"},{"$ref":"#/components/schemas/EnhancementConfig"}],"description":"Configuration used to generate this variation."}},"required":["id","render_id","created_at","status","eta"]},"LegacyStagingConfig":{"type":"object","properties":{"type":{"type":"string","enum":["legacy_staging"]},"room_type":{"$ref":"#/components/schemas/AnyRoomType"},"style":{"$ref":"#/components/schemas/FurnitureStyles"}},"required":["room_type","style","type"]},"AnyRoomType":{"oneOf":[{"$ref":"#/components/schemas/RoomType"},{"type":"string","enum":["bathroom"],"deprecated":true,"description":"Deprecated. Not accepted for new staging requests; may appear in historical variation data."}],"description":"Room type (active or deprecated). Use for reading variation/config output only."},"VariationStagingConfigRead":{"type":"object","properties":{"type":{"type":"string","enum":["staging"]},"output_resolution":{"$ref":"#/components/schemas/OutputResolution"},"add_virtually_staged_watermark":{"type":["boolean","null"],"description":"Whether to add a 'virtually staged' watermark to the output image."},"add_furniture":{"type":"object","properties":{"style":{"$ref":"#/components/schemas/FurnitureStyles"},"room_type":{"$ref":"#/components/schemas/AnyRoomType"},"base_variation_id":{"description":"ID of an existing removal variation that is being used as the base for this staging variation. This should be used to create multiple staging variations from a single removal variation.","type":"string"}},"required":["style","room_type"],"description":"Configuration for adding furniture to the image."},"remove_furniture":{"type":"object","properties":{"mode":{"type":"string","enum":["on","off","auto"],"description":"Furniture removal mode to use."},"mask_url":{"$ref":"#/components/schemas/ImageUrl","description":"URL of the mask image indicating areas to remove furniture from."}},"required":["mode"],"description":"Configuration for removing furniture from the image."}},"required":["type"]}},"responses":{"ValidationError":{"description":"Validation error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"errors":{"type":"array","items":{"type":"string"}}},"required":["message"]}}}},"AuthError":{"description":"Authentication error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}},"ForbiddenError":{"description":"Forbidden error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}},"UnexpectedError":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}}}},"paths":{"/renders/bulk":{"post":{"summary":"Create multiple renders in bulk","description":"Creates multiple renders with the specified parameters.","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["renders"],"additionalProperties":false,"properties":{"webhook_url":{"type":["string","null"],"format":"uri"},"wait_for_completion":{"type":["boolean","null"],"default":false},"renders":{"type":"array","minItems":1,"items":{"type":"object","required":["config","image_url","variation_count"],"additionalProperties":false,"properties":{"config":{"oneOf":[{"$ref":"#/components/schemas/RenderStagingConfig"},{"$ref":"#/components/schemas/DayToDuskConfig"},{"$ref":"#/components/schemas/EnhancementConfig"}]},"image_url":{"$ref":"#/components/schemas/ImageUrl"},"variation_count":{"type":"integer","minimum":1}}}}}}}}},"callbacks":{"renderWebhook":{"{$request.body.webhook_url}":{"post":{"description":"Webhook response sent upon the completion of each variation that is part of any render in the bulk request","requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/DoneWebhookResponse"},{"$ref":"#/components/schemas/ErrorWebhookResponse"},{"$ref":"#/components/schemas/UpdateWebhookResponse"}]}}}},"responses":{"200":{"description":"Webhook received successfully"}}}}}},"responses":{"200":{"description":"Renders created and completed successfully","content":{"application/json":{"schema":{"type":"object","properties":{"renders":{"type":"array","items":{"anyOf":[{"$ref":"#/components/schemas/Render"},{"type":"object","properties":{"status":{"type":"string","enum":["error"]},"message":{"type":"string","description":"Error message describing what went wrong"},"original_image_url":{"type":"string","description":"URL of the image that failed processing"}}}]}}}}}}},"201":{"description":"Renders created and queued for processing","content":{"application/json":{"schema":{"type":"object","properties":{"renders":{"type":"array","items":{"anyOf":[{"$ref":"#/components/schemas/Render"},{"type":"object","properties":{"status":{"type":"string","enum":["error"]},"message":{"type":"string","description":"Error message describing what went wrong"},"original_image_url":{"type":"string","description":"URL of the image that failed processing"}}}]}}}}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/AuthError"},"403":{"$ref":"#/components/responses/ForbiddenError"},"404":{"$ref":"#/components/responses/ValidationError"},"500":{"$ref":"#/components/responses/UnexpectedError"}}}}}}
```

## Create multiple variations in bulk

> Creates multiple variations for an existing render with different configurations.

```json
{"openapi":"3.1.0","info":{"title":"Virtual Staging AI API","version":"2.0.0"},"servers":[{"url":"https://api.virtualstagingai.app/v2","description":"Production base URL."},{"url":"https://us-central1-furniture-ai.cloudfunctions.net/apiV2","description":"Long-running operations endpoint."}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"Authorization","description":"API key authentication. Use the format: Api-Key ${key}."}},"schemas":{"VariationStagingConfig":{"type":"object","properties":{"type":{"type":"string","enum":["staging"]},"output_resolution":{"$ref":"#/components/schemas/OutputResolution"},"add_virtually_staged_watermark":{"type":["boolean","null"],"description":"Whether to add a 'virtually staged' watermark to the output image."},"add_furniture":{"type":"object","properties":{"style":{"$ref":"#/components/schemas/FurnitureStyles"},"room_type":{"$ref":"#/components/schemas/RoomType"},"base_variation_id":{"description":"ID of an existing removal variation that is being used as the base for this staging variation. This should be used to create multiple staging variations from a single removal variation.","type":"string"}},"required":["style","room_type"],"description":"Configuration for adding furniture to the image."},"remove_furniture":{"type":"object","properties":{"mode":{"type":"string","enum":["on","off","auto"],"description":"Furniture removal mode to use."},"mask_url":{"$ref":"#/components/schemas/ImageUrl","description":"URL of the mask image indicating areas to remove furniture from."}},"required":["mode"],"description":"Configuration for removing furniture from the image."}},"required":["type"]},"OutputResolution":{"oneOf":[{"type":"integer","enum":[1536],"description":"Force output to 1536px resolution regardless of input size"},{"type":"string","enum":["default"],"description":"Smart resolution: For Staging renders, upscale to 1536px minimum, or 3072px if input is larger than 1536px. For Enhancements and Day to Dusk renders, return size as-is to a maximum of 3072px."}],"default":"default","description":"Output image resolution. Use 'default' for smart resolution handling or 1536 to force 1536px output. Defaults to 'default' when omitted."},"FurnitureStyles":{"oneOf":[{"type":"string","enum":["standard","modern","scandinavian","industrial","midcentury","luxury","farmhouse","coastal"],"description":"Available furniture styles for staging."},{"type":"string","enum":["american","southwestern","hamptons"],"deprecated":true,"description":"Deprecated styles. These will be mapped to the closest existing style and are available only for backwards compatibility."}]},"RoomType":{"type":"string","enum":["living","bed","kitchen","dining","home_office","outdoor","kids_room"],"description":"Room types accepted for new staging requests (bathroom excluded)."},"ImageUrl":{"type":"string","pattern":"^(https?:\\/\\/[^\\s]+|data:image\\/[a-zA-Z+]+;base64,[A-Za-z0-9+/=]+)$","description":"URL for an image, either HTTP/HTTPS URL or base64 encoded data URL."},"DayToDuskConfig":{"type":"object","properties":{"type":{"type":"string","enum":["daytodusk"]},"output_resolution":{"$ref":"#/components/schemas/OutputResolution"},"sky_style":{"$ref":"#/components/schemas/SkyStyle"}},"required":["sky_style","type"]},"SkyStyle":{"type":"string","enum":["dusk","golden","blue"],"description":"Available sky styles for day-to-dusk transformations."},"EnhancementConfig":{"type":"object","properties":{"type":{"type":"string","enum":["enhancement"]},"output_resolution":{"$ref":"#/components/schemas/OutputResolution"}},"required":["type"]},"DoneWebhookResponse":{"type":"object","properties":{"render_id":{"type":"string","description":"ID of the render that this variation belongs to."},"variation_id":{"type":"string","description":"ID of the variation that completed."},"variation_type":{"type":"string","enum":["staging","removal","enhancement","daytodusk","multi-view-staging"],"description":"Type of variation that completed."},"base_variation_id":{"type":["string","null"],"description":"ID of the removal variation used as base, if this staging variation used a removal variation as its base."},"timestamp":{"type":"number","description":"Event timestamp (epoch milliseconds)."},"event_type":{"type":"string","enum":["done"],"description":"Event type indicating successful completion."},"result":{"oneOf":[{"$ref":"#/components/schemas/ImageResult"},{"type":"array","items":{"$ref":"#/components/schemas/ImageResult"}}],"description":"Generated result images."}},"required":["event_type","result","render_id","variation_id","variation_type","timestamp","base_variation_id"]},"ImageResult":{"type":"object","properties":{"url":{"type":"string","description":"Original image URL."},"optimized_url":{"type":["string","null"],"description":"Optimized (compressed) version URL."},"thumbnail_url":{"type":["string","null"],"description":"Thumbnail version URL."}},"required":["url"]},"ErrorWebhookResponse":{"type":"object","properties":{"render_id":{"type":"string","description":"ID of the render that this variation belongs to."},"variation_id":{"type":"string","description":"ID of the variation that failed."},"variation_type":{"type":"string","enum":["staging","removal","enhancement","daytodusk","multi-view-staging"],"description":"Type of variation that failed."},"timestamp":{"type":"number","description":"Event timestamp (epoch milliseconds)."},"event_type":{"type":"string","enum":["error"],"description":"Event type indicating an error occurred."},"error_message":{"type":"string","description":"Detailed error message explaining the failure."}},"required":["event_type","error_message","render_id","variation_id","variation_type","timestamp"]},"UpdateWebhookResponse":{"type":"object","properties":{"render_id":{"type":"string","description":"ID of the render that this variation belongs to."},"variation_id":{"type":"string","description":"ID of the variation that was updated."},"variation_type":{"type":"string","enum":["staging","removal","enhancement","daytodusk","multi-view-staging"],"description":"Type of variation that was updated."},"timestamp":{"type":"number","description":"Event timestamp (epoch milliseconds)."},"event_type":{"type":"string","enum":["update"],"description":"Event type indicating a status update."},"variation_status":{"type":"string","enum":["queued","rendering","done","error","idle","deleted"],"description":"Current status of the variation."},"eta":{"type":"number","description":"Estimated time remaining for the variation to complete (epoch milliseconds timestamp)."}},"required":["event_type","variation_status","eta","render_id","variation_id","variation_type","timestamp"]},"Variation":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for this variation."},"type":{"type":"string","enum":["staging","removal","enhancement","daytodusk","multi-view-staging"],"description":"Type of variation (staging, removal, etc.)."},"render_id":{"type":"string","description":"ID of the parent render this variation belongs to."},"created_at":{"type":"number","description":"Creation timestamp (epoch milliseconds)."},"status":{"type":"string","enum":["queued","rendering","done","error","idle","deleted"],"description":"Current status of the variation."},"result":{"oneOf":[{"$ref":"#/components/schemas/ImageResult"},{"type":"array","items":{"$ref":"#/components/schemas/ImageResult"}}],"description":"Result images (only present when status is 'done')."},"base_variation_id":{"description":"ID of the removal variation used as base, if this staging variation used a removal variation as its base.","type":"string"},"eta":{"type":["number","null"],"description":"Estimated time remaining for the variation to complete (epoch milliseconds timestamp)."},"config":{"oneOf":[{"$ref":"#/components/schemas/LegacyStagingConfig"},{"$ref":"#/components/schemas/VariationStagingConfigRead"},{"$ref":"#/components/schemas/DayToDuskConfig"},{"$ref":"#/components/schemas/EnhancementConfig"}],"description":"Configuration used to generate this variation."}},"required":["id","render_id","created_at","status","eta"]},"LegacyStagingConfig":{"type":"object","properties":{"type":{"type":"string","enum":["legacy_staging"]},"room_type":{"$ref":"#/components/schemas/AnyRoomType"},"style":{"$ref":"#/components/schemas/FurnitureStyles"}},"required":["room_type","style","type"]},"AnyRoomType":{"oneOf":[{"$ref":"#/components/schemas/RoomType"},{"type":"string","enum":["bathroom"],"deprecated":true,"description":"Deprecated. Not accepted for new staging requests; may appear in historical variation data."}],"description":"Room type (active or deprecated). Use for reading variation/config output only."},"VariationStagingConfigRead":{"type":"object","properties":{"type":{"type":"string","enum":["staging"]},"output_resolution":{"$ref":"#/components/schemas/OutputResolution"},"add_virtually_staged_watermark":{"type":["boolean","null"],"description":"Whether to add a 'virtually staged' watermark to the output image."},"add_furniture":{"type":"object","properties":{"style":{"$ref":"#/components/schemas/FurnitureStyles"},"room_type":{"$ref":"#/components/schemas/AnyRoomType"},"base_variation_id":{"description":"ID of an existing removal variation that is being used as the base for this staging variation. This should be used to create multiple staging variations from a single removal variation.","type":"string"}},"required":["style","room_type"],"description":"Configuration for adding furniture to the image."},"remove_furniture":{"type":"object","properties":{"mode":{"type":"string","enum":["on","off","auto"],"description":"Furniture removal mode to use."},"mask_url":{"$ref":"#/components/schemas/ImageUrl","description":"URL of the mask image indicating areas to remove furniture from."}},"required":["mode"],"description":"Configuration for removing furniture from the image."}},"required":["type"]}},"responses":{"ValidationError":{"description":"Validation error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"errors":{"type":"array","items":{"type":"string"}}},"required":["message"]}}}},"AuthError":{"description":"Authentication error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}},"ForbiddenError":{"description":"Forbidden error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}},"UnexpectedError":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}}}},"paths":{"/renders/variations/bulk":{"post":{"summary":"Create multiple variations in bulk","description":"Creates multiple variations for an existing render with different configurations.","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["renders"],"additionalProperties":false,"properties":{"wait_for_completion":{"type":["boolean","null"],"default":false},"renders":{"type":"array","minItems":1,"items":{"type":"object","required":["render_id","variation_count","config"],"additionalProperties":false,"properties":{"render_id":{"type":"string"},"variation_count":{"type":"integer","minimum":1},"config":{"oneOf":[{"$ref":"#/components/schemas/VariationStagingConfig"},{"$ref":"#/components/schemas/DayToDuskConfig"},{"$ref":"#/components/schemas/EnhancementConfig"}]}}}}}}}}},"callbacks":{"variationWebhook":{"{$parent_render.webhook_url}":{"post":{"description":"Webhook response sent upon the completion of each variation. The response is sent to the webhook_url specified in each parent render.","requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/DoneWebhookResponse"},{"$ref":"#/components/schemas/ErrorWebhookResponse"},{"$ref":"#/components/schemas/UpdateWebhookResponse"}]}}}},"responses":{"200":{"description":"Webhook received successfully"}}}}}},"responses":{"200":{"description":"Variations for renders created and completed successfully","content":{"application/json":{"schema":{"type":"object","properties":{"results":{"type":"array","items":{"oneOf":[{"$ref":"#/components/schemas/Variation"},{"type":"object","properties":{"status":{"type":"string","enum":["error"]},"message":{"type":"string","description":"Error message describing what went wrong"},"render_id":{"type":"string","description":"ID of the render that failed processing"}}}]}}}}}}},"201":{"description":"Variations for renders created and processing started","content":{"application/json":{"schema":{"type":"object","properties":{"results":{"type":"array","items":{"oneOf":[{"$ref":"#/components/schemas/Variation"},{"type":"object","properties":{"status":{"type":"string","enum":["error"]},"message":{"type":"string","description":"Error message describing what went wrong"},"render_id":{"type":"string","description":"ID of the render that failed processing"}}}]}}}}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/AuthError"},"403":{"$ref":"#/components/responses/ForbiddenError"},"404":{"$ref":"#/components/responses/ValidationError"},"500":{"$ref":"#/components/responses/UnexpectedError"}}}}}}
```

## Submit an image for a furniture mask generation

> Submits an image for analysis to generate a furniture mask. If a webhook\_url is provided, completion status will be sent to that URL.

```json
{"openapi":"3.1.0","info":{"title":"Virtual Staging AI API","version":"2.0.0"},"servers":[{"url":"https://api.virtualstagingai.app/v2","description":"Production base URL."},{"url":"https://us-central1-furniture-ai.cloudfunctions.net/apiV2","description":"Long-running operations endpoint."}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"Authorization","description":"API key authentication. Use the format: Api-Key ${key}."}},"schemas":{"ImageUrl":{"type":"string","pattern":"^(https?:\\/\\/[^\\s]+|data:image\\/[a-zA-Z+]+;base64,[A-Za-z0-9+/=]+)$","description":"URL for an image, either HTTP/HTTPS URL or base64 encoded data URL."},"AnalysisDoneWebhookResponse":{"type":"object","properties":{"id":{"type":"string","description":"Analysis ID."},"timestamp":{"type":"number","description":"Event timestamp (epoch milliseconds)."},"event_type":{"type":"string","enum":["analysis_completion"],"description":"Event type indicating successful analysis completion."},"percentage_masked":{"type":"number","description":"Percentage of the image that was identified as furniture."},"result_url":{"type":"string","description":"URL of the analysis result image."}},"required":["event_type","result_url","id","percentage_masked","timestamp"]},"AnalysisErrorWebhookResponse":{"type":"object","properties":{"id":{"type":"string","description":"Analysis ID."},"timestamp":{"type":"number","description":"Event timestamp (epoch milliseconds)."},"event_type":{"type":"string","enum":["analysis_error"],"description":"Event type indicating analysis failure."},"error_message":{"type":"string","description":"Detailed error message explaining the failure."}},"required":["id","timestamp","event_type","error_message"]},"Analysis":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for this analysis."},"created_at":{"type":"number","description":"Creation timestamp (epoch milliseconds)."},"result_url":{"type":"string","description":"URL of the analysis result image."},"percentage_masked":{"type":"number","description":"Percentage of the image that was identified as furniture."},"status":{"type":"string","enum":["done","error"],"description":"Status of the analysis."}},"required":["id","created_at","result_url","status"]}},"responses":{"ValidationError":{"description":"Validation error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"errors":{"type":"array","items":{"type":"string"}}},"required":["message"]}}}},"AuthError":{"description":"Authentication error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}},"UnexpectedError":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}}}},"paths":{"/analyze":{"post":{"summary":"Submit an image for a furniture mask generation","description":"Submits an image for analysis to generate a furniture mask. If a webhook_url is provided, completion status will be sent to that URL.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["image_url"],"additionalProperties":false,"properties":{"image_url":{"$ref":"#/components/schemas/ImageUrl"},"webhook_url":{"type":["string","null"],"format":"uri","description":"URL for completion payload"}}}}}},"callbacks":{"analysisWebhook":{"{$request.body.webhook_url}":{"post":{"requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/AnalysisDoneWebhookResponse"},{"$ref":"#/components/schemas/AnalysisErrorWebhookResponse"}]}}}},"responses":{"200":{"description":"Webhook received successfully"}}}}}},"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Analysis"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/AuthError"},"404":{"$ref":"#/components/responses/ValidationError"},"500":{"$ref":"#/components/responses/UnexpectedError"}}}}}}
```

## Create or update webhook secret

> Sets or updates the webhook secret used for HMAC signature verification

```json
{"openapi":"3.1.0","info":{"title":"Virtual Staging AI API","version":"2.0.0"},"servers":[{"url":"https://api.virtualstagingai.app/v2","description":"Production base URL."},{"url":"https://us-central1-furniture-ai.cloudfunctions.net/apiV2","description":"Long-running operations endpoint."}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"Authorization","description":"API key authentication. Use the format: Api-Key ${key}."}},"responses":{"ValidationError":{"description":"Validation error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"errors":{"type":"array","items":{"type":"string"}}},"required":["message"]}}}},"AuthError":{"description":"Authentication error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}},"UnexpectedError":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}}}},"paths":{"/user/webhook-secret":{"post":{"summary":"Create or update webhook secret","description":"Sets or updates the webhook secret used for HMAC signature verification","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["webhook_secret"],"additionalProperties":false,"properties":{"webhook_secret":{"type":"string","minLength":1,"pattern":"^[a-zA-Z0-9_-]+$","description":"The webhook secret to use for HMAC signature verification"}}}}}},"responses":{"200":{"description":"Webhook secret updated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/AuthError"},"500":{"$ref":"#/components/responses/UnexpectedError"}}}}}}
```

## Remove webhook secret

> Removes the webhook secret used for HMAC signature verification

```json
{"openapi":"3.1.0","info":{"title":"Virtual Staging AI API","version":"2.0.0"},"servers":[{"url":"https://api.virtualstagingai.app/v2","description":"Production base URL."},{"url":"https://us-central1-furniture-ai.cloudfunctions.net/apiV2","description":"Long-running operations endpoint."}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"Authorization","description":"API key authentication. Use the format: Api-Key ${key}."}},"responses":{"AuthError":{"description":"Authentication error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}},"UnexpectedError":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}}}},"paths":{"/user/webhook-secret":{"delete":{"summary":"Remove webhook secret","description":"Removes the webhook secret used for HMAC signature verification","responses":{"200":{"description":"Webhook secret removed successfully","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/AuthError"},"500":{"$ref":"#/components/responses/UnexpectedError"}}}}}}
```

### Schemas

## The ImageUrl object

```json
{"openapi":"3.1.0","info":{"title":"Virtual Staging AI API","version":"2.0.0"},"components":{"schemas":{"ImageUrl":{"type":"string","pattern":"^(https?:\\/\\/[^\\s]+|data:image\\/[a-zA-Z+]+;base64,[A-Za-z0-9+/=]+)$","description":"URL for an image, either HTTP/HTTPS URL or base64 encoded data URL."}}}}
```

## The FurnitureStyles object

```json
{"openapi":"3.1.0","info":{"title":"Virtual Staging AI API","version":"2.0.0"},"components":{"schemas":{"FurnitureStyles":{"oneOf":[{"type":"string","enum":["standard","modern","scandinavian","industrial","midcentury","luxury","farmhouse","coastal"],"description":"Available furniture styles for staging."},{"type":"string","enum":["american","southwestern","hamptons"],"deprecated":true,"description":"Deprecated styles. These will be mapped to the closest existing style and are available only for backwards compatibility."}]}}}}
```

## The RoomType object

```json
{"openapi":"3.1.0","info":{"title":"Virtual Staging AI API","version":"2.0.0"},"components":{"schemas":{"RoomType":{"type":"string","enum":["living","bed","kitchen","dining","home_office","outdoor","kids_room"],"description":"Room types accepted for new staging requests (bathroom excluded)."}}}}
```

## The SkyStyle object

```json
{"openapi":"3.1.0","info":{"title":"Virtual Staging AI API","version":"2.0.0"},"components":{"schemas":{"SkyStyle":{"type":"string","enum":["dusk","golden","blue"],"description":"Available sky styles for day-to-dusk transformations."}}}}
```

## The DayToDuskConfig object

```json
{"openapi":"3.1.0","info":{"title":"Virtual Staging AI API","version":"2.0.0"},"components":{"schemas":{"DayToDuskConfig":{"type":"object","properties":{"type":{"type":"string","enum":["daytodusk"]},"output_resolution":{"$ref":"#/components/schemas/OutputResolution"},"sky_style":{"$ref":"#/components/schemas/SkyStyle"}},"required":["sky_style","type"]},"OutputResolution":{"oneOf":[{"type":"integer","enum":[1536],"description":"Force output to 1536px resolution regardless of input size"},{"type":"string","enum":["default"],"description":"Smart resolution: For Staging renders, upscale to 1536px minimum, or 3072px if input is larger than 1536px. For Enhancements and Day to Dusk renders, return size as-is to a maximum of 3072px."}],"default":"default","description":"Output image resolution. Use 'default' for smart resolution handling or 1536 to force 1536px output. Defaults to 'default' when omitted."},"SkyStyle":{"type":"string","enum":["dusk","golden","blue"],"description":"Available sky styles for day-to-dusk transformations."}}}}
```

## The EnhancementConfig object

```json
{"openapi":"3.1.0","info":{"title":"Virtual Staging AI API","version":"2.0.0"},"components":{"schemas":{"EnhancementConfig":{"type":"object","properties":{"type":{"type":"string","enum":["enhancement"]},"output_resolution":{"$ref":"#/components/schemas/OutputResolution"}},"required":["type"]},"OutputResolution":{"oneOf":[{"type":"integer","enum":[1536],"description":"Force output to 1536px resolution regardless of input size"},{"type":"string","enum":["default"],"description":"Smart resolution: For Staging renders, upscale to 1536px minimum, or 3072px if input is larger than 1536px. For Enhancements and Day to Dusk renders, return size as-is to a maximum of 3072px."}],"default":"default","description":"Output image resolution. Use 'default' for smart resolution handling or 1536 to force 1536px output. Defaults to 'default' when omitted."}}}}
```

## The LegacyStagingConfig object

```json
{"openapi":"3.1.0","info":{"title":"Virtual Staging AI API","version":"2.0.0"},"components":{"schemas":{"LegacyStagingConfig":{"type":"object","properties":{"type":{"type":"string","enum":["legacy_staging"]},"room_type":{"$ref":"#/components/schemas/AnyRoomType"},"style":{"$ref":"#/components/schemas/FurnitureStyles"}},"required":["room_type","style","type"]},"AnyRoomType":{"oneOf":[{"$ref":"#/components/schemas/RoomType"},{"type":"string","enum":["bathroom"],"deprecated":true,"description":"Deprecated. Not accepted for new staging requests; may appear in historical variation data."}],"description":"Room type (active or deprecated). Use for reading variation/config output only."},"RoomType":{"type":"string","enum":["living","bed","kitchen","dining","home_office","outdoor","kids_room"],"description":"Room types accepted for new staging requests (bathroom excluded)."},"FurnitureStyles":{"oneOf":[{"type":"string","enum":["standard","modern","scandinavian","industrial","midcentury","luxury","farmhouse","coastal"],"description":"Available furniture styles for staging."},{"type":"string","enum":["american","southwestern","hamptons"],"deprecated":true,"description":"Deprecated styles. These will be mapped to the closest existing style and are available only for backwards compatibility."}]}}}}
```

## The ImageResult object

```json
{"openapi":"3.1.0","info":{"title":"Virtual Staging AI API","version":"2.0.0"},"components":{"schemas":{"ImageResult":{"type":"object","properties":{"url":{"type":"string","description":"Original image URL."},"optimized_url":{"type":["string","null"],"description":"Optimized (compressed) version URL."},"thumbnail_url":{"type":["string","null"],"description":"Thumbnail version URL."}},"required":["url"]}}}}
```

## The Variation object

```json
{"openapi":"3.1.0","info":{"title":"Virtual Staging AI API","version":"2.0.0"},"components":{"schemas":{"Variation":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for this variation."},"type":{"type":"string","enum":["staging","removal","enhancement","daytodusk","multi-view-staging"],"description":"Type of variation (staging, removal, etc.)."},"render_id":{"type":"string","description":"ID of the parent render this variation belongs to."},"created_at":{"type":"number","description":"Creation timestamp (epoch milliseconds)."},"status":{"type":"string","enum":["queued","rendering","done","error","idle","deleted"],"description":"Current status of the variation."},"result":{"oneOf":[{"$ref":"#/components/schemas/ImageResult"},{"type":"array","items":{"$ref":"#/components/schemas/ImageResult"}}],"description":"Result images (only present when status is 'done')."},"base_variation_id":{"description":"ID of the removal variation used as base, if this staging variation used a removal variation as its base.","type":"string"},"eta":{"type":["number","null"],"description":"Estimated time remaining for the variation to complete (epoch milliseconds timestamp)."},"config":{"oneOf":[{"$ref":"#/components/schemas/LegacyStagingConfig"},{"$ref":"#/components/schemas/VariationStagingConfigRead"},{"$ref":"#/components/schemas/DayToDuskConfig"},{"$ref":"#/components/schemas/EnhancementConfig"}],"description":"Configuration used to generate this variation."}},"required":["id","render_id","created_at","status","eta"]},"ImageResult":{"type":"object","properties":{"url":{"type":"string","description":"Original image URL."},"optimized_url":{"type":["string","null"],"description":"Optimized (compressed) version URL."},"thumbnail_url":{"type":["string","null"],"description":"Thumbnail version URL."}},"required":["url"]},"LegacyStagingConfig":{"type":"object","properties":{"type":{"type":"string","enum":["legacy_staging"]},"room_type":{"$ref":"#/components/schemas/AnyRoomType"},"style":{"$ref":"#/components/schemas/FurnitureStyles"}},"required":["room_type","style","type"]},"AnyRoomType":{"oneOf":[{"$ref":"#/components/schemas/RoomType"},{"type":"string","enum":["bathroom"],"deprecated":true,"description":"Deprecated. Not accepted for new staging requests; may appear in historical variation data."}],"description":"Room type (active or deprecated). Use for reading variation/config output only."},"RoomType":{"type":"string","enum":["living","bed","kitchen","dining","home_office","outdoor","kids_room"],"description":"Room types accepted for new staging requests (bathroom excluded)."},"FurnitureStyles":{"oneOf":[{"type":"string","enum":["standard","modern","scandinavian","industrial","midcentury","luxury","farmhouse","coastal"],"description":"Available furniture styles for staging."},{"type":"string","enum":["american","southwestern","hamptons"],"deprecated":true,"description":"Deprecated styles. These will be mapped to the closest existing style and are available only for backwards compatibility."}]},"VariationStagingConfigRead":{"type":"object","properties":{"type":{"type":"string","enum":["staging"]},"output_resolution":{"$ref":"#/components/schemas/OutputResolution"},"add_virtually_staged_watermark":{"type":["boolean","null"],"description":"Whether to add a 'virtually staged' watermark to the output image."},"add_furniture":{"type":"object","properties":{"style":{"$ref":"#/components/schemas/FurnitureStyles"},"room_type":{"$ref":"#/components/schemas/AnyRoomType"},"base_variation_id":{"description":"ID of an existing removal variation that is being used as the base for this staging variation. This should be used to create multiple staging variations from a single removal variation.","type":"string"}},"required":["style","room_type"],"description":"Configuration for adding furniture to the image."},"remove_furniture":{"type":"object","properties":{"mode":{"type":"string","enum":["on","off","auto"],"description":"Furniture removal mode to use."},"mask_url":{"$ref":"#/components/schemas/ImageUrl","description":"URL of the mask image indicating areas to remove furniture from."}},"required":["mode"],"description":"Configuration for removing furniture from the image."}},"required":["type"]},"OutputResolution":{"oneOf":[{"type":"integer","enum":[1536],"description":"Force output to 1536px resolution regardless of input size"},{"type":"string","enum":["default"],"description":"Smart resolution: For Staging renders, upscale to 1536px minimum, or 3072px if input is larger than 1536px. For Enhancements and Day to Dusk renders, return size as-is to a maximum of 3072px."}],"default":"default","description":"Output image resolution. Use 'default' for smart resolution handling or 1536 to force 1536px output. Defaults to 'default' when omitted."},"ImageUrl":{"type":"string","pattern":"^(https?:\\/\\/[^\\s]+|data:image\\/[a-zA-Z+]+;base64,[A-Za-z0-9+/=]+)$","description":"URL for an image, either HTTP/HTTPS URL or base64 encoded data URL."},"DayToDuskConfig":{"type":"object","properties":{"type":{"type":"string","enum":["daytodusk"]},"output_resolution":{"$ref":"#/components/schemas/OutputResolution"},"sky_style":{"$ref":"#/components/schemas/SkyStyle"}},"required":["sky_style","type"]},"SkyStyle":{"type":"string","enum":["dusk","golden","blue"],"description":"Available sky styles for day-to-dusk transformations."},"EnhancementConfig":{"type":"object","properties":{"type":{"type":"string","enum":["enhancement"]},"output_resolution":{"$ref":"#/components/schemas/OutputResolution"}},"required":["type"]}}}}
```

## The Render object

```json
{"openapi":"3.1.0","info":{"title":"Virtual Staging AI API","version":"2.0.0"},"components":{"schemas":{"Render":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for this render."},"created_at":{"type":"number","description":"Creation timestamp (epoch milliseconds)."},"queued_at":{"type":["number","null"],"description":"Timestamp when the render was queued for processing (epoch milliseconds)."},"variations":{"type":"object","properties":{"total_count":{"type":"number","description":"Total number of completed variations for this render."},"next_cursor":{"type":["string","null"],"description":"Cursor to use to get the next page of variations."},"items":{"type":"array","description":"List of variations for this render.","items":{"$ref":"#/components/schemas/Variation"}}},"required":["total_count"]},"eta":{"type":["number","null"],"description":"Estimated time remaining for the first variation to complete (epoch milliseconds timestamp)."}},"required":["id","created_at","variations","eta"]},"Variation":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for this variation."},"type":{"type":"string","enum":["staging","removal","enhancement","daytodusk","multi-view-staging"],"description":"Type of variation (staging, removal, etc.)."},"render_id":{"type":"string","description":"ID of the parent render this variation belongs to."},"created_at":{"type":"number","description":"Creation timestamp (epoch milliseconds)."},"status":{"type":"string","enum":["queued","rendering","done","error","idle","deleted"],"description":"Current status of the variation."},"result":{"oneOf":[{"$ref":"#/components/schemas/ImageResult"},{"type":"array","items":{"$ref":"#/components/schemas/ImageResult"}}],"description":"Result images (only present when status is 'done')."},"base_variation_id":{"description":"ID of the removal variation used as base, if this staging variation used a removal variation as its base.","type":"string"},"eta":{"type":["number","null"],"description":"Estimated time remaining for the variation to complete (epoch milliseconds timestamp)."},"config":{"oneOf":[{"$ref":"#/components/schemas/LegacyStagingConfig"},{"$ref":"#/components/schemas/VariationStagingConfigRead"},{"$ref":"#/components/schemas/DayToDuskConfig"},{"$ref":"#/components/schemas/EnhancementConfig"}],"description":"Configuration used to generate this variation."}},"required":["id","render_id","created_at","status","eta"]},"ImageResult":{"type":"object","properties":{"url":{"type":"string","description":"Original image URL."},"optimized_url":{"type":["string","null"],"description":"Optimized (compressed) version URL."},"thumbnail_url":{"type":["string","null"],"description":"Thumbnail version URL."}},"required":["url"]},"LegacyStagingConfig":{"type":"object","properties":{"type":{"type":"string","enum":["legacy_staging"]},"room_type":{"$ref":"#/components/schemas/AnyRoomType"},"style":{"$ref":"#/components/schemas/FurnitureStyles"}},"required":["room_type","style","type"]},"AnyRoomType":{"oneOf":[{"$ref":"#/components/schemas/RoomType"},{"type":"string","enum":["bathroom"],"deprecated":true,"description":"Deprecated. Not accepted for new staging requests; may appear in historical variation data."}],"description":"Room type (active or deprecated). Use for reading variation/config output only."},"RoomType":{"type":"string","enum":["living","bed","kitchen","dining","home_office","outdoor","kids_room"],"description":"Room types accepted for new staging requests (bathroom excluded)."},"FurnitureStyles":{"oneOf":[{"type":"string","enum":["standard","modern","scandinavian","industrial","midcentury","luxury","farmhouse","coastal"],"description":"Available furniture styles for staging."},{"type":"string","enum":["american","southwestern","hamptons"],"deprecated":true,"description":"Deprecated styles. These will be mapped to the closest existing style and are available only for backwards compatibility."}]},"VariationStagingConfigRead":{"type":"object","properties":{"type":{"type":"string","enum":["staging"]},"output_resolution":{"$ref":"#/components/schemas/OutputResolution"},"add_virtually_staged_watermark":{"type":["boolean","null"],"description":"Whether to add a 'virtually staged' watermark to the output image."},"add_furniture":{"type":"object","properties":{"style":{"$ref":"#/components/schemas/FurnitureStyles"},"room_type":{"$ref":"#/components/schemas/AnyRoomType"},"base_variation_id":{"description":"ID of an existing removal variation that is being used as the base for this staging variation. This should be used to create multiple staging variations from a single removal variation.","type":"string"}},"required":["style","room_type"],"description":"Configuration for adding furniture to the image."},"remove_furniture":{"type":"object","properties":{"mode":{"type":"string","enum":["on","off","auto"],"description":"Furniture removal mode to use."},"mask_url":{"$ref":"#/components/schemas/ImageUrl","description":"URL of the mask image indicating areas to remove furniture from."}},"required":["mode"],"description":"Configuration for removing furniture from the image."}},"required":["type"]},"OutputResolution":{"oneOf":[{"type":"integer","enum":[1536],"description":"Force output to 1536px resolution regardless of input size"},{"type":"string","enum":["default"],"description":"Smart resolution: For Staging renders, upscale to 1536px minimum, or 3072px if input is larger than 1536px. For Enhancements and Day to Dusk renders, return size as-is to a maximum of 3072px."}],"default":"default","description":"Output image resolution. Use 'default' for smart resolution handling or 1536 to force 1536px output. Defaults to 'default' when omitted."},"ImageUrl":{"type":"string","pattern":"^(https?:\\/\\/[^\\s]+|data:image\\/[a-zA-Z+]+;base64,[A-Za-z0-9+/=]+)$","description":"URL for an image, either HTTP/HTTPS URL or base64 encoded data URL."},"DayToDuskConfig":{"type":"object","properties":{"type":{"type":"string","enum":["daytodusk"]},"output_resolution":{"$ref":"#/components/schemas/OutputResolution"},"sky_style":{"$ref":"#/components/schemas/SkyStyle"}},"required":["sky_style","type"]},"SkyStyle":{"type":"string","enum":["dusk","golden","blue"],"description":"Available sky styles for day-to-dusk transformations."},"EnhancementConfig":{"type":"object","properties":{"type":{"type":"string","enum":["enhancement"]},"output_resolution":{"$ref":"#/components/schemas/OutputResolution"}},"required":["type"]}}}}
```

## The Analysis object

```json
{"openapi":"3.1.0","info":{"title":"Virtual Staging AI API","version":"2.0.0"},"components":{"schemas":{"Analysis":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for this analysis."},"created_at":{"type":"number","description":"Creation timestamp (epoch milliseconds)."},"result_url":{"type":"string","description":"URL of the analysis result image."},"percentage_masked":{"type":"number","description":"Percentage of the image that was identified as furniture."},"status":{"type":"string","enum":["done","error"],"description":"Status of the analysis."}},"required":["id","created_at","result_url","status"]}}}}
```

## The AnalysisDoneWebhookResponse object

```json
{"openapi":"3.1.0","info":{"title":"Virtual Staging AI API","version":"2.0.0"},"components":{"schemas":{"AnalysisDoneWebhookResponse":{"type":"object","properties":{"id":{"type":"string","description":"Analysis ID."},"timestamp":{"type":"number","description":"Event timestamp (epoch milliseconds)."},"event_type":{"type":"string","enum":["analysis_completion"],"description":"Event type indicating successful analysis completion."},"percentage_masked":{"type":"number","description":"Percentage of the image that was identified as furniture."},"result_url":{"type":"string","description":"URL of the analysis result image."}},"required":["event_type","result_url","id","percentage_masked","timestamp"]}}}}
```

## The AnalysisErrorWebhookResponse object

```json
{"openapi":"3.1.0","info":{"title":"Virtual Staging AI API","version":"2.0.0"},"components":{"schemas":{"AnalysisErrorWebhookResponse":{"type":"object","properties":{"id":{"type":"string","description":"Analysis ID."},"timestamp":{"type":"number","description":"Event timestamp (epoch milliseconds)."},"event_type":{"type":"string","enum":["analysis_error"],"description":"Event type indicating analysis failure."},"error_message":{"type":"string","description":"Detailed error message explaining the failure."}},"required":["id","timestamp","event_type","error_message"]}}}}
```

## The DoneWebhookResponse object

```json
{"openapi":"3.1.0","info":{"title":"Virtual Staging AI API","version":"2.0.0"},"components":{"schemas":{"DoneWebhookResponse":{"type":"object","properties":{"render_id":{"type":"string","description":"ID of the render that this variation belongs to."},"variation_id":{"type":"string","description":"ID of the variation that completed."},"variation_type":{"type":"string","enum":["staging","removal","enhancement","daytodusk","multi-view-staging"],"description":"Type of variation that completed."},"base_variation_id":{"type":["string","null"],"description":"ID of the removal variation used as base, if this staging variation used a removal variation as its base."},"timestamp":{"type":"number","description":"Event timestamp (epoch milliseconds)."},"event_type":{"type":"string","enum":["done"],"description":"Event type indicating successful completion."},"result":{"oneOf":[{"$ref":"#/components/schemas/ImageResult"},{"type":"array","items":{"$ref":"#/components/schemas/ImageResult"}}],"description":"Generated result images."}},"required":["event_type","result","render_id","variation_id","variation_type","timestamp","base_variation_id"]},"ImageResult":{"type":"object","properties":{"url":{"type":"string","description":"Original image URL."},"optimized_url":{"type":["string","null"],"description":"Optimized (compressed) version URL."},"thumbnail_url":{"type":["string","null"],"description":"Thumbnail version URL."}},"required":["url"]}}}}
```

## The ErrorWebhookResponse object

```json
{"openapi":"3.1.0","info":{"title":"Virtual Staging AI API","version":"2.0.0"},"components":{"schemas":{"ErrorWebhookResponse":{"type":"object","properties":{"render_id":{"type":"string","description":"ID of the render that this variation belongs to."},"variation_id":{"type":"string","description":"ID of the variation that failed."},"variation_type":{"type":"string","enum":["staging","removal","enhancement","daytodusk","multi-view-staging"],"description":"Type of variation that failed."},"timestamp":{"type":"number","description":"Event timestamp (epoch milliseconds)."},"event_type":{"type":"string","enum":["error"],"description":"Event type indicating an error occurred."},"error_message":{"type":"string","description":"Detailed error message explaining the failure."}},"required":["event_type","error_message","render_id","variation_id","variation_type","timestamp"]}}}}
```

## The UpdateWebhookResponse object

```json
{"openapi":"3.1.0","info":{"title":"Virtual Staging AI API","version":"2.0.0"},"components":{"schemas":{"UpdateWebhookResponse":{"type":"object","properties":{"render_id":{"type":"string","description":"ID of the render that this variation belongs to."},"variation_id":{"type":"string","description":"ID of the variation that was updated."},"variation_type":{"type":"string","enum":["staging","removal","enhancement","daytodusk","multi-view-staging"],"description":"Type of variation that was updated."},"timestamp":{"type":"number","description":"Event timestamp (epoch milliseconds)."},"event_type":{"type":"string","enum":["update"],"description":"Event type indicating a status update."},"variation_status":{"type":"string","enum":["queued","rendering","done","error","idle","deleted"],"description":"Current status of the variation."},"eta":{"type":"number","description":"Estimated time remaining for the variation to complete (epoch milliseconds timestamp)."}},"required":["event_type","variation_status","eta","render_id","variation_id","variation_type","timestamp"]}}}}
```

## The WebhookResponse object

```json
{"openapi":"3.1.0","info":{"title":"Virtual Staging AI API","version":"2.0.0"},"components":{"schemas":{"WebhookResponse":{"oneOf":[{"$ref":"#/components/schemas/DoneWebhookResponse"},{"$ref":"#/components/schemas/ErrorWebhookResponse"},{"$ref":"#/components/schemas/UpdateWebhookResponse"},{"$ref":"#/components/schemas/AnalysisDoneWebhookResponse"},{"$ref":"#/components/schemas/AnalysisErrorWebhookResponse"}],"description":"Webhook response payload for various events."},"DoneWebhookResponse":{"type":"object","properties":{"render_id":{"type":"string","description":"ID of the render that this variation belongs to."},"variation_id":{"type":"string","description":"ID of the variation that completed."},"variation_type":{"type":"string","enum":["staging","removal","enhancement","daytodusk","multi-view-staging"],"description":"Type of variation that completed."},"base_variation_id":{"type":["string","null"],"description":"ID of the removal variation used as base, if this staging variation used a removal variation as its base."},"timestamp":{"type":"number","description":"Event timestamp (epoch milliseconds)."},"event_type":{"type":"string","enum":["done"],"description":"Event type indicating successful completion."},"result":{"oneOf":[{"$ref":"#/components/schemas/ImageResult"},{"type":"array","items":{"$ref":"#/components/schemas/ImageResult"}}],"description":"Generated result images."}},"required":["event_type","result","render_id","variation_id","variation_type","timestamp","base_variation_id"]},"ImageResult":{"type":"object","properties":{"url":{"type":"string","description":"Original image URL."},"optimized_url":{"type":["string","null"],"description":"Optimized (compressed) version URL."},"thumbnail_url":{"type":["string","null"],"description":"Thumbnail version URL."}},"required":["url"]},"ErrorWebhookResponse":{"type":"object","properties":{"render_id":{"type":"string","description":"ID of the render that this variation belongs to."},"variation_id":{"type":"string","description":"ID of the variation that failed."},"variation_type":{"type":"string","enum":["staging","removal","enhancement","daytodusk","multi-view-staging"],"description":"Type of variation that failed."},"timestamp":{"type":"number","description":"Event timestamp (epoch milliseconds)."},"event_type":{"type":"string","enum":["error"],"description":"Event type indicating an error occurred."},"error_message":{"type":"string","description":"Detailed error message explaining the failure."}},"required":["event_type","error_message","render_id","variation_id","variation_type","timestamp"]},"UpdateWebhookResponse":{"type":"object","properties":{"render_id":{"type":"string","description":"ID of the render that this variation belongs to."},"variation_id":{"type":"string","description":"ID of the variation that was updated."},"variation_type":{"type":"string","enum":["staging","removal","enhancement","daytodusk","multi-view-staging"],"description":"Type of variation that was updated."},"timestamp":{"type":"number","description":"Event timestamp (epoch milliseconds)."},"event_type":{"type":"string","enum":["update"],"description":"Event type indicating a status update."},"variation_status":{"type":"string","enum":["queued","rendering","done","error","idle","deleted"],"description":"Current status of the variation."},"eta":{"type":"number","description":"Estimated time remaining for the variation to complete (epoch milliseconds timestamp)."}},"required":["event_type","variation_status","eta","render_id","variation_id","variation_type","timestamp"]},"AnalysisDoneWebhookResponse":{"type":"object","properties":{"id":{"type":"string","description":"Analysis ID."},"timestamp":{"type":"number","description":"Event timestamp (epoch milliseconds)."},"event_type":{"type":"string","enum":["analysis_completion"],"description":"Event type indicating successful analysis completion."},"percentage_masked":{"type":"number","description":"Percentage of the image that was identified as furniture."},"result_url":{"type":"string","description":"URL of the analysis result image."}},"required":["event_type","result_url","id","percentage_masked","timestamp"]},"AnalysisErrorWebhookResponse":{"type":"object","properties":{"id":{"type":"string","description":"Analysis ID."},"timestamp":{"type":"number","description":"Event timestamp (epoch milliseconds)."},"event_type":{"type":"string","enum":["analysis_error"],"description":"Event type indicating analysis failure."},"error_message":{"type":"string","description":"Detailed error message explaining the failure."}},"required":["id","timestamp","event_type","error_message"]}}}}
```


# Webhooks

Webhooks allow you to receive real-time updates when new Variations are created. By setting up a webhook, your application can automatically receive information about these events without the need for constant polling.

### How Webhooks Work

When creating a Render or Variation, include a `webhook_url` parameter:

```
{
"config": { ... },
"image_url": "https://example.com/room.jpg",
"variation_count": 3,
"webhook_url": "https://your-app.com/webhooks/renders"
}
```

Your endpoint will receive separate POST requests for:

* Each Variation's completion or error state
* Analysis results (when using the analyze endpoint)

For example, if you create a render with 3 Variations, you'll receive 3 webhook responses once the Variations either complete or fail. You will not receive a separate webhook response for the parent Render.

### Variation Webhook Response Types

There are 2 Variation webhook payload types: `done` and `error`.

#### \`Done\` response schema

```
{
"render_id": "rnd_abc123", // the parent render id
"variation_id": "var_xyz789",
"variation_type": "staging",
"base_variation_id": "var_removal123", // if using a base variation from a removal
"timestamp": 1634567890123,
"event_type": "done",
"result": {
    "url":"https://results.example.com/image.jpg",
    "optimized_url":"https://results.example.com/image_optimized.webp",
    "thumbnail_url":"https://results.example.com/image_thumb.jpg"
    }
}
```

#### \`Error\` response schema

```
{
"render_id": "rnd_abc123",
"variation_id": "var_xyz789",
"variation_type": "staging",
"timestamp": 1634567890123,
"event_type": "error",
"error_message": "Failed to process image"
}
```

### Analysis Webhook Response Types

### Best Practices

1. **Acknowledge Quickly**: Return a 200 status code as soon as you receive the webhook. Process the payload asynchronously if needed.
2. **Handle Retries**: Webhooks will be retried up to 3 times if your endpoint fails to respond with a 200 status.
3. **Store Base Variation IDs**: For staging variations, the `base_variation_id` links to the removal variation it was based on (if a base variation was used or the removal mode was set to `auto`).
4. **Track Event Types**: Different `event_type` values indicate different stages:
   * `update`: Status changes and progress
   * `done`: Processing complete
   * `error`: Processing failed
   * `analysis_completion`: Analysis complete
   * `analysis_error`: Analysis failed

### Testing Webhooks

We recommend using tools like [webhook.site](https://webhook.site) for testing webhook integration before setting up your production endpoint.

### Authenticating Webhooks

To ensure the security and authenticity of webhook payloads, we use HMAC (Hash-based Message Authentication Code) signatures. This helps verify that webhook requests are genuinely coming from our servers and haven't been tampered with.

### How HMAC Works

HMAC combines your secret key with the webhook payload to create a unique signature. The process works like this:

1. We take your webhook secret (which only you and our servers know)
2. We combine it with the exact payload data
3. We run this through a cryptographic hash function (SHA-256)
4. The result is a unique signature that can only be generated with both the correct secret and payload

This means that if anyone tries to:

* Send a fake webhook without knowing your secret
* Modify the payload in any way
* Use a different secret

The signature verification will fail, alerting you to the potential security issue.

#### Setting Up Webhook Authentication

1. Set your webhook secret using the `POST /user/webhook-secret` endpoint. You can remove it at any time using the `DELETE /user/webhook-secret` endpoint.
2. When receiving webhooks, verify the signature:<br>

   ```javascript
   const crypto = require('crypto');

   function verifyWebhookSignature(payload, signature, secret) {
     const calculatedSignature = crypto
       .createHmac('sha256', secret)
       .update(JSON.stringify(payload))
       .digest('hex');
       
     return signature === calculatedSignature;
   }

   // In your webhook handler:
   app.post('/webhook', (req, res) => {
     const signature = req.headers['x-vsai-signature'];
     const payload = req.body;
     
     if (!verifyWebhookSignature(payload, signature, 'your-secret-here')) {
       return res.status(401).json({ error: 'Invalid signature' });
     }
     
     // Process the webhook...
   });
   ```

The signature is sent in the X-VSAI-Signature header. Always verify this signature before processing any webhook payload to ensure it's legitimate.


