API Reference
Use the VirtualStaging.ai API to submit virtual staging, furniture removal, and custom-prompt editing jobs from your own application. All jobs are processed asynchronously — you submit a request and receive the result via a webhook callback.
Overview
Base URL
How it works
- You POST a request with an image URL, a webhook URL, and a payload describing the operation.
- The API responds immediately with a
request_idand starts processing in the background. - When the render is complete, the API calls your webhook with the result image URL.
- Each request uses 1 token from your subscription. Revisions are free.
Request headers
BothAuthorizationand
Authentication
Generate an API key
- Log in and go to Account Settings, then click the API settings tab.
- Click Generate key, enter a name, and confirm.
- Copy both the Key and the Secret immediately — the key is only visible for 1 hour and the secret is used to verify webhook callbacks.
Revoke an API key
- Go to the API settings tab in Account Settings.
- Click Revoke key next to the key you want to disable.
Security tip: never expose your API key in client-side code or public repositories. Store it as an environment variable on your server.
Endpoints
All operations share a single endpoint:
The operation type is determined by the type field inside the payload JSON string.
Virtual Staging
Virtually furnish and decorate an empty room. Choose a style and room type combination from the list of valid type values below.
Request parameters
| Field | Description |
|---|---|
imagerequired | Publicly accessible HTTPS URL of the source room photo. |
webhookrequired | HTTPS URL that receives the result callback when rendering is complete. |
payloadrequired | A JSON-encoded string containing at minimum identifier and type. |
Payload fields
| Field | Description |
|---|---|
identifierrequired | Your own reference ID — echoed back in the webhook so you can match the result to your record. |
typerequired | The staging style. See valid values below. |
Valid type values
| Style | Valid values |
|---|---|
| Modern | Modern LivingModern BedroomModern DiningModern OfficeModern Living & DiningModern HallwayModern Game RoomModern Kid's RoomModern Nursery |
| Luxury Modern | Luxury Modern LivingLuxury Modern BedroomLuxury Modern DiningLuxury Modern OfficeLuxury Modern Living & DiningLuxury Modern HallwayLuxury Modern Game RoomLuxury Modern Kid's RoomLuxury Modern Nursery |
| Scandinavian | Scandinavian LivingScandinavian BedroomScandinavian DiningScandinavian OfficeScandinavian Living & DiningScandinavian HallwayScandinavian Game RoomScandinavian Kid's RoomScandinavian Nursery |
| Industrial | Industrial LivingIndustrial BedroomIndustrial DiningIndustrial OfficeIndustrial Living & DiningIndustrial HallwayIndustrial Game RoomIndustrial Kid's RoomIndustrial Nursery |
| Traditional | Traditional LivingTraditional BedroomTraditional DiningTraditional OfficeTraditional Living & DiningTraditional HallwayTraditional Game RoomTraditional Kid's RoomTraditional Nursery |
| Bohemian | Bohemian LivingBohemian BedroomBohemian DiningBohemian OfficeBohemian Living & DiningBohemian HallwayBohemian Game RoomBohemian Kid's RoomBohemian Nursery |
| Transitional | Transitional LivingTransitional BedroomTransitional DiningTransitional OfficeTransitional Living & DiningTransitional HallwayTransitional Game RoomTransitional Kid's RoomTransitional Nursery |
| Mid Century | Mid Century LivingMid Century BedroomMid Century DiningMid Century OfficeMid Century Living & DiningMid Century HallwayMid Century Game RoomMid Century Kid's RoomMid Century Nursery |
| Farmhouse | Farmhouse LivingFarmhouse BedroomFarmhouse DiningFarmhouse OfficeFarmhouse Living & DiningFarmhouse HallwayFarmhouse Game RoomFarmhouse Kid's RoomFarmhouse Nursery |
Request body
Response
Python
JavaScript (Node.js)
cURL
Multi-angle Staging
Generate a staged version of a room using two angles of the same space. Send the empty room photo you want staged as image, and include an already-staged image of the same room from another angle as ref_image inside the payload. The AI reuses the furniture, layout and style from ref_image so both angles stay consistent.
Both images must be the same physical room. First stage one angle with the standard Virtual Staging endpoint, then pass that staged result asref_imagewhen staging the next angle. For best consistency use overlapping angles and avoid fully opposite shots. The result is a single staged image based onimage.
Request parameters
| Field | Description |
|---|---|
imagerequired | Publicly accessible HTTPS URL of the empty room photo for the angle you want staged. |
webhookrequired | HTTPS URL that receives the result callback when rendering is complete. |
payloadrequired | JSON-encoded string with identifier, type, and ref_image. |
Payload fields
| Field | Description |
|---|---|
identifierrequired | Your own reference ID. |
typerequired | The staging style — same valid values as Virtual Staging. |
ref_imagerequired | Publicly accessible HTTPS URL of an already-staged image of the same room from another angle (typically the output of a previous staging call). |
Request body
Response
Python
JavaScript (Node.js)
cURL
Furniture Removal
Remove specific objects from a room photo using a mask image. The mask must be the same dimensions as the source image — white pixels mark areas to remove, black pixels are kept.
Request parameters
| Field | Description |
|---|---|
imagerequired | Publicly accessible HTTPS URL of the source room photo. |
maskrequired | Publicly accessible HTTPS URL of the mask image (same dimensions as image). White = remove, black = keep. |
webhookrequired | HTTPS URL that receives the result callback. |
payloadrequired | JSON-encoded string with identifier and type: "removal". |
Request body
Python
cURL
Custom Prompt
Edit a room photo using a free-text prompt. The AI will apply the instructions to the source image. Use type: "refine" and include a prompt field in the payload.
Request parameters
| Field | Description |
|---|---|
imagerequired | Publicly accessible HTTPS URL of the source room photo. |
webhookrequired | HTTPS URL that receives the result callback. |
payloadrequired | JSON-encoded string with identifier, type: "refine", and prompt. |
Payload fields
| Field | Description |
|---|---|
identifierrequired | Your own reference ID. |
typerequired | Must be "refine". |
promptrequired | A natural-language description of the changes to apply to the image. |
Request body
Python
JavaScript (Node.js)
cURL
Revision
Re-run any previous request by sending its request_id back to the same endpoint. Revisions do not consume a token. You can revise unlimited times.
Optionally override webhook or payload on the revision if you need the result delivered to a different URL or with different metadata.
Request parameters
| Field | Description |
|---|---|
request_idrequired | The request_id returned by the original request. |
webhookoptional | Override the webhook URL for this revision only. |
payloadoptional | Override the payload JSON string for this revision only. |
Request body (minimal)
Request body (with overrides)
Response
Python
JavaScript (Node.js)
cURL
Webhook
When a render completes, we send a POST request to your webhook URL with the result.
Webhook payload
identifieris exactly what you sent in the original request payload. Use it to match this callback to your internal record.outputis the URL of the completed render.
Verifying authenticity
Every webhook request includes a Verification-Token header set to your API key secret. Always validate this before processing the payload.
Important: webhook endpoints must allow unauthenticated access — do not protect them with standard auth middleware. Use only the token check below.
Node.js (Express)
Python (Django REST Framework)
PHP (Symfony) — security.yaml
PHP (Symfony) — Controller
Testing your credentials
Before making real requests, verify that your API key, secret, and email are configured correctly by calling the test endpoint. It does not consume a token.
POST https://backend.virtualstaging.ai:8443/api/api-test/A successful response confirms your credentials and shows which plan is active:
If you receive 401 the key, email, or secret is wrong. Generate a new key in Account Settings → API settings.
Errors
All errors return HTTP 400 with a JSON body containing an error field.
| HTTP | Error message | Cause & fix |
|---|---|---|
| Authentication | ||
| 401 | No auth token or email provided | The Authorization or Email header is missing. Both are required on every request. |
| 401 | Invalid or inactive API key | The API key does not match the email, has been revoked, or belongs to a different account. Generate a new key in Account Settings → API settings. |
| Tokens & requests | ||
| 400 | No funds | No tokens remaining on your subscription. Purchase more or upgrade your plan. |
| 400 | There is no request with this id | The request_id does not exist or belongs to a different API key. |
| URL validation | ||
| 400 | Image URL must use HTTPS. | Only HTTPS URLs are accepted for image. |
| 400 | Invalid image URL. | The image field is not a valid URL. |
| 400 | Image URL does not exist. | The server could not reach the image. Make sure it is publicly accessible and returns HTTP 200. |
| 400 | Mask URL must use HTTPS. | Only HTTPS URLs are accepted for mask. |
| 400 | Invalid mask URL. | The mask field is not a valid URL. |
| 400 | Mask URL does not exist. | Make sure the mask image is publicly accessible and returns HTTP 200. |
| 400 | Webhook URL must use HTTPS. | Only HTTPS URLs are accepted for webhook. |
| 400 | Invalid webhook URL. | The webhook field is not a valid URL. |
| Payload validation | ||
| 400 | Payload must be a valid JSON string. | payload must be a JSON-encoded string, not a nested object. Use json.dumps() in Python or JSON.stringify() in JavaScript. |
| 400 | Payload must contain a 'type' key with a valid value. | The type field is missing or unrecognized. See valid type values. |
| 400 | Payload must contain an 'identifier'... | The identifier field is missing. It must be a string or number used to match the webhook callback to your record. |
Example error response
Limits & Costs
Token costs
| Operation | Token cost |
|---|---|
| Virtual Staging | 1 token |
| Furniture Removal | 1 token |
| Custom Prompt | 1 token |
| Revision (any type) | Free |
Concurrency & throughput
- There is no hard limit on how many requests you can submit.
- The rendering pipeline processes approximately 2–3 jobs simultaneously.
- Because the API is asynchronous you can submit many requests in parallel — extra jobs are queued and processed in order. Expect delays during peak demand.
Need help?
Email: [email protected]
Live chat: via Intercom on our website