> ## Documentation Index
> Fetch the complete documentation index at: https://api.housera.ro/llms.txt
> Use this file to discover all available pages before exploring further.

# Open house

> How you publish an open house with a note, sign-up and places, tell the people who saved the listing, and work with the attendance sheet.

On an open house day, people come to the listing without a set time. Through the API you publish and change it, tell the people who saved the listing, and read the attendance sheet. The rules are the ones on the Open house page of your Housera account.

## Publishing

`POST /listings/{code}/open-house` publishes one or more windows, at most 60 per request, on an active listing only. Each window has `starts_at` and `ends_at` and can also have:

* `note`: what you tell visitors, for example which buzzer to ring. At most 500 characters. On a firm's listing the note shows on the listing page. On a private person's listing only the people who said they're coming see it.
* `rsvp`: whether people can say they're coming. Defaults to `true`. On a private person's listing it is always `true`.
* `capacity`: the number of places on a developer project's visit day, from 1 to 500. See [Visit days on a project](#visit-days-on-a-project).
* `notify_savers`: `true` tells the people who saved the listing right away, like `POST /viewings/{id}/open-house/announce`.

```json theme={null}
{ "windows": [
  { "starts_at": "2026-11-15T10:00", "ends_at": "2026-11-15T13:00",
    "note": "Ring the buzzer for flat 12.", "rsvp": true, "notify_savers": true }
] }
```

A time without a time zone is read on the listing's local clock. A window can't overlap another window or a viewing time. If one window in the request is refused (an overlap, a time in the past), none of them is published. A body without the new fields publishes exactly what it published in 1.1.0.

The response contains the listing's agenda and `warnings[]`, as when you write a listing. `capacity` sent for a listing that isn't a project is ignored, with the `capacity_not_applicable` warning.

## Visit days on a project

On a developer project that isn't finished (the Launch or Under construction stage, or no stage), visitors only go on site on a visit day with a set number of places. Every window of such a project needs `capacity`. Signing up is required (`rsvp` becomes `true`).

The rule applies in the API from the day we announce to you. Until then, a window without `capacity` is still published, and the response carries the `Deprecation` header with that day (in the form `@1767225600`), a `Link` header to this section and the `site_visit_required_soon` warning on `/windows/{i}/capacity`, with the day in `detail`. From that day on, such a window gets `422 site_visit_required` on `/windows/{i}/capacity`, and nothing in the request is published.

A Finished or Mixed project has viewings at the flats and open houses without places, like any listing.

## Changing a window

`PATCH /viewings/{id}/open-house` changes `starts_at`, `ends_at`, `note`, `rsvp` or `capacity`. Anything you don't send stays as it is, and `note: null` removes the note. The hours move under the same rules as when publishing. A project's visit day keeps its places: you can change them, but `capacity: null` gets `422 site_visit_required`. The response is the window, as an agenda time, plus `warnings[]`.

`PATCH /viewings/{id}` still moves only the hours, as in 1.1.0.

## Telling the people who saved the listing

`POST /viewings/{id}/open-house/announce` tells the people who saved the listing about your open house. The response says in `told` how many people were told.

```json theme={null}
{ "data": { "told": 37, "already_announced": false } }
```

A window is announced only once. A second request, yours or a colleague's, answers `told: 0` and `already_announced: true`. A window that has ended is not announced: `told: 0`, without an error. You can send at most 10 requests a minute, on top of the account's write budget.

## The window's state

Every agenda time has an `open_house` field, `null` for a viewing. For an open house window:

```json theme={null}
"open_house": { "note": "Ring the buzzer for flat 12.", "rsvp": true, "capacity": null,
                "going": 11, "arrived": 4, "savers_notified": false, "savers_to_notify": 37, "running": false }
```

* `going`: how many people said they're coming; `arrived`: how many were marked as arrived.
* `savers_notified`: whether you've already announced the window. `savers_to_notify` is how many people an announcement would reach now, and `null` once it's been announced.
* `running`: `true` while the window is under way.

The numbers aren't personal data, so any key with `listings:read` reads them. The agenda shows only the windows that haven't ended. Windows aren't deleted; only the attendance sheet's rows are, 90 days after the open house.

## The attendance sheet

The attendance sheet says who said they're coming and who came. Its rows are people, so reading it needs `listings:read` and `leads:read`, and changing it needs `listings:write`, `leads:read` and `leads:write`.

`GET /viewings/{id}/attendees` gives the window's rows, most recent first (by arrival, then by sign-up), with `cursor` and `per_page` (at most 100):

```json theme={null}
{ "data": [ {
    "id": 5521, "name": "Ana Popescu", "phone": "+40740123456", "source": "rsvp", "account": true,
    "rsvp_at": "2026-11-13T18:20:00+00:00", "arrived_at": null, "interested": false,
    "consent": false, "consent_at": null, "consent_version": null
  } ],
  "meta": { "going": 11, "arrived": 4, "private": false,
            "checkin": { "url": "https://housera.ro/prezenta-open-house/Ab3…", "opens_at": "2026-11-15T07:00:00+00:00", "closes_at": "2026-11-15T12:00:00+00:00", "open": false } } }
```

* `source` says where the row comes from: `rsvp` (they said they're coming from the listing page), `checkin` (they signed at the door) or `manual` (you added them). For `rsvp`, `name` is the account's name; for `checkin`, what the person wrote.
* `phone` is what the sheet keeps: the account's phone for `rsvp`, the phone written at the door only if the person agreed to be contacted (`consent: true`), and what you typed for `manual`. `consent_version` is the version of the notice they accepted.
* `meta.checkin.url` is the link to the door sheet, which you turn into a QR code. The sheet takes signatures from an hour before the window until an hour after it (`opens_at`, `closes_at`), and `open` says whether it takes them now. The printable poster stays on the portal.
* On a private person's listing, the list shows who said they're coming, and `checkin` is `null`: a private person's open house has no sheet at the door.
* Rows are deleted 90 days after the open house. After that the list is empty.

`POST /viewings/{id}/attendees` adds someone who came, with `name` (at most 120 characters) and, optionally, `phone`. The phone is stored in international format, as on the portal. The row is marked as arrived right away, and the person joins your contacts; if they have a phone, the contact moves to the Viewing stage. The answer is `201` with the row. With the `Idempotency-Key` header, the same request sent again within 10 minutes with the same API key returns the same row with `200` and adds nothing. The same key with a different `name` or `phone` is refused on `/idempotency_key`.

On a row (`/open-house-attendees/{id}`):

* `POST …/arrived` marks it as arrived, and the contact moves to the Viewing stage. On a row that has already arrived it answers `200` and does nothing else.

Adding someone and marking them as arrived get `409 listing_action_refused`, with the reason in `detail`, when the sheet does not accept them right now, for example outside the open house's window, as in the portal.

* `PATCH` with `{ "interested": true }` or `false` says whether the person is interested.
* `DELETE …/consent` withdraws the consent to be contacted, at the person's request: the phone leaves the row, the name stays.
* `DELETE` deletes the row, for example at the person's request or for a wrong row. The answer is `204`. The contact in your requests isn't deleted with the row: if the person asks you to, delete it there too, with `DELETE /leads/{id}`.

A row or window the key can't reach gets `404`, like one that doesn't exist. You learn what happens on the sheet, from the portal, from the visitor or through the API, through the `open_house.attendee_added`, `open_house.attendee_arrived` and `open_house.attendee_removed` events. A webhook subscribed to `lead.created` gets them too. See [Webhooks](https://api.housera.ro/en/webhooks.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.