Project add-ons

A project's public page is assembled from four add-ons. Each one is independent, each is off until you turn it on, and each is fully manageable over the API — so a project can be set up end to end without anyone opening the dashboard.

Add-onWhat it rendersBase path
InvestmentRich-text sections with attached files/estates/{estateId}/investment
GalleryImages and video, optionally grouped into sections/estates/{estateId}/gallery
MapA location map with categorised points of interest/estates/{estateId}/map
DownloadsDocuments grouped into named folders/estates/{estateId}/downloads
Note

Add-on paths use the plural /estates/{estateId}/…, while the project resource itself is at /estate/{id}. That is a quirk of the routing, not a typo.

Every write below accepts an organization API key. A key may only touch projects in the organization it was issued for — anything else returns 404. Reads (GET) on all four add-ons are public, because that is what the published viewer calls.

For the rest of this page:

export YNH_API_KEY="ynh_live_xxxxxxxxxxxxxxxxxxxx"
export ESTATE_ID="df41fc85-..."
export API="https://api.yournexthome.app/api/v1"

The shape of every add-on

All four follow the same three moves, so once you have automated one the others read the same way:

  1. Enable it. PUT the base path with { "enabled": true }. This creates the add-on record on first call and updates it after that, so it is safe to repeat.
  2. Add content. POST children (sections, items, groups, points of interest); PATCH to edit one; DELETE to remove one.
  3. Order it. PUT …/order with orderedIds — the complete list of ids in the order you want. Partial lists are rejected.

Reordering is deliberately all-or-nothing: sending every id makes the result independent of what the list looked like before, which is what you want from a job that may run twice.

Investment

Rich-text sections, each of which can carry files.

Turn it on:

curl -X PUT $API/estates/$ESTATE_ID/investment \
  -H "Authorization: Bearer $YNH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "enabled": true }'

Add a section. description is HTML (the dashboard writes it with a rich-text editor); it is sanitised server-side. Omit order and the section is appended.

curl -X POST $API/estates/$ESTATE_ID/investment/sections \
  -H "Authorization: Bearer $YNH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Project overview",
    "description": "<p>Ten floors, 84 apartments, completion Q4 2027.</p>"
  }'

The response carries the new id. Edit with PATCH (send only the fields you are changing) and remove with DELETE:

curl -X PATCH $API/estates/$ESTATE_ID/investment/sections/$SECTION_ID \
  -H "Authorization: Bearer $YNH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "title": "Overview" }'

curl -X DELETE $API/estates/$ESTATE_ID/investment/sections/$SECTION_ID \
  -H "Authorization: Bearer $YNH_API_KEY"

Reorder the whole set:

curl -X PUT $API/estates/$ESTATE_ID/investment/sections/order \
  -H "Authorization: Bearer $YNH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "orderedIds": ["<second-id>", "<first-id>"] }'

Files on a section

First create an asset (see Assets & images), then attach its id:

curl -X POST $API/estates/$ESTATE_ID/investment/sections/$SECTION_ID/files \
  -H "Authorization: Bearer $YNH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "assetId": "9f1c2d3e-...", "label": "Sales brochure" }'

PATCH …/files/{fileId} changes the label or order, DELETE …/files/{fileId} detaches it, and PUT …/files/order reorders the section's files. Documents, images, video, archives and CAD files are accepted, up to 50 MB each.

Images and video, either loose or grouped into sections.

curl -X PUT $API/estates/$ESTATE_ID/gallery \
  -H "Authorization: Bearer $YNH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "enabled": true }'

Sections are optional — an item with no sectionId renders ungrouped.

curl -X POST $API/estates/$ESTATE_ID/gallery/sections \
  -H "Authorization: Bearer $YNH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "title": "Exteriors", "description": "Renders of the north elevation" }'

curl -X POST $API/estates/$ESTATE_ID/gallery/items \
  -H "Authorization: Bearer $YNH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "assetId": "9f1c2d3e-...",
    "caption": "North facade",
    "sectionId": "<section-id>"
  }'

The gallery only accepts image and video assets; a PDF is rejected with 400. An asset from another organization is rejected with 404.

Three order endpoints, because there are three orderable levels:

EndpointOrders
PUT …/gallery/items/orderUngrouped items
PUT …/gallery/sections/orderThe sections themselves
PUT …/gallery/sections/{sectionId}/items/orderItems inside one section

Map

One configuration object plus a flat list of points of interest.

curl -X PUT $API/estates/$ESTATE_ID/map \
  -H "Authorization: Bearer $YNH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "enabled": true,
    "centerLat": 52.2297,
    "centerLng": 21.0122,
    "defaultZoom": 14,
    "tileStyle": "VOYAGER"
  }'

tileStyle is one of VOYAGER, VOYAGER_NOLABELS, POSITRON, GRAY_CANVAS, DARK_MATTER, OSM, SATELLITE, HUMANITARIAN. defaultViewLat / defaultViewLng set the opening viewport when it should differ from the project pin, and logoAssetId overlays your logo.

Points of interest:

curl -X POST $API/estates/$ESTATE_ID/map/pois \
  -H "Authorization: Bearer $YNH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "category": "TRANSIT",
    "label": "Centrum station",
    "lat": 52.2317,
    "lng": 21.0059,
    "customDistanceLabel": "5 min walk"
  }'

category is one of TRANSIT, SHOPPING, EDUCATION, HEALTHCARE, FOOD, PARKS, ENTERTAINMENT, SERVICES, LANDMARK, OTHER. Distance from the project is computed for you; set customDistanceLabel only to override the wording.

DELETE /estates/{estateId}/map removes the whole configuration, points of interest included.

Downloads

Documents in named groups. Every item belongs to a group, so create the group first.

curl -X PUT $API/estates/$ESTATE_ID/downloads \
  -H "Authorization: Bearer $YNH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "enabled": true }'

curl -X POST $API/estates/$ESTATE_ID/downloads/groups \
  -H "Authorization: Bearer $YNH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "title": "Brochures" }'

curl -X POST $API/estates/$ESTATE_ID/downloads/groups/$GROUP_ID/items \
  -H "Authorization: Bearer $YNH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "assetId": "9f1c2d3e-...", "label": "Sales brochure" }'

Groups reorder with PUT …/downloads/groups/order, items within a group with PUT …/downloads/groups/{groupId}/items/order.

Setting up a project end to end

The full sequence for a new project, all of it over the API:

  1. POST /estate — create the project.
  2. POST /building, POST /apartment — add inventory.
  3. POST /asset/upload — upload renders, brochures, floor plans.
  4. PUT /estates/{id}/investment|gallery|map|downloads — enable the add-ons you want and fill them from the assets above.
  5. Publish the project from the dashboard, or connect a custom domain.

Read the assembled result back at any time with the public GET on each add-on — the same call the viewer makes.

Errors

StatusMeans
401Missing or invalid key.
403The key is valid but the endpoint is not on the partner surface.
404The project or a referenced asset is not in your organization, or orderedIds did not list every sibling exactly once.
400Payload failed validation — for example an asset whose mime type the add-on does not accept.

See Errors for the response body shape.