Integrate AI-powered real estate image enhancement and virtual staging into your application.
Sign up for an account, then create an API key in your dashboard Settings. Or create one via the API:
curl -X POST https://www.zestio.de/api/keys \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ***" \
-d '{"name": "My App"}'
# Response: { "secret": "zest_a1b2c3d4..." }curl -X POST https://www.zestio.de/api/enhance \
-H "Authorization: Bearer ***" \
-H "Content-Type: application/json" \
-d '{
"image": "https://example.com/property.jpg",
"enhancementType": "sky",
"model": "auto"
}'All API requests require an API key passed as a Bearer token:
Authorization: Bearer zest_x...Create API keys in your dashboard Settings after signing up. Each key is prefixed zest_ and the full secret is only shown once.
/api/keysList all your API keys (secrets are never returned)
{
"keys": [
{ "id": "uuid", "name": "My App", "key_prefix": "zest_a1b",
"last_used_at": "...", "created_at": "...", "is_active": true }
]
}/api/keysCreate a new API key. The secret is only returned once.
| Name | Type | Required | Description |
|---|---|---|---|
| name | string | No | Label for the key (default: "Default Key") |
{
"key": { "id": "uuid", "name": "My App", "key_prefix": "zest_a1b" },
"secret": "zest_a1b2c3d4e5f6...",
"warning": "Store this key securely. It cannot be retrieved again."
}/api/keysRevoke an API key
| Name | Type | Required | Description |
|---|---|---|---|
| key_id | string | Yes | The key ID to revoke |
{ "success": true }Enhance, transform, and clean up property photos.
/api/enhanceEnhance a property image using AI. Supports sky replacement, season changes, decluttering, and more.
| Name | Type | Required | Description |
|---|---|---|---|
| image | string | Yes | Image URL or base64 data URL |
| enhancementType | string | No | Type of enhancement (see table). Default: "auto" |
| model | string | No | Model: "auto" (only option — diffusion models removed) |
| customPrompt | string | No | Custom prompt (overrides enhancementType) |
{
"success": true,
"output": "https://replicate.delivery/...",
"creditsUsed": 1,
"model": "auto"
}| Type | Name | Description |
|---|---|---|
| auto | Auto Enhance | General enhancement |
| sky | Blue Sky | Clear sunny sky |
| sky_sunset | Golden Sunset | Warm golden hour |
| sky_dramatic | Dramatic Clouds | Moody cinematic sky |
| twilight | Virtual Twilight | Blue hour with warm glow |
| season_summer | Summer | Lush green landscape |
| season_autumn | Autumn | Golden fall foliage |
| season_winter | Winter | Pristine snow scene |
| curb_appeal | Curb Appeal | Green lawn & landscaping |
| facade_refresh | Facade Refresh | Clean painted exterior |
| object_removal | Object Removal | Remove unwanted items |
| declutter | Declutter | Remove personal items |
Stage empty rooms with AI-generated furniture — or redesign furnished rooms.
/api/stagingApply virtual staging to a room photo (empty or furnished).
| Name | Type | Required | Description |
|---|---|---|---|
| image | string | Yes | Image URL or base64 of the empty room |
| model | string | No | "interior-design" (default, fast), "precision" (mask-based, structure-preserving) |
| roomType | string | No | living, bedroom, kitchen, dining, bathroom, office, basement, patio |
| furnitureStyle | string | No | modern, scandinavian, luxury, minimalist, industrial, bohemian, midcentury, farmhouse |
{
"success": true,
"output": "https://replicate.delivery/...",
"model": "interior-design",
"creditsUsed": 2,
"creditsRemaining": 48
}| Model | Credits | Description |
|---|---|---|
| interior-design | 2 | Best value, ControlNet-based — synchronous; empty and furnished rooms |
| precision | 2 | Structure-preserving: room layout, floor, windows and doors stay exactly as they are; walls/ceiling may be redesigned (paint, panels, lamp) — empty rooms get furnished, furniture is replaced (asynchronous) |
Precision redesigns the room — empty or furnished — in two zones: the fix zone (windows, doors, curtains, outdoor areas such as balcony/terrace) is taken 1:1 from the original; the edit zone (furniture, decor, walls, ceiling) may be redesigned — walls can be painted or fitted with wall panels, the ceiling can get a lamp. The floor is part of the mask (so furniture is drawn completely) and is then restored 1:1 from the original (floor restore) — the visible floor is always exactly the original, including shadows & furniture feet lying on top. Light switches/sockets are protected by a fixed prompt instruction (no ADE20K class → no mask protection). Processing runs asynchronously:
POST /api/staging with model: "precision" → the response contains a jobIdGET /api/staging/poll?jobId=<id> until status: "completed" (typical duration ~1–2.5 min)# 1) Job starten
curl -X POST https://www.zestio.de/api/staging \
-H "Authorization: Bearer ***" -H "Content-Type: application/json" \
-d '{"image":"https://example.com/room.jpg","model":"precision","roomType":"living","furnitureStyle":"modern"}'
# → { "status": "processing", "stage": "mask", "jobId": "uuid", "maskPredictionId": "..." }
# 2) Fortschritt abfragen (alle ~5 s)
curl "https://www.zestio.de/api/staging/poll?jobId=uuid" -H "Authorization: Bearer ***"
# → { "status": "completed", "output": "https://...result.jpg", "stats": { "maskCoverage": 0.75, "structureCoverage": 0.35, "floorCoverage": 0.92 } }
# Fehler: { "status": "failed", "error": "..." } — Rate-Limits (429) werden automatisch retried,
# Außenaufnahmen ohne Innen-Struktur brechen mit klarer Meldung ab ("Kein Innenraum erkannt")Progress: mask → inpaint → floor → completed. The job metadata carries the zone analysis (maskCoverage = edit zone/furnishable area, structureCoverage = detected interior structure (guard basis, exterior shots), protectedLabels = detected fix-zone classes, floorCoverage = share of the floor restored 1:1, floorPreserved = floor restore active) and the pixel difference outside the mask — your proof that windows & outdoor areas were left untouched. Jobs stuck without progress for more than 10 minutes are marked as failed automatically.
All AI-generated or AI-modified images (staging, sky replacement, object removal, videos, floor plans) carry a permanently burned-in official EU AI symbol (Art. 50(3) EU AI Act) with a label such as „Mit KI-Unterstützung (KI-modifiziert)". The symbol is part of the image itself (bottom right) — it cannot be removed or covered by a UI overlay. This keeps AI content clearly identifiable even after download or forwarding.
Also machine-readable in the XMP metadata: IPTC DigitalSourceType: trainedAlgorithmicMedia as well as comZestio:MarkingLabel / comZestio:MarkingVersion (namespace http://zestio.de/ns/ai-marking/1.0/). Assistive standard edits (brightness, colour correction, upscaling) count as the Art. 50(2) exception and are not labelled.
| Status | Meaning |
|---|---|
| 400 | Missing or invalid parameters |
| 401 | Missing or invalid authentication |
| 402 | Insufficient credits (0 Credits — top up at /billing) |
| 429 | Rate limit exceeded |
| 500 | Server error or AI model failure |
Limits apply per API key/user per hour and are tiered by plan. Remaining requests are returned in the X-RateLimit-Remaining / X-RateLimit-Reset headers.
| Plan | Limit | Endpoints |
|---|---|---|
| Public (no login) | 10/h | enhance, staging |
| Standard (signed in) | 100/h | enhance, staging, keys, MCP |
| Pro / Enterprise | 500/h | all |
| Video (expensive calls) | 20/h | generate_video |
| Webhooks | 1.000/h | MCP, Feed |
On 429 the API replies with Retry-After. Asynchronous jobs (Precision) retry rate-limit overruns automatically. Credits are deducted before execution; if the AI call fails (5xx, model error) they are refunded automatically — no double charge on retries.
Sign up for a free account and get API access with 10 free credits.
The Zestio MCP server gives AI assistants (Claude, Cursor, Windsurf) direct access to your property data and Zestio features — without code. Over the standardised JSON-RPC 2.0 MCP protocol, AI agents can search listings, fetch CRM data, run market analyses and edit images.
/api/mcpJSON-RPC 2.0 MCP server. All 34 tools behind a single endpoint.
| Name | Type | Required | Description |
|---|---|---|---|
| Authorization | header | Yes | Bearer zest_YOUR_API_KEY |
// tools/list response
{ "tools": [ { "name": "search_listings", ... }, ... ] }Handshake: server info + capabilities
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{}}}Lists all 34 tools with schema
{"jsonrpc":"2.0","id":2,"method":"tools/list"}Runs a tool
{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"search_listings","arguments":{"location":"Berlin","maxPrice":500000}}}| Category | Tool | Description | Credits | Admin |
|---|---|---|---|---|
| Listings & portals | search_listings | Search properties (price, type, location, status) | — | — |
| create_listing | Create a new property listing | — | — | |
| update_listing | Change an existing listing (price, description, location, …) | — | — | |
| publish_to_portal | Publish a listing to a portal | 1 | — | |
| CRM | create_contact | Create a new contact/lead | — | — |
| search_leads | Search leads/contacts | — | — | |
| get_pipeline | Fetch the deal pipeline with all stages | — | — | |
| create_deal | Create a new deal in the CRM | — | — | |
| get_deals | Fetch all deals with a filter | — | Admin | |
| get_deal | Fetch a single deal by ID | — | Admin | |
| get_milestones | Upcoming milestones | — | Admin | |
| update_deal_progress | Update deal progress (0–100) | — | Admin | |
| get_follow_ups | Fetch due follow-ups | — | Admin | |
| create_followup | Create a new follow-up | — | Admin | |
| log_activity | Log a CRM activity | — | Admin | |
| get_property | Fetch property details | — | Admin | |
| 3D tours | get_tours | Fetch 3D tours with share URLs | — | — |
| create_tour | Create a new 3D tour from photos | 5 | — | |
| Property file | list_property_documents | List the documents of a property (private, no URLs) | — | — |
| list_property_notes | Read the internal notes of a property | — | — | |
| create_property_note | Create an internal note on a property | — | — | |
| Market analysis | get_price_prediction | AI price forecast for properties | — | — |
| get_market_trends | Historical price trends for a location | — | — | |
| market_analysis | Full market analysis (IS24 + postcode) | — | — | |
| AI image editing | enhance_image | Improve a photo (sky, season, etc.) | 1 | — |
| virtual_staging | Furnish rooms virtually — empty or furnished, structure preserved (precision) | 2 | — | |
| renovate_room | AI renovation preview | 2 | — | |
| cleanup_image | Remove objects, declutter | 1 | — | |
| generate_video | Property video from images | 15 | — | |
| Feed syndication | check_feed_token | Check feed token status | — | — |
| generate_feed_token | Generate an OpenImmo feed token | — | — | |
| ensure_feed_token | Ensure a feed token (creates one if needed) | — | — | |
| show_feed_url | Show the feed URL for portals | — | — | |
| Agent & briefing | compile_brief | Daily agent briefing | — | — |
| summarize_deal | Summarise a single deal | — | — | |
| summarize_pipeline | Pipeline overview | — | — | |
| Client (email) | send_drip_email | Send a drip email to a lead | — | Admin |
Zestio's orchestrator delegates complex requests to modular agent modules — encapsulated components with their own context (supabase, user, previousResults). The MCP tools above are the public interface; the modules behind them deliver the data & actions. Modules are loaded lazily (imported only when needed).
| Module | Actions | Purpose |
|---|---|---|
| agent | compile_brief, summarize_deal, summarize_pipeline, respond, analyze_market, estimate_value | Orchestrator: compile briefings, summarise data, market/value analyses |
| crm | fetch_pipeline, fetch_contact, fetch_property, fetch_follow_ups, create_followup, log_activity | CRM data: pipeline, contacts, follow-ups, activities |
| deals | fetch_active_deals, fetch_deal, fetch_milestones | Deal pipeline: active deals, details, milestones |
| calls | fetch_scheduled_calls, trigger_call | Telephony — currently stubs (requires Retell/Twilio API keys) |
Call path: tools/call → orchestrator → module registry (moduleRegistry[modul][aktion]) → ModuleResult.
“Change the price of listing X to 420.000 €”finds the listing, updates price“Show me my current deal pipeline”get_pipeline + summarize_pipeline“Publish listing Y on ImmobilienScout24”publish_to_portal (the client asks before running)“Create a market analysis for Berlin-Mitte”market_analysis with the locationThe AI client handles orchestration: it finds the listing ID itself (via search_listings), calls the matching tools in sequence and asks when details are missing.
Requires the mcp-remote proxy for HTTP→stdio
{
"mcpServers": {
"zestio": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://www.zestio.de/api/mcp"],
"env": { "MCP_REMOTE_API_KEY": "zest_YOUR_KEY" }
}
}
}curl -X POST https://www.zestio.de/api/mcp \
-H "Authorization: Bearer zest_KEY" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'| Code | Meaning |
|---|---|
| -32601 | Tool/method not found |
| -32602 | Invalid parameters |
| -32603 | Internal server error |
| -32001 | Admin-restricted — tool available to admins only |