Get property by UUID
Retrieve a single property by its public UUID from Elasticsearch.
curl -X GET "https://api-v2.stream.estate/properties/string"{
"uuid": "6e6ab049-7e39-4fbe-828b-d4b10a3ced66",
"listings": [
{
"uuid": "6e6ab049-7e39-4fbe-828b-d4b10a3ced66",
"title": "Beautiful apartment in Paris center",
"description": "string",
"url": "https://example.com/listings/123",
"price": 350000,
"currency": "EUR",
"transactionType": "SELL",
"propertyType": "APARTMENT",
"dataProvider": "seloger",
"area": 72.5,
"rooms": 3,
"bedrooms": 2,
"hasParking": true,
"hasBalcony": true,
"hasGarden": true,
"hasCellar": true,
"cityId": 42,
"cityName": "Paris",
"districtId": 7,
"districtName": "7ème arrondissement",
"neighborhoodId": 15,
"neighborhoodName": "Eiffel",
"createdAt": "2025-01-15T10:30:00+00:00",
"updatedAt": "2025-01-15T10:30:00+00:00"
}
],
"minPrice": 250000,
"maxPrice": 350000,
"createdAt": "2025-01-15T10:30:00+00:00",
"updatedAt": "2025-01-15T10:30:00+00:00"
}{
"title": "string",
"detail": "string",
"status": 404,
"instance": "string",
"type": "string"
}{
"title": "string",
"detail": "string",
"status": 404,
"instance": "string",
"type": "string"
}Search properties POST
Search properties by combining a **search mode** (how filters are expressed) with a **pagination mode** (how pages are navigated). Both choices are made in the request body — no extra endpoints or query parameters needed. --- ## Search Modes Use the `searchMode` field as the discriminator. ### `classic` (default) Flat key-value filters at the root level, all combined with an implicit AND. Best for simple, well-known filter sets (the majority of use cases). ```json { "searchMode": "classic", "paginationType": "page", "page": 1, "size": 10, "transactionType": "SELL", "propertyTypes": ["FLAT", "HOUSE"], "cityIds": [1001, 1002], "price": { "gte": 100000, "lte": 500000 }, "area": { "gte": 50 }, "rooms": { "gte": 2 }, "bedrooms": { "gte": 1 } } ``` ### `advanced` A recursive `criteria` tree allowing arbitrarily nested AND / OR logic. Use this when you need complex boolean queries (e.g. "flats in Paris OR houses in Lyon with price under 300k"). **Simple leaf** (equivalent to a classic request): ```json { "searchMode": "advanced", "paginationType": "page", "page": 1, "size": 10, "criteria": { "transactionType": { "value": "SELL" }, "price": { "min": 100000, "max": 500000 }, "location": { "included": [{ "cityId": 1001 }, { "cityId": 1002 }] } } } ``` **Nested OR branch** (flats under 200k OR houses with 4+ rooms): ```json { "searchMode": "advanced", "paginationType": "page", "page": 1, "size": 10, "criteria": { "operator": "OR", "branches": [ { "propertyType": { "included": ["FLAT"] }, "price": { "max": 200000 } }, { "propertyType": { "included": ["HOUSE"] }, "rooms": { "min": 4 } } ] } } ``` --- ## Pagination Modes Use the `paginationType` field as the discriminator. ### `page` (default) Offset-based pagination. Use `page` (1-indexed) and `size`. `totalItems` is accurate up to 10,000, then capped. Supports both next and previous navigation. **First page:** ```json { "searchMode": "classic", "paginationType": "page", "page": 1, "size": 20, "transactionType": "RENT" } ``` **Navigate using `meta.pagination.nextRequestBody` from the response (page 2):** ```json { "searchMode": "classic", "paginationType": "page", "page": 2, "size": 20, "transactionType": "RENT" } ``` ### `cursor` Stable cursor-based pagination. Pass the opaque `cursor` value from the previous response. `totalItems` reflects the true count (no cap). Forward-only — no `prevRequestBody`. **Web users** are capped at 100 visible results; Partner API users have no limit. **First page:** ```json { "searchMode": "classic", "paginationType": "cursor", "size": 20, "transactionType": "SELL" } ``` **Next page — copy `meta.pagination.nextRequestBody` from the response:** ```json { "searchMode": "classic", "paginationType": "cursor", "size": 20, "transactionType": "SELL", "cursor": "<opaque cursor from previous response>" } ``` --- ## Response Structure ```json { "data": [ { "id": "/properties/018e1f9a-…", "type": "PropertySearch", "attributes": { "uuid": "018e1f9a-…", "listings": [ { "title": "Beautiful flat", "price": 250000, … } ], "minPrice": 250000, "maxPrice": 250000, "createdAt": "2025-01-01T00:00:00+00:00", "updatedAt": "2025-06-15T12:00:00+00:00" } } ], "meta": { "totalItems": 1843, "hasNextPage": true, "cursor": "eyJzb3J0IjpbMTczNjk1MjYwMDAwMCwxMjM0NV19", "pagination": { "type": "cursor", "size": 20, "nextRequestBody": { "paginationType": "cursor", "size": 20, "cursor": "eyJzb3J0IjpbMTczNjk1MjYwMDAwMCwxMjM0NV19" }, "prevRequestBody": null, "supportsPreviousPage": false, "usage": "Send a new POST /properties request using meta.pagination.nextRequestBody." } }, "links": { "self": "/properties" } } ``` > `cursor` only appears in `meta` when `paginationType` is `cursor` and `hasNextPage` is `true`. > `links.self` identifies the endpoint — pagination is request-body driven, not URL-driven. --- ## Pagination Mode Comparison | Feature | `page` | `cursor` | |---|---|---| | Parameters | `page`, `size` | `size`, `cursor` | | `totalItems` | Capped at 10,000 | True count | | Max depth | 10,000 results | Unlimited | | SAAS_USER cap | — | 100 results | | Prev-page support | ✅ | ❌ | | Default | ✅ (when `paginationType` omitted) | — | --- ## Role Restrictions | Role | Classic | Advanced | Page | Cursor | |---|---|---|---|---| | `ROLE_API_CLIENT` | ✅ Full access | ✅ Full access | ✅ Unlimited | ✅ Unlimited | | `ROLE_SAAS_USER` | ✅ Full access | ✅ Full access | ✅ Unlimited | ⚠️ Max 100 results |
List source categories GET
List source categories