# EAS CMS — Front-end API Contract

You are building a public real-estate website against this headless CMS.
Everything below is public (no auth). Base URL: `https://easnode.wini.app`

**Front-end scope note:** the CMS covers data + admin only. Design, routing,
SEO markup, i18n and all visual decisions are YOUR responsibility. Build
whatever the client's brand needs — the API is stable, the rest is open.

## Endpoints

| Method | Path | Purpose |
|---|---|---|
| GET | /api/v1/config | Site name, branding, languages, theme hints |
| GET | /api/v1/properties | Paginated listing w/ filters (see below) |
| GET | /api/v1/properties/{slug} | Full property detail (also accepts EA UID) |
| GET | /api/v1/properties/{slug}/similar | Up to 6 related properties |
| GET | /api/v1/filters | Filter options: cities, types, price range |
| GET | /api/v1/filters?city={id} | + neighborhoods of that city |
| GET | /api/v1/nomenclatures | All lookup groups (grouped object) |
| GET | /api/v1/nomenclatures/{group} | One group (e.g. estate_type, city, neighborhood) |
| GET | /api/v1/brokers | Agent list |
| GET | /api/v1/brokers/{id} | Single agent |
| GET | /api/img?u={encoded-url} | HTTPS image proxy (EA images are http://) |

## Filtering /api/v1/properties

Query params (all optional):

- `offer_type` — 1 = sale (продажба), 2 = rent (наем)
- `city` — **nomenclature ID** (from /api/v1/filters cities[].value)
- `neighborhood` — comma-separated **nomenclature IDs**
- `property_type` — comma-separated nomenclature IDs (group estate_type)
- `price_min` / `price_max` — EUR numbers
- `area_min` / `area_max` — m² numbers
- `bedrooms` — minimum count
- `keyword` — free text (title, city, neighborhood, address, description)
- `sort` — newest | price_asc | price_desc | area_asc | area_desc
- `page` — 1-based; 24 items per page

**Important: locations are ID-based.** Cities and neighborhoods form a
hierarchy (neighborhood.parent_id → city). Always filter by the IDs from
/api/v1/filters — never by string labels. Keep IDs in your URLs
(e.g. /imoti?city=236&neighborhood=1667) so views are shareable.

## Response envelopes

Listing:
```json
{ "data": [Property], "meta": { "total": 142, "per_page": 24, "current_page": 1, "last_page": 6 },
  "links": { "first": "…", "last": "…", "prev": null, "next": "…" } }
```

Detail: `{ "data": Property }` — detail adds description, description_bg/en,
address, images[], features[], extras (raw JSONB).

## Property object (list shape)

```json
{
  "id": 1, "ea_estate_id": "uuid", "code": "5382", "slug": "partsel-plovdiv-5382",
  "title": "…BG title…", "title_bg": "…", "title_en": null,
  "offer_type": 1, "offer_type_label": "Продажба",
  "property_type": { "id": 11, "label": "Къща", "label_bg": "Къща" },
  "status": "active", "price": 65814, "price_per_sqm": null, "currency": "EUR",
  "area_sqm": 3134, "rooms": null, "bedrooms": null, "bathrooms": null,
  "floor": null, "total_floors": null, "year_built": null, "construction": null,
  "is_new_construction": false,
  "state_of_property": null, "stage_of_construction": null,
  "city": "Пловдив", "neighborhood": "Прослав",
  "latitude": 42.14, "longitude": 24.71,
  "main_image": { "url": "http://img001.estateassistant.bg/…" },
  "broker": { "name": "…", "phone": "…", "photo": "…" },
  "top": false, "synced_at": "…", "created_at": "…"
}
```

## Images

EA serves images over plain http:// which browsers block on https pages.
ALWAYS wrap image URLs: `/api/img?u=${encodeURIComponent(url)}`.
Responses are cache-control: immutable (1 year).

## Statuses

- `active` — live listing (default filter)
- `sold` — kept for social proof when the site opts into it; show a
  ПРОДАДЕН/ОТДАДЕН badge and consider hiding price + disabling inquiry.

## Conventions the demo front-end uses (copy freely)

- Currency display: `65 814 €` (bg-BG locale) · missing price → "Цена при запитване"
- Offer labels: 1 → Продажба, 2 → Наем
- Slugs are transliterated Cyrillic→Latin with the property code suffix
- Detail page fallback: /api/v1/properties/{slug} also resolves EA UIDs

## Real-time (optional)

A WebSocket at `wss://easnode.wini.app/ws` broadcasts admin sync progress.
Public front-ends normally don't need it.
