> ## 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.

# Weekly schedule

> How your viewing hours come from your schedule: your base schedule, each listing's schedule, and applying it to many listings at once.

The hours clients book usually come from a schedule: the days and hours you hold viewings, how long one lasts, the break between them, how far ahead a client must book and how many days ahead they can. Through the API you read and change the schedule as you do on the “My schedule” page of your account. Reading needs the `listings:read` ability; changes need `listings:write` and spend the account's transition budget (60 a minute).

## How the hours come about

Each listing takes its hours in one of three modes:

* `inherit`: it follows the base schedule of whoever runs the listing's viewings. A listing you never changed is in this mode.
* `own`: it has hours of its own, by day.
* `on_request`: it has no hours. Clients ask for a day by message.

From the schedule, Housera generates the free hours over the chosen horizon (7, 14, 21 or 28 days) and extends them as the days go by. New hours show up shortly after you save the schedule. The schedule only adds and withdraws free hours it generated itself: hours published by hand, bookings, requests and open houses stay as they are. A generated hour you withdrew or moved by hand is not created again.

The order of the rules, from the one that wins: the days off and the first day the listing can be visited take whole days out, the notice closes the hours too close to now, and the length plus the break split each range into hours. The hours are read on the clock of each listing's place.

A day holds a list of `{from, to}` ranges, at most 6, on a 15-minute step (`09:00`, `09:15`…), with no overlaps. `24:00` is accepted as the end of the day. A day left out is a day without viewings.

## Your base schedule

`GET /account/viewing-schedule`:

```json theme={null}
{ "data": {
  "saved": true,
  "hours": { "mon": [ { "from": "09:00", "to": "12:00" }, { "from": "14:00", "to": "18:00" } ], "sat": [ { "from": "10:00", "to": "13:00" } ] },
  "duration_min": 30, "buffer_min": null, "notice_min": 120, "horizon_days": 21,
  "confirmation": "manual",
  "blocked_dates": [ { "from": "2026-12-24", "to": "2026-12-26" } ],
  "effective": { "duration_min": 30, "buffer_min": 15, "notice_min": 120, "horizon_days": 21 },
  "options": { "duration_min": [15, 30, 45, 60, 90], "buffer_min": [0, 15, 30], "notice_min": [0, 60, 120, 240, 1440, 2880], "horizon_days": [7, 14, 21, 28] },
  "listings_following": 42
} }
```

* `saved` is `false` until you save the schedule. `effective` then gives the values it starts from.
* A `null` field means you chose nothing. The value applied is in `effective`.
* `confirmation` is your account's setting for every listing without a choice of its own: `auto` confirms bookings at once, `manual` leaves them waiting for your answer.
* `listings_following` counts the public listings whose viewings you run and that follow the base schedule.

`PATCH /account/viewing-schedule` changes only the fields you send:

```bash theme={null}
curl -X PATCH https://housera.ro/api/v1/account/viewing-schedule \
  -H "Authorization: Bearer $HOUSERA_KEY" -H "Content-Type: application/json" \
  -d '{ "hours": { "tue": [ { "from": "17:00", "to": "20:00" } ] }, "notice_min": 240, "confirmation": "auto", "confirm_pending": true }'
```

* A field left out stays as it was, and `null` brings back the default. `confirmation` takes only `auto` or `manual`.
* `hours`, when you send it, replaces the whole week.
* `blocked_dates` holds at most 50 ranges. A one-day range may leave out `to`.
* With `confirm_pending: true`, when the account's setting is `auto` (sent now or already saved), the requests waiting on your listings that follow the account's setting are confirmed too, at most 100 at a time, and each client gets the confirmation. The answer says how many were confirmed and how many still wait: `"confirmed_pending": { "confirmed": 12, "still_waiting": 0 }`.
* The answer has the same shape as `GET` and does not wait for the hours to be generated.
* The base schedule is the account's: the listings whose viewings you run follow it, in every firm you work in. The requests confirmed with `confirm_pending` and the counts in the answer cover only the key's firm and your listings without a firm.

## A listing's schedule

`GET /account/listings/{code}/viewing-schedule`:

```json theme={null}
{ "data": {
  "code": "HEWPUTA8", "mode": "own", "timezone": "Europe/Bucharest",
  "hours": { "tue": [ { "from": "17:00", "to": "20:00" } ] },
  "duration_min": 45, "notice_min": null, "available_from": "2026-12-01",
  "confirmation": null,
  "runner": { "name": "Maria Popa", "email": "maria@exemplu.ro" },
  "blocked_dates": [],
  "occupant": { "notify": true, "phone": "+40740123456" },
  "effective": { "hours": { "tue": [ { "from": "17:00", "to": "20:00" } ] }, "duration_min": 45, "buffer_min": 15, "notice_min": 120, "horizon_days": 21, "confirmation": "auto", "blocked_dates": [] },
  "base_saved": true, "pending_requests": 3
} }
```

* `hours` are the listing's own hours. They are kept while the listing follows another mode, so you find them again when you switch back.
* `duration_min`, `notice_min` and `confirmation` set to `null` mean “as usual”: the base schedule of whoever runs the viewings, and the holder's setting.
* `runner` is the person who runs the viewings: a colleague you gave them to or, otherwise, the holder. Its email goes to the keys of the holder, the admins and the manager who has that person on their team, and to the person's own key; any other key gets `email: null`, as on the Team page in the portal.
* `occupant.phone` is a person's phone number, so only a key with `leads:read` gets it. Otherwise it is `null`.
* `effective` is what generates the hours now, and is read only. The break and the horizon always come from the base schedule of whoever runs the viewings.
* `base_saved` says whether that person has a saved base schedule. Without one, `inherit` gives clients no hours.

`PATCH /listings/{code}/viewing-schedule` changes only the fields you send: `mode`, `hours` (only with `mode: own`), `duration_min`, `notice_min`, `available_from` (`YYYY-MM-DD`), `confirmation` (`auto`, `manual` or `null`), `runner`, `occupant` (`notify`, `phone`), `blocked_dates`, `confirm_pending`.

* `{"mode": "inherit"}` alone (or another mode) changes the mode and nothing else, as in the portal: the rules and the own hours stay. A listing moving to `own` without hours of its own starts from the base schedule of whoever runs the viewings, so nothing changes for clients until you edit the hours.
* `runner` is the email of an active colleague of the listing's firm, one you could also pick in the portal (a manager picks from their team). `null` or the holder's email leaves the viewings to the holder. On a listing without a firm, the only possible `runner` is the holder.
* `occupant.phone` is required when `occupant.notify` is `true`. The number is kept with the listing's schedule while `notify` is `true`; with `notify: false` it is deleted, as in the app.
* `confirm_pending: true` confirms the requests waiting on this listing, when after the save the listing confirms at once.
* On a listing that is not public, the schedule is saved but generates no hours until the listing is active again.

`PATCH /listings/{code}/viewings` (the settings in [Viewings](https://api.housera.ro/en/guides/viewings.md)) writes the same length and the same confirmation. There a `null` is ignored. Here, `null` means “as usual”.

The listing's length and confirmation change the listing's `etag`, as through `PATCH /listings/{code}/viewings`. The hours, the mode, the notice, the days off and `runner` do not.

## Your schedule on several listings

`POST /account/viewing-schedule/apply` does what „Folosește programul meu” does on the listings selected in the portal. You send at most 100 codes:

```json theme={null}
{ "codes": ["HEWPUTA8", "HEWPUTB2", "HEWPUTC3"] }
```

```json theme={null}
{ "data": { "applied": ["HEWPUTA8"], "skipped": [ { "code": "HEWPUTB2", "reason": "base_schedule_missing" }, { "code": "HEWPUTC3", "reason": "not_active" } ] } }
```

A listing moves to `inherit` when it is active, you manage it and whoever runs its viewings has a saved base schedule. Otherwise you get the reason: `base_schedule_missing`, `not_active` or `not_found`. A code that does not exist and one your key does not reach both get `not_found`. The same list sent twice gives the same result.

## Errors

| Status | `code` | When |
| - | - | - |
| `422` | `viewing_hours` | `hours` is not a valid week: a range off the 15-minute step, an end before the start, overlapping ranges, more than 6 a day or an unknown day. |
| `422` | `hours_need_own_mode` | You sent `hours` for a listing that stays on `inherit` or `on_request`. Send `mode: own` as well. |
| `422` | `runner_not_member` | The email in `runner` is not a colleague you can have run the listing's viewings. |
| `422` | `occupant_phone_required` | `occupant.notify` is `true`, but `occupant.phone` is missing. |
| `422` | `in`, `max`, `date_format`, `regex` | A value not in `options`, more than 50 days off or more than 100 codes, a date in another format, a wrong phone number. |
| `404` | `not_found` | A listing you neither manage nor run the viewings of. The answer comes before any check of the body. |
| `403` | `missing_ability` | A key without `listings:write` tries a change. |


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