StageHQ API
Stage room photos from your own code. The API uses the same engine and the same credits as the studio: 1 credit per staged image, and a failed job refunds its credit. Base URL: https://stagehq.ai/api/v1.
Quickstart
- Buy any credit pack. API keys are for paid accounts.
- Open Account → Developers and create a key. Copy it: it is shown once.
- Send a photo, then poll the job until it is finished.
import { readFile } from "node:fs/promises";
const API = "https://stagehq.ai/api/v1";
const headers = { Authorization: `Bearer ${process.env.STAGEHQ_API_KEY}` };
const form = new FormData();
const photo = new Blob([await readFile("empty-room.jpg")], { type: "image/jpeg" });
form.append("image", photo, "empty-room.jpg");
form.append("room_type", "bedroom");
form.append("style", "scandinavian");
const submit = await fetch(`${API}/stagings`, {
method: "POST",
headers: { ...headers, "Idempotency-Key": "listing-1042-photo-3" },
body: form,
});
const job = await submit.json();
if (!submit.ok) throw new Error(`${job.code}: ${job.message}`);
let gen;
do {
await new Promise((r) => setTimeout(r, 5000));
gen = await (await fetch(`${API}/generations/${job.id}`, { headers })).json();
} while (gen.status === "processing");
console.log(gen.status, gen.result_url);Authentication
Send the key in the Authorization header of every request: Authorization: Bearer shq_live_…. Keys start with shq_live_. An account can have up to 5 active keys; revoke a key on the account page at any time.
Keep the key on your server. It spends your credits, so do not put it in a website, a mobile app or a public repository.
Stage a photo
POST /api/v1/stagings with a multipart/form-data body. Returns 202 with the job id and charges 1 credit.
| Field | Required | Description |
|---|---|---|
image | Yes | JPEG, PNG or WebP file, up to 10 MB. |
room_type | No | One of the room types. Default living room. |
style | No | One of the styles. Default modern. |
mode | No | One of the modes. Default precise. |
room_description | No | Short description of the room, up to 160 characters. |
instructions | No | Extra instructions for this photo, up to 500 characters. Name positions from things in the photo ("bed against the wall with the window"). |
Unknown values are rejected with invalid_parameter; nothing is charged.
curl https://stagehq.ai/api/v1/stagings \
-H "Authorization: Bearer $STAGEHQ_API_KEY" \
-H "Idempotency-Key: listing-1042-photo-3" \
-F [email protected] \
-F room_type=bedroom \
-F style=scandinavian \
-F mode=precise \
-F room_description="corner room, two windows" \
-F instructions="queen bed against the long wall"HTTP/1.1 202 Accepted
{
"id": "6f1c2a7e-4b8d-4c55-9a1e-2f3b4c5d6e7f",
"status": "processing",
"status_url": "https://stagehq.ai/api/v1/generations/6f1c2a7e-4b8d-4c55-9a1e-2f3b4c5d6e7f",
"credits_remaining": 41,
"replayed": false
}Get a job
GET /api/v1/generations/{id}. Poll every 5 seconds until status is completed or failed; most jobs finish in about 30 seconds. A job finishes on our side even if you stop polling.
curl https://stagehq.ai/api/v1/generations/6f1c2a7e-4b8d-4c55-9a1e-2f3b4c5d6e7f \
-H "Authorization: Bearer $STAGEHQ_API_KEY"{
"id": "6f1c2a7e-4b8d-4c55-9a1e-2f3b4c5d6e7f",
"tool": "staging",
"status": "completed",
"mode": "precise",
"room_type": "bedroom",
"style": "scandinavian",
"source_url": "https://cdn.stagehq.ai/uploads/…/6f1c2a7e-….jpg",
"result_url": "https://cdn.stagehq.ai/results/…/6f1c2a7e-….png",
"error": null,
"created_at": "2026-10-06T09:00:00.000Z",
"completed_at": "2026-10-06T09:00:31.000Z"
}result_url is a permanent link to the staged image at about 2K resolution. The file name contains a random token, but anyone who has the link can open the image, so treat it like a private link and copy the file into your own storage. A failed job has an error value and its credit is refunded.
Credit balance
GET /api/v1/credits returns the account balance.
curl https://stagehq.ai/api/v1/credits \
-H "Authorization: Bearer $STAGEHQ_API_KEY"
{ "credits": 41, "plan": "paid" }Safe retries
Send an Idempotency-Key header (1–255 printable characters, no spaces) with POST /stagings. If a request with the same key already exists on your account, the API returns that job with 200, "replayed": trueand the job's current status, and charges nothing. A repeat with different fields still returns the first job. Use one key per photo, for example your listing id plus the photo number, so a timeout retry never pays twice.
Modes
| mode | What it does |
|---|---|
precise | Default. Adds furniture and decor; walls, floors, windows and fixtures stay exactly as photographed. |
creative | Fuller styling: furniture, decor, artwork and accent finishes. |
renovation | Shows the room remodeled: new finishes, fixtures and layout. |
remove | Removes the furniture and clutter in the photo and leaves the room empty. |
Room types
| Group | room_type values |
|---|---|
| Residential | living roombedroomnurserybathroomkitchendining roomhome officestudioloftdressing roomtoiletbasementgarage |
| Commercial | office spacemeeting roomcoworking spacereception area |
| Hospitality | hotel lobbyhotel roomhotel bathroomrestaurantcoffee shop |
| Specialty | study roomgaming roomworkshopfitness gymauditoriumclassroomlecture hallclothing store |
| Outdoor | backyardpatio |
Styles
| Group | style values |
|---|---|
| Popular | ai-decidemodernminimalistcontemporaryjapandiwarm-cozymodern-farmhouse |
| Classic | neoclassicart-decoart-nouveaubaroquemidcentury-modernbauhaus |
| Natural & Organic | biophilicrusticcoastalmediterraneantropicalwabi-sabizen |
| Bold & Eclectic | industrialboho-chiceclecticmaximalisttribal |
| Luxury | luxuryscandinavian |
| Vintage & Retro | vintageshabby-chicmedievalpharaonic |
| Futuristic | futuristiccyberpunk |
| Seasonal | christmashalloween |
Errors
Every error has the same JSON shape. Use code in your logic and show message to people.
HTTP/1.1 402 Payment Required
{
"status": "error",
"code": "insufficient_credits",
"message": "Not enough credits. Buy credits to continue."
}| HTTP | code | Meaning |
|---|---|---|
| 400 | invalid_parameter | A parameter or the Idempotency-Key is not valid. The message names the field. |
| 400 | image_required | No `image` file in the form. |
| 400 | invalid_format | The file is not a JPEG, PNG or WebP image. |
| 400 | file_too_large | The file is larger than 10 MB. |
| 400 | read_error | The image could not be decoded. |
| 401 | invalid_api_key | The key is missing, malformed, unknown or revoked. |
| 402 | insufficient_credits | The account has no credits left. |
| 403 | paid_required | The account has no paid credit pack. Keys work only on paid accounts. |
| 404 | not_found | No job with this id on your account. |
| 429 | rate_limited | Too many stagings this minute. Wait for the Retry-After seconds. |
| 500 | api_error | The job could not start. The credit was refunded; retry. |
Limits
- 12 stagings per minute per account, shared with the studio. Over the limit:
429with aRetry-Afterheader. - Polling a running job: up to 60 checks per minute per account. Over that, the response still comes back, with a
Retry-Afterheader. - Images: JPEG, PNG or WebP, up to 10 MB; larger than 4096 px on a side is resized down.
- Server-to-server only: the API does not send CORS headers for browser calls.
Questions or a feature you need? Contact us.