Conventions
Base address and format
https://<company host>/api/v1/. JSON, UTF-8, snake_case fields. CORS is open for reads (any origin, no credentials) and limited to the key’s origins for enquiries.
Languages
Every response carries every language. Each text, slug, website path and label is an object with one key per language:
{"title": {"en": "Harbour view apartment", "ar": "شقة بإطلالة على الميناء"}}Where a language has no text of its own, it carries the English one. A website picks title[locale] and switches language without asking again. There is no language parameter, so one cached answer serves every visitor, and Content-Language names every language.
Objects with translated fields can include translation_fallbacks, mapping a field to the language codes for which English was substituted. A strict-language website can suppress those values. A listing is found by its slug in any language; its path gives the page address in each language, for hreflang links.
Pagination
List reads take page and page_size (24 by default, at most 100; a larger size is reduced to 100). The answer has count, next and previous (full addresses, or null) and results.
Errors
Errors are RFC 9457 problem details, Content-Type: application/problem+json:
{"type": "about:blank", "title": "Not Found", "status": 404, "detail": "No published listing has this slug.", "code": "not_found"}code is stable and meant for your code; detail is for people. Invalid parameters answer 400 with errors per field. A feature the company does not have answers 404, like a page that does not exist. Unexpected errors answer a bare 500 with code: server_error and no internal detail.
Rate limits
Reads are limited per visitor address; enquiries per visitor address, and per key once the key is valid; server keys per key. Past a limit the answer is 429 with a Retry-After header in seconds.
Caching
Every read sends an ETag, and a request with If-None-Match gets 304 when nothing changed. Static site builds should cache responses between builds.
Versioning
/api/v1 never loses or changes a field; it only gains fields and endpoints. A retiring operation sends Deprecation and Sunset headers well before it goes, and the change is announced in the product’s changelog. A breaking change would ship as /api/v2 beside v1.
Dates, money and ids
- Dates are
YYYY-MM-DD; timestamps are ISO 8601 with their offset. - Money is a decimal string in the company’s currency, never a float.
- Records are addressed by a
reference(leads, contacts, bookings, leases, jobs, deals, viewings) or an id (tasks, payments, charges, contractors), as each operation says. References are stable and safe to store.