Headless Interface API Reference
PLUS The headless interface is part of the WordPress REST API and responds under the namespace immomakler-headless/v1. The base URL is therefore
https://your-wordpress-address.com/wp-json/immomakler-headless/v1/All endpoints only respond once you have enabled the interface in the back end of your website (wp-admin) under WP-ImmoMakler → Integrations → Headless; see Headless mode with your own front end.
Authentication
Section titled “Authentication”Read endpoints are public by default. If you have enabled the option Require an API key for read requests too, every request must send the API key, either in the dedicated header or as a bearer token:
curl -H "X-ImmoMakler-Key: YOUR-API-KEY" https://your-wordpress-address.com/wp-json/immomakler-headless/v1/propertiescurl -H "Authorization: Bearer YOUR-API-KEY" https://your-wordpress-address.com/wp-json/immomakler-headless/v1/propertiesIf the key is missing or wrong, the interface responds with 401 and the error code headless_unauthorized.
Common parameters
Section titled “Common parameters”| Parameter | Meaning |
|---|---|
page, per_page | Page and page size of a list. per_page is limited to 100, and to 1000 for the overview /properties/manifest. |
fields | summary returns the short form for lists (list view data, featured image, status, address, links), full the complete property for the detail view. Lists return summary by default, the single request full. |
status | open shows the properties of the property list, reference only reference properties, all both. Lists return open by default, the single request all. |
modified_since | Only properties changed since this point in time (ISO 8601, for example 2026-10-11T08:00:00Z). |
locale | Language of the labels and category names, for example de_DE or en. On multilingual websites with WPML or Polylang, the parameter also switches the language of the properties. |
Lists respond with an envelope:
{ "items": [], "total": 42, "total_pages": 3, "page": 1, "per_page": 20, "generated_at": "2026-10-11T08:15:00+00:00"}In addition, lists carry the headers X-WP-Total, X-WP-TotalPages and a Link header with rel="next" and rel="prev".
Caching
Section titled “Caching”Read responses carry Cache-Control: public, max-age=60, s-maxage=300, stale-while-revalidate=600 and an ETag. If you send the ETag in the If-None-Match header on the next request, the interface responds with 304 Not Modified as long as the data has not changed. In the browser, the browser’s HTTP cache handles this by itself; if a front end sends If-None-Match itself, its code receives an empty response when the data is unchanged and must then use the data it loaded earlier. After every transfer from your CRM software and after every change to a property, WP-ImmoMakler discards its cache, so the next request returns the current data.
Endpoints
Section titled “Endpoints”GET /site
Section titled “GET /site”Describes the website once per build: the address of WordPress and the front end, the path patterns, the available languages (locales, and under languages the code, locale, name, default language and front-end directory prefix of each), currency, feature set (PDF, watch list, property alerts, radius search), all categories with query variable and URL path, the data fields chosen in your settings (keys.archive, keys.single, keys.single_areas, keys.single_prices, keys.epass, keys.contact), the registered image sizes and, under search, the structure of your search form: the categories shown, the ranges with slug, unit, step size and maximum value, the sort orders with labels, the default sort order, the radius search with its radii and, under search.places, the address autocomplete of the radius search if you have set up a provider for it (see below).
GET /properties
Section titled “GET /properties”The property list, most recently changed first. Supports page, per_page, fields, status, modified_since and locale.
GET /properties/manifest
Section titled “GET /properties/manifest”The compact overview of all visible properties for reconciliation when building a static front end. Each entry states objektnr_extern, post_id, slug, language, modified_gmt, public_since, is_reference, is_project, is_project_unit and frontend_url. Supports page, per_page (up to 1000), status and locale.
GET /properties/{objektnr_extern}
Section titled “GET /properties/{objektnr_extern}”One property, addressed by its object number. Pass the object number URL-encoded (A%2F1 for A/1); upper and lower case do not matter. A property that the property list does not show responds with 404 and the error code headless_not_found. Supports fields, status and locale.
GET /search
Section titled “GET /search”The property search with the filters of your website. The parameters are named as in the search of your WordPress website, so a filtered address of the property list and a search request mean the same thing:
- Categories via their query variable (
typ,vermarktungsart,nutzungsart,ort,land,ausstattung) with term slugs; the status category is calledobjektstatushere, becausestatusselects between open properties, references and all, as with/properties. Separate several terms with a comma if any one of them should match (typ=wohnung,haus), or with a plus if all must match (ausstattung=balkon+garten). For features, a list (ausstattung[]=balkon&ausstattung[]=garten) also means “all”. - Ranges via
von-{slug}andbis-{slug}, for examplevon-kaufpreis=200000&bis-kaufpreis=500000orvon-zimmer=3. Which ranges exist and how far they reach is stated insite.search.ranges. The ranges apply exactly as in the search of your website; a purchase price of 0 (on request) is not excluded, just as there. objekt-id: object number or its beginning.centerandradius(km) for the radius search (PLUS only, with radius search enabled);radiusis optional. Aortfilter is then ignored, as on the website. Underradius, the response gives the address found or the error if the place could not be determined.bounds=south,west,north,eastfor the visible map section in decimal degrees.orderwith a key fromsite.search.orders; without it, the default sort order of your website applies.facets=1adds, underfacets, the terms of the result for each category with their count, most frequent first, for counters next to the filters.- In addition
page,per_page,fields,statusandlocaleas with/properties.
Besides the properties, the response contains under applied the filters as the interface understood them, so a front end can restore its form state from them. The same visibility rules apply as for the property list.
Address suggestions for the radius search
Section titled “Address suggestions for the radius search”If a provider for address autocomplete is set up under WP-ImmoMakler > Integrations > Geo Services, site.search.places describes how a front end fetches suggestions while a visitor types in the radius search field; without a provider, places is null. The flow is the same as in the search form of your website, and the provider’s key stays on your server:
GETonplaces.token_urlreturns a token valid for 15 minutes and, underproxy_url, the address of the Fast-API proxy, which responds without WordPress;proxy_urlis empty if the proxy is switched off or the provider is not Google.- Each input is sent as a
POSTwith the JSON body{ "q": "Hambu", "session": "…", "languageCode": "de" }and the headerX-ImmoMakler-Sign: <token>toproxy_url, or alternatively toplaces.suggest_url. The response is{ "suggestions": [ { "label": "Hamburg, Germany", "placeId": "…" } ] }. - The front end passes the chosen
labelto/searchascenter.
Both endpoints are also listed in the OpenAPI document and in llms.txt, with their own namespace immomakler/v1 as the server. sessions indicates whether the provider bills per typing sequence; in that case a front end uses the same random session value for a sequence of inputs and starts a new one after a selection or a three-minute pause. min_length, max_results and debounce_ms are the values of your website. Call the endpoints from the browser, not from a server: the limits (90 requests per minute and visitor at the proxy, 600 requests per hour that are not answered from the cache) apply per visitor. The proxy accepts requests from the address of your front end and the allowed origins; it picks up a change to these settings on the next save.
GET /properties/{objektnr_extern}/similar
Section titled “GET /properties/{objektnr_extern}/similar”Similar properties, as your website shows them below a property: same property type and marketing type nearby, gradually relaxed until something matches, in random order. count limits the number (default: your setting, at most 12). Units of the same construction project are left out if your website shows them in their own table.
GET /properties/{objektnr_extern}/units
Section titled “GET /properties/{objektnr_extern}/units”The units of a construction project, as the “Other units in this project” table shows them: all units by object number, including sold and rented ones that the property list no longer carries. For a property that is not a construction project, the interface responds with 404.
GET /taxonomies
Section titled “GET /taxonomies”All categories (property type, marketing type, usage type, location, country, features, status) with their terms: term_id, slug, name, parent, count, description and source_slug, the language-independent slug of the term. With hide_empty=false, terms without properties also appear. The count includes all properties of a term, even those that the property list hides.
GET /contacts and GET /contacts/{post_id}
Section titled “GET /contacts and GET /contacts/{post_id}”The published contact persons with name, description, portrait, the contact fields from your settings and the number of their properties.
GET /content/pages and GET /content/pages/{path}
Section titled “GET /content/pages and GET /content/pages/{path}”The published pages of your website, excluding the WP-ImmoMakler template pages. For each page the list gives the hierarchical path (about-us/team), the parent page, the order, the page template, whether it is the front page and its address on the front end. The single request by path returns the page as a block structure: each block carries its name (core/paragraph, immomakler/single-data, …), its attributes, its inner HTML, its inner blocks and, under rendered, the HTML that WordPress would output for it. WP-ImmoMakler blocks have no rendered; a front end displays them from the property data. In addition there are content_html, the entire content as one HTML fragment, and seo with the title and description from Yoast SEO or Rank Math, if maintained there. Links to your WordPress website already point to the front end in both versions; images and documents stay on WordPress.
GET /content/posts and GET /content/posts/{slug}
Section titled “GET /content/posts and GET /content/posts/{slug}”The published posts, newest first, with categories, tags, excerpt and featured image; supports modified_since. The single request returns the same block structure as for pages.
GET /spam/token, POST /enquiries and POST /widerruf
Section titled “GET /spam/token, POST /enquiries and POST /widerruf”The form routes: the token for spam protection, contact enquiries and withdrawals from your own front end. They accept requests only from the allowed origins or with the API key and are never cached. The page Forms via the headless interface describes the structure of the documents, the error codes and how it works together with spam protection; site.forms lists the fields, mandatory fields and consent texts of your forms.
Webhook
Section titled “Webhook”The interface reports changes to your properties to your front end on its own; the page Webhook, links and redirect describes the structure, signature and retry of the message.
Menus and branding in /site
Section titled “Menus and branding in /site”site.menus contains the three menu locations that WP-ImmoMakler registers for your front end and that you assign in the backend of your website (wp-admin) under Appearance → Menus: primary (main navigation), footer and legal (legal notice, privacy policy). Each entry carries the title, the address stored in WordPress, the address on the front end under frontend_url, the target, CSS classes, the type of the target and its sub-entries.
site.branding delivers the design settings from the Branding and Astro starter sections of the headless settings: the design preset (preset), name and tagline of the website, logo and default thumbnail with all image sizes, primary and accent colour as hex values, the font combination (sans, serif-headlines, humanist, system) and the corner rounding (none, small, medium, large). A front end writes these values into its design tokens, so you can change the appearance in WordPress without touching the front end.
Structure of a property
Section titled “Structure of a property”The full form (fields=full) of a property, abridged:
{ "objektnr_extern": "A-1234", "openimmo_obid": "7f3c…", "post_id": 4711, "slug": "wohnung-kaufen-in-hamburg-a-1234", "language": "de", "published_gmt": "2026-09-01T10:00:00+00:00", "modified_gmt": "2026-10-10T08:15:00+00:00", "title": "3-Zimmer-Wohnung in Hamburg-Altona, 85 m²", "object_title": "Helle Stadtwohnung mit Blick aufs Wasser", "subtitle": "Hamburg-Altona · Wohnung · Kauf", "excerpt": "…", "status": { "terms": [ { "slug": "offen", "name": "offen" } ], "is_open": true, "is_reserved": false, "is_reference": false, "archived": false, "is_project": false, "is_project_unit": false, "is_hidden_project": false, "project_id": null, "public_since": "2026-09-01T10:00:00+00:00" }, "marketing": { "vermarktungsart": "kauf", "nutzungsart": "wohnen", "objektart": [ "wohnung" ] }, "taxonomies": { "immomakler_object_type": [ { "term_id": 12, "slug": "wohnung", "name": "Wohnung", "parent": 0, "source_slug": "wohnung" } ] }, "address": { "street": "Elbchaussee", "house_number": "1", "zip": "22763", "city": "Hamburg", "district": "Altona", "state": "Hamburg", "country": "DEU", "country_name": "Deutschland" }, "geo": { "lat": 53.55, "lng": 9.93, "exact": true, "radius_m": null }, "fields": { "property": [ { "key": "rooms", "source_key": "anzahl_zimmer", "label": "Zimmer", "value": "3", "text": "3 Zimmer", "raw": 3 } ], "areas": [ { "key": "living_area", "source_key": "wohnflaeche", "label": "Wohnfläche ca.", "value": "85 m²", "text": "Wohnfläche ca. 85 m²", "raw": 85 } ], "prices": [ { "key": "purchase_price", "source_key": "kaufpreis", "label": "Kaufpreis", "value": "350.000 €", "text": "Kaufpreis 350.000 €", "raw": 350000 } ], "epass": [] }, "descriptions": { "objektbeschreibung": { "label": "Beschreibung", "html": "<p>…</p>", "text": "…" } }, "media": { "featured": { "id": 99, "alt": "", "title": "Wohnzimmer", "mime": "image/jpeg", "sizes": { "immomakler-archive-thumb": { "url": "…", "width": 400, "height": 267 }, "full": { "url": "…", "width": 2000, "height": 1333 } } }, "images_count": 12, "floorplans_count": 1, "images": [], "floorplans": [], "downloads": [ { "id": 101, "title": "Exposé", "url": "…", "filename": "expose.pdf", "is_pdf": true, "is_floorplan": false } ], "links": [], "videos": [ { "type": "embed", "url": "https://www.youtube.com/watch?v=…", "embeddable": true } ], "virtual_tours": [] }, "contact": { "post_id": 7, "name": "Erika Mustermann", "slug": "erika-mustermann", "wp_url": "…", "photo": { "…": "…" }, "fields": [ { "key": "kontaktperson_fullname", "label": "Ansprechpartner", "value": "Erika Mustermann" } ] }, "seo": { "title": "…", "description": "…", "canonical": "https://ihr-frontend.de/immobilien/wohnung-kaufen-in-hamburg-a-1234/", "og_image_url": "…" }, "json_ld": [ { "@context": "https://schema.org", "@type": [ "Product" ] } ], "links": { "frontend_url": "https://ihr-frontend.de/immobilien/wohnung-kaufen-in-hamburg-a-1234/", "wp_url": "https://ihre-wordpress-adresse.de/immobilien/wohnung-kaufen-in-hamburg-a-1234/", "archive_frontend_url": "https://ihr-frontend.de/immobilien/", "og_image_url": "…/og-image/1/", "pdf_url": "…?pdf", "qr_url": "…?qrcode" }}seo contains the property’s SEO title and description, as WP-ImmoMakler generated them during the import or as the AI texts wrote them; if you have entered your own title or description for the property in Yoast SEO or Rank Math, these take precedence. Templates with placeholders such as %%title%% are left to the SEO plugin and are not taken into account here.
Each data field carries an English key that is the same on every website, and under source_key the name that WordPress and OpenImmo use. It also includes the label (label) and the display text (value) in the language of the website, both combined as a phrase (text) as in the text form of the Elementor tags, for example “3.5 rooms” or “2 parking spaces”, as well as the raw value (raw) as a number or string. If a display text contains HTML, such as a link, html additionally provides the unaltered version. The short form (fields=summary) replaces the groups property, areas, prices and epass with archive and archive_prices, that is, the fields of the list view, and omits descriptions, json_ld and the image, document and video lists.
Machine-readable description
Section titled “Machine-readable description”The interface describes itself. Both endpoints are always public, even if you require the API key for read requests, because they do not output any property data.
GET /openapi.json
Section titled “GET /openapi.json”An OpenAPI 3.1 document with all endpoints, parameters, response schemas and both authentication methods. Development tools such as Postman, Insomnia or generators for typed clients read it directly; the parameters come from the registered routes, so the document keeps pace with every extension of the interface. Under webhooks it describes the messages your website sends to the front end, with headers, signature and structure; the introduction lists the error codes and the rule for forms that a server passes on.
GET /llms.txt and GET /llms-full.txt
Section titled “GET /llms.txt and GET /llms-full.txt”A short description in text format following the llms.txt convention: the purpose of the interface, base URL, authentication, the rule to address properties by object number, the error codes, the webhook and the list of endpoints with links. The llms-full.txt variant adds the parameters and the response fields for each endpoint.
For AI website builders
Section titled “For AI website builders”AI-assisted tools that generate code from a description can work with these two files without further explanation:
- Lovable, Bolt, v0, Replit: Give the address of
llms.txtoropenapi.jsonin the prompt, for example “Build a property list with the API at https://your-wordpress-address.com/wp-json/immomakler-headless/v1/llms.txt”. Read requests work directly from the browser, because WordPress allows the REST API for all origins. - Base44: Store the address of
openapi.jsonas a custom OpenAPI integration. If you require the API key for read requests, store it there as a secret; Base44 then calls the interface from a backend function.
Generated code should always address properties by objektnr_extern and use the links from links.frontend_url; both are stated that way in llms.txt.
Error codes
Section titled “Error codes”| HTTP status | Code | Meaning |
|---|---|---|
401 | headless_unauthorized | The API key is missing or wrong although it is required for read requests. |
404 | headless_not_found | The property or contact person does not exist or is not shown publicly. |
404 | rest_no_route | The interface is not enabled. |
400 | headless_invalid_modified_since | The modified_since parameter is not a valid date. |
403 | headless_forbidden | A form route was called neither from an allowed origin nor with the API key. |
422 | headless_validation_failed | Mandatory fields are missing or invalid; data.errors lists them. |
422 | headless_unknown_property | An object number in properties does not belong to any published property. |
422 | headless_spam_rejected | The submission was rejected as spam. |
429 | headless_rate_limited | Too many requests in this hour. |
502 | headless_delivery_failed | The enquiry is saved but could not be delivered to all recipients. |
Filters for developers
Section titled “Filters for developers”immomakler_headless_frontend_urlchanges a URL that the interface outputs for the front end. Parameters: the URL, the WordPress ID of the property (0 for the property list) and the kind (propertyorarchive).immomakler_headless_propertychanges the JSON document of a property before it is output and cached. Parameters: the document, the WordPress ID and the form (summaryorfull).immomakler_headless_presetsdetermines which design presets the Astro starter section offers for selection. Parameter: an array of preset slug and label.immomakler_headless_webhook_payloadchanges the webhook message before it is signed and sent. Parameters: the message as an array and the name of the event (properties.changedorping).immomakler_contact_property_urlchanges the address of a property in the email of a contact enquiry. With the interface enabled and a front end address set, it points to the front end. Parameters: the URL and the WordPress ID of the property.