Table of Contents(8)
- What You're Building: Architecture of a Staging Feature
- Before You Start: Keys, Environments, and Image Requirements
- Step 1: Submit a Staging Job
- Step 2: Handle Completion — Webhooks vs Polling
- Step 3: Deliver Results to Your Users
- Production Concerns: Rate Limits, Retries, and Credit Budgeting
- Common Mistakes in Staging API Integrations
- The Bottom Line: Ship the Loop, Then Extend It
This tutorial shows developers how to add AI virtual staging to any app through a REST API. The pattern: upload a room photo, submit an asynchronous job, and receive furnished results via webhook or polling in 10–40 seconds. Using Roomagen's API as the worked example, the core integration is one POST endpoint, one webhook handler, and a storage step, at $0.20–$0.25 per image on volume packs with failed jobs automatically refunded.
Free AI Virtual Staging — Stage Any Empty Room in 30 Seconds
Stage vacant listings with AI in 30 seconds. 14 design styles, MLS-ready photos, used by realtors and photographers. 6 free credits, no credit card required.
What You're Building: Architecture of a Staging Feature
By the end of this tutorial, your app will accept a room photo from a user, send it to a virtual staging API, and return a furnished, photorealistic version of that room 10–40 seconds later. That is the entire feature. Everything else — webhooks, retries, credit budgeting, disclosure labels — exists to make that loop reliable at production scale.
The demand side is well established. The global virtual staging market reached $454 million in 2025 and staging demand keeps climbing as listings compete for online attention:
"The global virtual staging solution market is projected to grow from $454 million in 2025 to $4.73 billion by 2035." — Business Research Insights
If you run a listing platform, a photography delivery tool, a property management dashboard, or a proptech CRM, staging is increasingly a feature your users expect inside your product rather than a separate service they visit.
Architecturally, every staging API on the market — Roomagen, AI HomeDesign, Decor8, and a handful of others — follows the same asynchronous job pattern. Generation takes tens of seconds, far too long to hold an HTTP request open, so the flow is always: submit a job, get a job ID immediately, and receive results later.
| Stage | Who handles it | Typical latency |
|---|---|---|
| Upload and validate photo | Your app | Under 1 second |
| Submit staging job | Your backend → staging API | Under 1 second |
| AI generation | Staging provider | 10–40 seconds |
| Completion notification | Webhook (push) or polling (pull) | 0–10 seconds |
| Store and display results | Your app | Under 1 second |
This tutorial uses the Roomagen API as the worked example because its endpoints map cleanly onto the generic pattern, but every concept here — async jobs, webhooks versus polling, idempotency, failure economics — transfers directly to any provider. Where Roomagen-specific behavior matters, it is called out explicitly.
Before You Start: Keys, Environments, and Image Requirements
You need three things before writing integration code: an API key, a plan for separating environments, and images that meet the provider's input requirements.
Getting a key. Roomagen's API is in early access: join the waitlist at roomagen.com/api, and the free developer tier includes 50 watermarked calls per month — enough to build and test the full integration before spending anything. Keys look like rmg_live_... and are sent in an X-Api-Key header. Whatever provider you choose, the same two rules apply: keep the key in a server-side environment variable, and never ship it in client-side JavaScript or a mobile binary, where anyone can extract it and drain your credits.
Environments. Use separate keys for development and production if the provider issues them. During development, watermarked output is actually useful — it prevents test images from accidentally reaching a live listing.
Image inputs. Staging quality depends heavily on input quality. The table below summarizes what a staging API typically expects, using Roomagen's requirements as the concrete case.
| Requirement | Recommendation |
|---|---|
| Format | JPEG or PNG |
| Delivery | Public image_url (preferred) or image_base64 |
| Resolution | 1024px+ on the long edge; higher input yields higher-quality output |
| Content | A single room, shot level, reasonably lit; wide-angle works |
| Room state | Empty rooms stage most predictably; furnished rooms suit redesign tools |
One practical note: passing a URL is better than base64 for anything above trivial file sizes. Your backend avoids re-encoding overhead, request bodies stay small, and the provider fetches the image directly from your CDN or signed storage URL.
Finally, check your credit balance programmatically. Roomagen exposes GET /api/v1/account, which returns image_credits — poll it from your admin dashboard or a daily cron so you are never surprised mid-month. Most credit-based providers offer an equivalent endpoint, and wiring a low-balance alert takes ten minutes now versus an outage later.
Step 1: Submit a Staging Job
The core call is a single POST. You specify which tool to run, the image, styling options, and optionally a webhook URL for completion notification.
curl -X POST https://api.roomagen.com/api/v1/jobs \
-H "X-Api-Key: rmg_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"tool": "virtual-staging",
"image_url": "https://cdn.yourapp.com/rooms/123.jpg",
"options": { "room_type": "living_room", "style": "scandinavian" },
"webhook_url": "https://yourapp.com/hooks/roomagen"
}'
The response comes back immediately — before generation finishes:
{ "job_id": "job_8f3ka92m", "status": "processing", "images_charged": 1 }
The same call from a Node.js backend:
const res = await fetch("https://api.roomagen.com/api/v1/jobs", {
method: "POST",
headers: {
"X-Api-Key": process.env.ROOMAGEN_API_KEY,
"Content-Type": "application/json"
},
body: JSON.stringify({
tool: "virtual-staging",
image_url: imageUrl,
options: { room_type: "living_room", style: "scandinavian" },
webhook_url: "https://yourapp.com/hooks/roomagen"
})
});
const { job_id } = await res.json();
Two things to do the moment the response arrives. First, persist the job_id against your own record — the listing, the photo, the user — before doing anything else. That row is your idempotency anchor: if your process crashes, you can recover the job by ID instead of resubmitting and paying twice. Second, record images_charged so your internal accounting matches the provider's.
Note that tool is just a slug. Roomagen's GET /api/v1/tools endpoint lists 40+ tools that all use this identical job pattern — virtual staging for empty rooms, day-to-dusk twilight conversion, item removal for decluttering, image enhancement for exposure and color correction, sketch-to-floor-plan conversion, and virtual renovation among them. Once the job loop below works for staging, adding a "twilight photo" or "remove clutter" button to your app is a one-line change to the tool field. This multi-tool pattern is worth checking for in any provider you evaluate: single-tool APIs mean re-integrating from scratch when your roadmap grows.
For empty-room listings specifically, virtual-staging is the workhorse, while furnished rooms route better to a redesign tool or an unfurnishing tool first — a distinction your UI can expose as a simple "is the room empty?" toggle.
Step 2: Handle Completion — Webhooks vs Polling
Your job is processing. Now you need to know when it finishes. There are exactly two mechanisms, and mature integrations use both.
| Dimension | Webhooks (push) | Polling (pull) |
|---|---|---|
| Latency | Near-instant on completion | Up to one polling interval (5–10 s) |
| Infrastructure | Public HTTPS endpoint required | None beyond a scheduler |
| Reliability | Delivery can fail (your downtime, network) | Robust — you control the loop |
| Security work | Signature verification required | API key only |
| Server cost | One request per job | N requests per job |
| Best for | Production at volume | Development, fallback, low volume |
The recommended pattern: webhooks as the primary channel, polling as the fallback. Register a webhook_url on every job, and also schedule a polling check — GET /api/v1/jobs/{id} every 5–10 seconds — that activates if no webhook has arrived within, say, 60 seconds. Cap the polling at a hard timeout (2–3 minutes) after which the job is marked failed in your UI. This combination survives webhook outages on either side without adding meaningful cost. Both GitHub's and Stripe's webhook guidance converge on the same principles: respond fast, verify signatures, deduplicate, and reconcile with polling.
A minimal Express webhook handler with signature verification:
app.post("/hooks/roomagen", express.raw({ type: "*/*" }), (req, res) => {
const sig = req.get("X-Roomagen-Signature");
const expected = crypto
.createHmac("sha256", process.env.ROOMAGEN_WEBHOOK_SECRET)
.update(req.body)
.digest("hex");
if (!sig || !crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) {
return res.sendStatus(401);
}
const { job_id, status, result_urls } = JSON.parse(req.body);
completeJob(job_id, status, result_urls); // must be idempotent
res.sendStatus(200);
});
Three details matter here. First, verify the signature on the raw body, before JSON parsing — Roomagen signs payloads with HMAC-SHA256 (RFC 2104) and sends the digest in X-Roomagen-Signature; most providers use an equivalent scheme. Skipping verification means anyone who discovers your endpoint URL can inject fake "completed" events into your app. Second, use a timing-safe comparison, not ===. Third, make the completion handler idempotent: webhook systems retry on failure, so the same event may arrive twice, and polling may also have already completed the job. An UPDATE ... WHERE status = 'processing' guard is usually enough.
When polling, the status endpoint returns everything you need: status (processing, completed, or failed), result_urls on success, error on failure, and processing_ms — worth logging for latency monitoring.
Step 3: Deliver Results to Your Users
A completed job returns result_urls — an array of URLs pointing to the generated images. Resist the temptation to hotlink them.
Re-host the results in your own storage. Download each result URL and write it to your own S3, R2, or GCS bucket, then serve from your CDN. Provider result URLs should be treated as transient delivery mechanisms, not permanent infrastructure: retention policies vary, and your product's images should not break if a provider prunes old jobs or you switch vendors. The download-and-store step is five lines of code and removes an entire category of future incident.
Keep the original, always. Store the source photo and the staged photo as a linked pair. This matters for three reasons: your UI can offer a before/after slider (consistently the highest-engagement way to present staging), your users can revert, and — in US real estate contexts — regulations increasingly require that the unedited image remain available. Roomagen's job results are designed to pair original and edited images for exactly this reason.
Label staged images in listing contexts. If your users publish to MLS platforms, disclosure is no longer optional courtesy. California's AB 723 requires disclosure of AI-altered listing images as of January 1, 2026, and MLS rules across the US expect a visible "Virtually Staged" label. Roomagen exposes an optional disclosure-label parameter that renders the marking directly onto the output image, which is the lowest-effort way to keep downstream publishing compliant. The legal detail is a topic of its own — the short version for your integration is: store the staged/original distinction in your data model, and surface a label wherever a staged image can reach a listing.
Expose regeneration. Generative output has variance; sometimes the sofa is wrong. Roomagen includes 1 free regeneration per image, so a "Regenerate" button next to each result costs you nothing for the first retry and dramatically reduces support tickets. Whatever provider you use, check its regeneration policy and mirror it in your UI rather than making users pay for a coin flip.
The same delivery pipeline serves every other tool you add later — a floor plan generated from a sketch, a twilight exterior, a sky replacement, or a kitchen renovation preview all come back as result_urls through the identical webhook.
Production Concerns: Rate Limits, Retries, and Credit Budgeting
The integration above works. These four practices keep it working under load.
Retries and backoff. Treat 429 and 5xx responses to job submission as retryable with exponential backoff (1s, 2s, 4s, cap at 30s). Critically, only retry when you know the job was not created — if the submission timed out after the request was sent, check your stored records and the account's job list before resubmitting, or you will pay for duplicate generations. This is the idempotency anchor from Step 1 earning its keep.
Failure economics. Understand what failures cost before modeling your margins. On Roomagen, infrastructure failures never consume credits and failed jobs auto-refund, so a failed status is an inconvenience, not a cost. Not every provider works this way — some charge per attempt — so this belongs on your evaluation checklist alongside price per image. Your UI should distinguish "failed, no charge, try again" from "completed but not to your taste, use your free regeneration."
Credit budgeting. Credit-pack APIs reward volume commitment. Roomagen's current packs:
| Monthly volume | Pack price | Effective cost per image |
|---|---|---|
| 500 images | $125 | $0.25 |
| 2,500 images | $550 | $0.22 |
| 10,000 images | $2,000 | $0.20 |
| 50,000+ images | Custom | Negotiated |
For comparison, AI HomeDesign's API runs around $0.24 per image and Decor8 around $0.20 — the credible providers cluster in the same band, so provider choice tends to hinge on tool breadth, webhook quality, and compliance features more than a few cents of unit price. When budgeting, multiply expected volume by roughly 1.1× to cover regenerations beyond the free one and user experimentation, and remember the margin math from the buyer's side: agents routinely pay $16–$69 per image for human staging services, so a feature that costs you $0.20–$0.25 per image leaves room for healthy pricing however you package it.
An honest caveat on maturity. Roomagen's API is a 2026 entrant currently in early access behind a waitlist — you get modern ergonomics (HMAC webhooks, auto-refunds, 40+ tools on one endpoint) but not a decade of battle-tested uptime history or a large public community. If you need instant self-serve signup today, the alternatives above have been selling API access longer. The generic architecture in this tutorial is deliberately provider-portable for exactly that reason: your job table, webhook handler, and storage pipeline survive a vendor swap almost untouched.
Common Mistakes in Staging API Integrations
Seven failure modes show up repeatedly in staging integrations. All are avoidable.
1. Blocking the request thread. Holding the user's HTTP request open for 10–40 seconds of generation ties up server resources and times out on most load balancers. Submit the job, return 202 Accepted with your internal record ID, and let the client subscribe to updates via WebSocket, SSE, or simple polling of your own API.
2. Trusting webhooks alone. Your deploy window, a TLS misconfiguration, or a provider-side delivery hiccup will eventually eat a webhook. Without a polling fallback, that job hangs in "processing" forever in your UI. The dual-channel pattern from Step 2 costs almost nothing.
3. Skipping signature verification. An unverified webhook endpoint is an open write API into your application state. Verify the HMAC on the raw body with a timing-safe comparison — it is ten lines, shown above.
4. Hotlinking result URLs. Provider URLs are transient. Re-host results in your own storage on completion, every time.
5. Resubmitting without idempotency checks. Network timeouts plus naive retries equal double charges. Persist the job_id immediately on submission and gate retries on your own records.
6. Ignoring disclosure in listing markets. If staged images can reach an MLS through your product, an unlabeled image is now a legal exposure for your users in California and a policy violation on major portals. Carry the staged flag through your data model and render the label.
7. Shipping without failure UX. Around 10–40 seconds is a long time in UI terms, and a small percentage of jobs will fail. Design the processing state (progress indication, skeleton image), the failure state (clear retry, "you were not charged"), and the regeneration affordance before launch, not after the first support ticket.
The Bottom Line: Ship the Loop, Then Extend It
Adding virtual staging to an app is a genuinely small integration: one POST to create a job, one webhook handler with a polling fallback, and a storage step for results. A working prototype fits in an afternoon; the production hardening — idempotent completion, signature verification, retry discipline, disclosure labels — is another day. At $0.20–$0.25 per image on volume packs, with failed jobs refunded automatically and results delivered in 10–40 seconds, the economics work for everything from a photographer's delivery portal to a national listing platform.
The architecture is deliberately provider-neutral: async job submission, dual-channel completion handling, re-hosted results, and a staged/original pair in your data model will fit any staging API you choose now or migrate to later.
If you want to build against the worked example in this tutorial, join the Roomagen API waitlist — the free developer tier includes 50 watermarked calls per month, which covers the entire integration and test cycle in this guide without a paid commitment. From there, the same job endpoint gives you virtual staging, day-to-dusk, item removal, image enhancement, and floor plan tools behind a single integration.
Ready to transform your listings?
Try Roomagen's AI virtual staging for free. Upload your first photo and see the difference in seconds.
Start FreeSources & References
- 1.Business Research Insights – Virtual Staging Solution Market
- 2.California Legislature – AB 723 (AI-Altered Listing Images, 2025)
- 3.Stripe Documentation – Webhook Best Practices
- 4.GitHub Docs – Best Practices for Using Webhooks
- 5.IETF – RFC 2104: HMAC, Keyed-Hashing for Message Authentication
- 6.National Association of Realtors – 2025 Profile of Home Staging
- 7.Roomagen – Real Estate Image API (Early Access)
Frequently Asked Questions
Written by
Roomagen Team
The Roomagen team creates in-depth guides about AI virtual staging, real estate photography, and property marketing strategies to help agents and professionals stay ahead.





