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

# Agenda de vizionări

> Cum citești vizionările de pe toate anunțurile tale și cum lucrezi cu ele: clientul care a sunat, altă oră, anularea și „Cum a fost?”.

Agenda adună vizionările, cererile și zilele de vizită de pe toate anunțurile pe care le conduci, ca agenda din cont. Prin API o citești și lucrezi cu fiecare vizionare. Citirea cere dreptul `listings:read`. Datele clienților cer în plus `leads:read`.

## Ce intră în agendă

Agenda unei chei e agenda contului ei din portal:

* anunțurile active ale contului;
* anunțurile ale căror vizionări i-au fost date de un coleg;
* pentru titular, administratori și manageri, anunțurile echipei (un manager își vede echipa);
* pentru un consultant al unui dezvoltator, proiectele pe care lucrează, iar acolo doar clienții care au ajuns la el și zilele de vizită.

Un anunț care nu e public nu apare. O cheie legată de o firmă vede doar anunțurile acelei firme și pe cele fără firmă ale contului.

## Citirea agendei

`GET /account/viewings` întoarce orele dintr-un interval, câte o pagină, în ordinea orei:

```bash theme={null}
curl "https://housera.ro/api/v1/account/viewings?from=2026-11-16&to=2026-11-22&status=pending,booked" \
  -H "Authorization: Bearer $HOUSERA_KEY"
```

| Parametru | Ce face |
| - | - |
| `from`, `to` | Intervalul: o zi (`2026-11-16`, pe ceasul României, ca agenda) sau un moment cu fus orar. O zi trimisă în `to` intră întreagă. Implicit, de azi pe 14 zile. Cel mult 93 de zile. |
| `listing` | Codul unui anunț. Un cod din afara agendei dă o listă goală. |
| `agent` | Emailul unui coleg: doar ce face el. Titularul, un administrator sau un manager pot numi orice coleg din agenda lor. Ceilalți pot numi doar emailul propriu. Altfel lista e goală. |
| `status` | Stările vizionărilor, separate prin virgulă: `pending`, `booked`, `completed`, `available`. Implicit `pending,booked,completed`. `available` cere și `listing`. |
| `kind` | `viewing` sau `open_house`. Fără el, amândouă. Zilele de vizită liberă intră indiferent de `status`. |
| `per_page`, `cursor` | Mărimea paginii (cel mult 100, implicit 50) și cursorul din `meta.next_cursor`. |

```json theme={null}
{ "data": [ {
    "id": 9182, "kind": "viewing", "status": "completed",
    "starts_at": "2026-11-10T08:00:00+00:00", "ends_at": "2026-11-10T08:30:00+00:00", "request_expires_at": null,
    "visitor": { "name": "Ana Popescu", "email": "ana@exemplu.ro", "phone": "+40740123456", "account": true },
    "source": "manual", "duration_min": 30, "held": false, "bookable": null,
    "booked_at": "2026-11-08T10:12:00+00:00", "proposed_starts_at": null,
    "attendance_confirmed_at": "2026-11-09T07:00:00+00:00", "reminded_day_at": "2026-11-09T07:00:00+00:00", "reminded_soon_at": null,
    "outcome": "again", "outcome_at": "2026-11-10T09:00:00+00:00",
    "agent": { "name": "Maria Popa", "email": "maria@exemplu.ro" },
    "place": null, "place_rooms": null, "seat": 0,
    "listing": { "code": "HEWPUTA8", "external_ref": "crm-118", "title": "Apartament 3 camere, Copou", "url": "https://housera.ro/anunt/hewputa8" },
    "outcome_note": "Vrea să revină cu soția."
  } ],
  "links": { "first": null, "last": null, "prev": null, "next": null },
  "meta": { "path": "https://housera.ro/api/v1/account/viewings", "per_page": 50, "next_cursor": null, "prev_cursor": null,
    "pending_requests": 2, "next_at": "2026-11-16T10:00:00+00:00" } }
```

`meta.pending_requests` numără toate cererile care așteaptă răspunsul tău în agendă, nu doar cele din interval. O cerere la care ai propus altă oră așteaptă răspunsul clientului și nu intră în număr, ca în portal. `meta.next_at` e următoarea vizionare sau cerere.

`GET /viewings/{id}` întoarce o singură oră, în aceeași formă. O oră din afara agendei răspunde `404`.

## Stările

* `available`: o oră liberă.
* `pending`: o cerere care așteaptă răspunsul tău, până la `request_expires_at`.
* `booked`: o vizionare rezervată care n-a trecut.
* `completed`: o vizionare rezervată a cărei oră s-a terminat. Starea se calculează la citire: o vizionare devine `completed` imediat ce i se termină ora.

`completed` apare doar aici și în `GET /viewings/{id}`. Agenda unui anunț (`GET /account/listings/{code}/viewings`) arată doar orele care n-au trecut, cu stările `available`, `pending` și `booked`.

## Clientul și datele lui

`visitor` și `outcome_note` vin doar pentru o cheie cu dreptul `leads:read`. Pentru celelalte chei sunt `null`, iar `outcome` și `outcome_at` rămân.

* `account: true`: clientul are cont pe Housera, cu nume, email și telefon.
* `account: false`: un client fără cont, adăugat de mână. Are nume și, dacă l-ai trecut, telefon, dar nu are email. Agenda unui anunț nu îl numește (`visitor: null`).

Housera nu păstrează aceste date mai mult decât în portal. Numele și telefonul unui client adăugat de mână se șterg la 90 de zile după vizionare, iar apoi `visitor` e `null`. Nota de la „Cum a fost?” se șterge după 24 de luni.

## Orele libere

* `source`: `schedule` pentru orele generate de [programul săptămânal](https://api.housera.ro/ro/guides/viewing-schedule.md), `manual` pentru cele puse de mână.
* `held`: ora e ținută pentru scurt timp pentru cineva care intră în cont ca s-o rezerve.
* `bookable`: dacă un client poate rezerva ora acum. E `false` când ora e prea aproape (preavizul), când cel care face vizionările e ocupat la același moment la alt anunț (cu pauza dintre vizionări) sau când ora e ținută. La orele care nu sunt libere e `null`.

## Proiectele dezvoltatorilor

La un proiect cu mai mulți consultanți, fiecare oră are câte un rând pentru fiecare consultant, cu același `starts_at` și alt `seat`. Rândurile nu sunt dubluri: sunt locurile orei. După rezervare, `agent` e consultantul care se întâlnește cu clientul, iar `place` spune unde: `office` (biroul de vânzări), `show_flat` (apartamentul de prezentare) sau `unit` (un apartament finalizat, cu `place_rooms` camere). În rest, `agent` e cel care face vizionările anunțului. `agent.email` îl primesc cheile titularului, ale administratorilor și ale managerului care îl are în echipă, plus cheia lui; celelalte primesc `null`, ca pe pagina Echipa din portal.

## Agenda unui anunț

`GET /account/listings/{code}/viewings` primește aceleași câmpuri noi pe fiecare oră (`source`, `duration_min`, `held`, `bookable`, `booked_at`, `proposed_starts_at`, `attendance_confirmed_at`, `reminded_day_at`, `reminded_soon_at`, `outcome`, `outcome_at`, `agent`, `place`, `place_rooms`, `seat`), plus `timezone` și `schedule_mode` pe anunț.

## Clientul care a sunat

`POST /listings/{code}/viewings/clients` pune în agendă un client fără cont cu care ai stabilit o oră la telefon, ca „Adaugă în agendă” din portal. Cere `listings:write`, `leads:read` și `leads:write`, fiindcă adaugă un contact.

```json theme={null}
{ "starts_at": "2026-11-14T11:00", "duration_min": 30, "name": "Ion Marinescu", "phone": "+40740123456" }
```

* `starts_at` se citește ca la orele publicate: fără fus orar, pe ceasul locului anunțului. `duration_min` e 15, 30, 45, 60 sau 90. `name` are cel mult 120 de caractere, iar `phone` e opțional.
* Ora se rezervă pe loc, cu aceleași reguli de suprapunere ca o oră publicată pe anunț. Orele libere de sub ea dispar.
* Clientul intră în contacte cu sursa `other`. Dacă are telefon, contactul trece în etapa Vizionare.
* Răspunsul e `201`, cu ora (`visitor` cu `account: false`).
* Cu antetul `Idempotency-Key`, aceeași cerere repetată în 10 minute nu mai adaugă nimic și întoarce ora adăugată prima dată, în starea ei de acum, cu `200`. Aceeași cheie cu alt corp e refuzată pe `/idempotency_key`. Fără cheie, a doua cerere pe aceeași oră primește `409 listing_action_refused`, fiindcă ora nu mai e liberă.
* O oră care se suprapune cu altă vizionare sau cu o zi de vizită, una din trecut sau una care nu există la schimbarea orei e refuzată pe `/starts_at`.

Vizionarea unui astfel de client se mută direct, cu `PATCH /viewings/{id}`.

## Altă oră pentru un client cu cont

`POST /viewings/{id}/proposal` cu `{"starts_at": "2026-11-15T10:00"}` îi propune clientului altă oră. Vizionarea își păstrează ora până răspunde el, iar răspunsul are acum `proposed_starts_at`. Clientul primește mesajul ca din portal. Când acceptă, `starts_at` devine ora propusă, iar `proposed_starts_at` redevine `null`.

O zi de vizită, o vizionare fără client cu cont și una care s-a terminat primesc `409 listing_action_refused`. O oră care se suprapune cu alta sau la care cel care face vizionările nu e liber (cu pauza dintre vizionări, la toate anunțurile lui) e refuzată pe `/starts_at`.

## Anularea cu o notă

`POST /viewings/{id}/cancel` primește opțional `note`, cel mult 300 de caractere, care ajunge în mesajul către clientul cu cont (un client adăugat de mână nu primește mesaje de la Housera). `note` e opțional.

## „Cum a fost?”

`PUT /viewings/{id}/outcome` spune ce a ieșit dintr-o vizionare care a avut loc:

```json theme={null}
{ "outcome": "offer", "note": "Revine joi cu soția." }
```

* `outcome` e `offer` (vrea să facă o ofertă), `again` (revine), `not_interested` (nu e interesat) sau `no_show` (nu a venit). `note` are cel mult 500 de caractere.
* Răspunsul se poate schimba oricând, iar o nouă cerere fără `note` șterge nota.
* La `offer`, contactul clientului de pe anunț trece în etapa Ofertă, dacă nu ajunsese acolo. Răspunsul are `meta.lead_moved_to_offer`.
* Cere `listings:write` și `leads:write`, fiindcă mută un contact între etape.
* O vizionare care n-a avut loc încă primește `409 listing_action_refused`.

## Linia de vizionări din „Anunțurile mele”

`GET /account/listings?include=viewings` adaugă pe fiecare anunț câmpul `viewings`:

```json theme={null}
{ "next_at": "2026-11-16T10:00:00+00:00", "next_kind": "viewing", "next_pending": false, "more": 3, "bookable": true, "on_request": false }
```

`next_at` și `next_kind` sunt următoarea programare (o vizionare sau o zi de vizită), `more` câte mai urmează după ea, `bookable` dacă are ore libere de rezervat, `on_request` dacă e „La cerere”. Fără `include`, răspunsul nu are aceste câmpuri, iar `etag`-ul anunțului nu se schimbă.

`GET /account/listings?viewings=none` întoarce doar anunțurile active „Fără program”: fără ore libere, fără nimic programat și fără să fie „La cerere”.

## Ce află CRM-ul fără să întrebe

Din ziua pe care ți-o anunțăm, fiecare schimbare a unei vizionări pleacă și ca eveniment, la fel din portal și din API. Așa afli și ce a făcut un coleg în portal, fără să citești agenda la fiecare minut.

| Ce s-a întâmplat | Evenimentul |
| - | - |
| Un client a rezervat sau a cerut o oră | `viewing.booked` |
| Ai confirmat sau ai refuzat o cerere | `viewing.confirmed`, `viewing.declined` |
| I-ai propus clientului altă oră, iar el a răspuns | `viewing.proposal_sent`, `viewing.proposal_answered` |
| Vizionarea s-a mutat la altă oră | `viewing.rescheduled` |
| Clientul a anulat sau cererea a expirat | `viewing.cancelled` |
| Tu sau un coleg ați anulat vizionarea ori ați retras ora | `viewing.cancelled_by_lister` |
| Clientul a răspuns „Da, vin” | `viewing.attendance_confirmed` |
| Vizionarea s-a încheiat | `viewing.completed` |
| S-a spus „Cum a fost?” | `viewing.outcome_recorded` |

Evenimentele au `slot_id` și ora, fără datele clientului. Cu `slot_id` citești vizionarea prin `GET /viewings/{id}`, iar numele și telefonul clientului le vede doar o cheie cu `leads:read`.

Când clientul cu cont își mută singur vizionarea pe altă oră liberă, primești `viewing.cancelled` și apoi `viewing.booked`, cu id nou.

Când anunțul iese de la vânzare (îl pui pe pauză, îl marchezi vândut, îl retragi sau e respins), vizionările lui viitoare se eliberează fără câte un eveniment pentru fiecare. Afli din evenimentul anunțului, de exemplu `listing.paused` sau `listing.sold`, iar clienții cu cont primesc vestea de la Housera.

`viewing.completed` poate sosi cu o întârziere de până la o oră. Starea din `GET /account/viewings` e `completed` imediat ce ora s-a terminat: dacă ai nevoie de ea pe loc, citește-o.

Lista completă, cu câmpurile fiecărui eveniment și cine îl primește, e în [Webhook-uri](https://api.housera.ro/ro/webhooks.md#evenimentele-vizionărilor).


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