Virtual Staging ART Developer API
Use the Virtual Staging ART API to upload an image, request staging or decluttering, poll for status, and receive finished render URLs by webhook.
Base URL
Examples on this page use the legacy-compatible /api/... paths:
https://www.virtualstaging.art/api/...
Equivalent /v1/... paths are also available if you prefer them.
Authentication
All developer API requests use a Bearer token:
Authorization: Bearer YOUR_API_TOKEN
You can generate an API token from your Virtual Staging ART account settings.
Typical workflow
Most integrations follow this sequence:
- Upload an image with
/api/image/upload, or provide your own public image URL. - Submit a render request with
/api/image/render/requestor/api/image/render/declutter. - Poll
/api/image/check-statuswith the returnedupload_id, or provide acallback_urland wait for the webhook. - Use the returned render URLs in your app.
1. Upload an image
Endpoint
POST /api/image/upload
Response
{
"url": "https://..."
}
Use the returned url as the image_url in the render request.
Option A: Multipart upload
Send a standard file upload using multipart/form-data.
Form field:
file
Example:
curl -X POST "https://www.virtualstaging.art/api/image/upload" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-F "[email protected]"
Option B: Base64 JSON upload
Send either raw base64 or a data URL in JSON.
Raw base64 example:
{
"image_base64": "BASE64_HERE",
"content_type": "image/jpeg"
}
Data URL example:
{
"data_url": "data:image/png;base64,iVBORw0KGgoAAA..."
}
Upload limits
- Max upload size:
10 MB - Accepted formats:
- JPEG
- PNG
- WebP
- HEIC / HEIF
2. Use your own image URL instead of uploading
If you already host your images yourself, you can skip /api/image/upload and send your own image_url directly in the render request.
Your image_url should be:
- a direct image URL
- publicly reachable
https://- returning the image file itself with a normal
200response
Examples that usually fail:
- expired temporary URLs
- links that require login or cookies
- share pages that return HTML instead of the raw image
- localhost or private-network URLs
3. Submit a staging render
Endpoint
POST /api/image/render/request
Request body
{
"image_url": "https://example.com/source.jpg",
"room_type": "living",
"style": "modern",
"number_of_renders": 1,
"upload_id": "optional-grouping-id",
"layout_type": "studio",
"ai_notes": "Keep the room bright and add a premium contemporary feel.",
"callback_url": "https://example.com/callback",
"tier": "premium"
}
Required fields
image_urlroom_typestyle
tier options
classic- default if omitted
- supports up to
20renders per upload group
premium- supports up to
8renders per credit charge on this compatibility endpoint
- supports up to
Supported room_type
livingbedkitchenofficediningstudioldk* premium onlybathroom* premium onlyentrance* premium only
Legacy note: home_office is also accepted as an alias for office.
Supported style
modernscandinavianindustrialcoastalluxurymid-century modernfarmhousestandardminimalist* premium onlyjapandi* premium onlybohemian* premium onlytraditional* premium only
Optional fields
number_of_renders- default:
1 - max per request:
10
- default:
upload_id- lets you keep repeated requests grouped under the same upload
layout_typestudiois supported for compatibility
callback_url- webhook destination for completion notifications
ai_notes* premium only- optional free-text guidance for the model
- max length:
500characters
tierclassicorpremium- existing API users default to
classicif omitted
Response
{
"upload_id": "uuid-or-existing-group-id",
"status": "rendering",
"tier": "classic"
}
4. Submit a declutter render
Endpoint
POST /api/image/render/declutter
tier options
classic- default if omitted
- supports up to
20renders per upload group
premium- supports up to
8renders per credit charge on this compatibility endpoint
- supports up to
Request body
{
"image_url": "https://example.com/source.jpg",
"number_of_renders": 1,
"upload_id": "optional-grouping-id",
"ai_notes": "Remove clutter while preserving the natural lighting.",
"callback_url": "https://example.com/callback",
"tier": "premium"
}
ai_notes is available on declutter requests only when tier is premium.
Response
{
"upload_id": "uuid-or-existing-group-id",
"status": "rendering",
"tier": "classic"
}
5. Check render status
Endpoint
POST /api/image/check-status
Recommended request
{
"upload_id": "uuid-or-existing-group-id"
}
Compatibility request
{
"image_url": "https://example.com/source.jpg"
}
Response
{
"status": "rendering"
}
Possible values:
renderingdoneerror
upload_id is the preferred lookup method.
6. Check how many renders have been used for an upload
Endpoint
POST /api/image/check-rendering-amount
Request body
{
"uploadId": "uuid-or-existing-group-id"
}
You can also use:
{
"sourceImage": "https://example.com/source.jpg"
}
Compatibility aliases are also accepted:
{
"upload_id": "uuid-or-existing-group-id",
"image_url": "https://example.com/source.jpg"
}
Response
{
"renderCount": 3,
"limitExceeded": false,
"maxRenders": 20
}
7. Webhook callbacks
If you provide callback_url in a render request, Virtual Staging ART will POST the result when the job completes.
Success payload
{
"status": "done",
"render_urls": [
"https://assets.example.com/render-1.jpg",
"https://assets.example.com/render-2.jpg"
]
}
Error payload
{
"status": "error",
"error": "Internal server error. Please try again later."
}
Compatibility notes for existing Virtual Staging integrations
What still works
- legacy
/api/...image endpoints remain available - existing API users still default to
classictier if notieris provided upload_idgrouping is preserved for repeated compatibility requestslayout_type="studio"is supported- callback payloads still use the familiar
status+render_urlsshape
What changed
The old Vercel Blob upload handshake is no longer supported.
/api/image/upload now accepts:
multipart/form-data- JSON with
image_base64 - JSON with
data_url
If an old client still tries the legacy Vercel upload method, the endpoint returns a clear error telling you to switch to multipart or base64 upload.
Common errors
400invalid request body, invalid image format, invalid image URL, unsupported content type, or render cap exceeded401missing or invalid API token402insufficient credits403account blocked or restricted413upload too large503temporary service or queueing failure