# Availability

Two endpoints deal with whether a night can be sold, and the difference trips
people up often enough to be worth one page.

| | `/v1/calendar` | `/v1/blocks` |
| --- | --- | --- |
| What it is | A **projection** | A **resource** |
| Answers | "Can I sell this night, and for how much?" | "Why is this night closed, and who closed it?" |
| Has ids | No — addressed by property + date | Yes |
| You can delete | Nothing | A block |

## The calendar is a view, not a store

`GET /v1/calendar` merges four things into one row per property per date:
reservations, blocks, per-date overrides and the property defaults. That is the
whole point — you get the answer instead of four queries and a join:

```json
{
  "date": "2026-10-02",
  "available": false,
  "price_cents": 14500,
  "min_stay": 2,
  "closed_to_arrival": false,
  "closed_to_departure": false,
  "blocked_by": "block"
}
```

`blocked_by` tells you which of the four caused the closure: `reservation`,
`block`, `stop_sell`, or `null` when the night is sellable.

Because it is a projection, there is nothing to delete. Writing to it sets
per-date prices and restrictions, including `stop_sell` to close a night with no
further explanation.

## Blocks are things

A block has an id, a reason, and an owner. Only the integration that created one
may amend or delete it — your blocks are yours, and a staff-created block is
readable but immutable through the API. None of that fits in a date-addressed
grid, which is why blocks are their own resource rather than a calendar flag.

```bash
curl -X POST https://api.wearenoe.fr/v1/blocks \
  -H "Authorization: Bearer $KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "property_id": "…",
    "start_date": "2026-10-01",
    "end_date": "2026-10-05",
    "reason_type": "maintenance",
    "reason": "Boiler replacement"
  }'
```

## Which one should I use?

Use a **block** when there is a real-world reason worth recording — an owner
stay, maintenance, a hold. It survives as an explanation, and you can remove it
later by id.

Use **`stop_sell`** on the calendar when you just want the night closed and the
reason does not matter, for example while you decide on pricing.

Use `last_day_is_checkout` on a block when the occupant leaves that morning: the
final date stops being a held night and stays sellable as an arrival. Getting
this wrong is the most common cause of "we lost a bookable night".
