From Property to Listing
Five steps that can be fully automated - from an empty record to a published document.
Five steps that can be fully automated - from an empty record to a published document.
A listing never comes out of nowhere - it always references a property. Create it first via Property Management.
curl -X POST https://api.realestateagency.example/v1/properties \
-H "apikey: $REAL_ESTATE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "apartment",
"title": "3-Bedroom Period Home near Riverside Park",
"address": { "street": "148 Elm Street", "postal_code": "10001", "city": "Springfield" },
"living_area_sqm": 86.5,
"rooms": 3,
"year_built": 1908,
"purchase_price_eur": 645000,
"commission": { "buyer_percent": 3.57, "note": "includes applicable sales tax" },
"energy_certificate": {
"type": "consumption",
"final_energy_demand_kwh": 118.4,
"energy_source": "district_heating",
"efficiency_class": "D",
"valid_until": "2031-04-30"
}
}'
The energy_certificate block is optional when creating a property, but mandatory for later publication. See Mandatory Disclosures.
Photos and floor plans are attached to the property, not to a listing. That way they're available to every listing and template generated later.
curl -X POST https://api.realestateagency.example/v1/properties/prop_8f2c1a/media \
-H "apikey: $REAL_ESTATE_API_KEY" \
-F "file=@living-room.jpg" \
-F "category=interior" \
-F "order=1"
At least one cover photo (category=cover_photo) and one floor plan (category=floor_plan) are recommended. If the cover photo is missing, the template falls back to a neutral placeholder graphic.
Want to see the flow without code first? The Listing Generator accepts the same property data through a form and produces a finished listing text via a language model - the call runs through the Kong AI Gateway.
curl -X POST https://api.realestateagency.example/v1/listings \
-H "apikey: $REAL_ESTATE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"property_id": "prop_8f2c1a",
"template_id": "tpl_classic",
"sections": ["location", "features", "energy", "floor_plan", "commission"]
}'
{
"id": "lst_4d9b2e",
"property_id": "prop_8f2c1a",
"template_id": "tpl_classic",
"status": "in_progress",
"created_at": "2026-08-20T09:41:12Z"
}
Generation is asynchronous because images need to be resized and the PDF laid out. Usually takes two to ten seconds.
Two paths lead to the finished document:
Event-driven (recommended). Subscribe to listing.completed; the webhook carries the listing ID and the download link. See Webhooks.
Polling. Poll GET /listings/{id} with increasing backoff (1s, 2s, 4s, 8s) until status reaches completed:
curl https://api.realestateagency.example/v1/listings/lst_4d9b2e/pdf \
-H "apikey: $REAL_ESTATE_API_KEY" \
-o listing-elm-street.pdf
The link in pdf_url is valid for 24 hours. Store the document instead of passing the link around.
curl -X POST https://api.realestateagency.example/v1/listings/lst_4d9b2e/publish \
-H "apikey: $REAL_ESTATE_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "channels": ["portal", "website", "newsletter"] }'
Before publishing, the API checks the mandatory disclosures. If something's missing, you get 422:
{
"code": "mandatory_disclosure_missing",
"message": "Mandatory disclosures from the energy certificate are missing for publication.",
"details": [
{ "field": "energy_certificate.final_energy_demand_kwh", "reason": "missing" }
]
}
Add the missing figure on the property, regenerate the listing, and publish again. A listing that's already been generated is never changed after the fact - that keeps the history traceable.
property_id is required; standalone listings deliberately don't exist.template_id must belong to your tenant, otherwise 404.status: "completed", /pdf returns 409.