Image enhancement and virtual staging you can build into your own product, under your own brand.
Send your API key as a bearer token on every request. Keep it server-side — never in a browser, a mobile app, or a public repository.
Authorization: Bearer alp_xxxxxxxxxxxxxxxxxxxxxxxx
If a key is ever exposed, tell us and we will revoke it and issue a new one. You are responsible for usage on your key until you do.
POST https://avonyalabs.com/api/v1/stage
Send the photo as the raw request body. Options go in the query string. You get the finished image back as bytes — there is no hosted URL and nothing in the response identifies us, so you can pass it straight to your client.
| Name | Notes |
|---|---|
mode | interior (default), exterior, declutter, brighten, dusk |
style | Optional furnishing style for interior, e.g. modern, farmhouse |
instructions | Optional free text, up to 400 characters |
reference | Optional. Your own job id — returned in the X-Reference header so you can match it up |
# JPEG or PNG, up to 12 MB
curl -X POST \
"https://avonyalabs.com/api/v1/stage?mode=interior&style=modern&reference=job-8842" \
-H "Authorization: Bearer $AVONYALABS_KEY" \
-H "Content-Type: image/jpeg" \
--data-binary @living-room.jpg \
--output living-room-staged.jpg
On success: 200 with the image bytes. Useful headers:
| Header | Meaning |
|---|---|
X-Job-Id | Our id for this image — quote it if you ever query a charge |
X-Charge-Cents | What this image cost, in cents |
X-Images-This-Month | Your running count for the current month |
X-Reference | Whatever you passed as reference |
On failure: a JSON body with ok: false and an error string. Failed images are never charged, so you can retry safely.
import { readFile, writeFile } from 'node:fs/promises';
const photo = await readFile('living-room.jpg');
const res = await fetch(
'https://avonyalabs.com/api/v1/stage?mode=interior&style=modern',
{ method: 'POST',
headers: { Authorization: `Bearer ${process.env.AVONYALABS_KEY}`,
'Content-Type': 'image/jpeg' },
body: photo });
if (!res.ok) throw new Error((await res.json()).error);
await writeFile('staged.jpg', Buffer.from(await res.arrayBuffer()));
console.log('job', res.headers.get('X-Job-Id'));
GET https://avonyalabs.com/api/v1/usage
{
"ok": true,
"month": "2026-08",
"images": 214,
"ratePerImage": "3.00",
"amountDue": "642.00",
"currency": "usd"
}
The engine is built not to alter the structure of a property. It will not add, remove or move walls, windows, doors, rooflines or permanent fixtures, and it will not paint over a defect. Every result is checked against the original, and one that fails that check is rejected rather than returned.
That is a deliberate limit. It is also your protection: an image that changes the property itself is the kind that ends in a complaint.
| Image size | 12 MB maximum, JPEG or PNG |
| Daily volume | 500 images per day by default — ask if you need more |
| Billing | Charged to your card per finished image, at the moment it is delivered. Failed images are not charged |
| Status | What it means |
|---|---|
401 | Missing or invalid key |
403 | Agreement not accepted, or the account is suspended |
413 | Image over 12 MB |
415 | Body was not image/jpeg or image/png |
429 | Daily limit reached |
502 | The engine could not process it. Not charged — retry |
Email [email protected]. Include your X-Job-Id for anything to do with a specific image.