# `/v1/slots`

Read-only availability surface. Use **list** for "show me everything in a
window" and **check** for "is this exact time still bookable?".

---

## GET `/v1/slots`

List available slots for an event type over a window.

| | |
|---|---|
| **Method** | `GET` |
| **URL** | `https://api.42min.us/v1/slots` |
| **Scope** | `slots:read` |
| **Auth** | Required |

### Query parameters

| Param | Type | Notes |
|---|---|---|
| `event_type_id` | UUID | Either this **or** `username` + `event_slug` is required. |
| `username` | string | Owner's username. |
| `event_slug` | string | Event-type slug. |
| `start` | ISO 8601 | Window start (inclusive). **Required.** |
| `end` | ISO 8601 | Window end (exclusive). **Required.** Max **31 days** after `start`. |
| `timezone` | IANA tz | Timezone the engine should compute in. Defaults to the event type's schedule timezone, then `UTC`. |

### Response

```json
{
  "data": {
    "event_type_id": "01HXXX…",
    "timezone": "Europe/London",
    "computed_at": "2026-05-14T09:00:00.000Z",
    "slots": [
      { "start": "2026-05-20T10:00:00.000Z", "end": "2026-05-20T10:30:00.000Z", "available": true },
      { "start": "2026-05-20T10:30:00.000Z", "end": "2026-05-20T11:00:00.000Z", "available": true }
    ]
  },
  "meta": { "request_id": "req_…" }
}
```

- All slots returned have `available: true` — busy times are simply omitted.
- `slots[].start` / `end` are ISO 8601 in UTC.
- `computed_at` is the server time the result was generated — useful for
  detecting staleness between list and create.

### curl

```bash
curl -H "Authorization: Bearer $TOKEN" \
  "https://api.42min.us/v1/slots?event_type_id=01HXXX…&start=2026-05-20T00:00:00Z&end=2026-05-21T00:00:00Z&timezone=Europe/London"
```

### Common errors

- `400 invalid_query_param` — `start`/`end` missing, malformed, or window
  longer than 31 days.
- `404 event_type_not_found` — unknown id/slug or wrong account.

---

## GET `/v1/slots/check`

Check whether a specific slot is bookable **right now**.

| | |
|---|---|
| **Method** | `GET` |
| **URL** | `https://api.42min.us/v1/slots/check` |
| **Scope** | `slots:read` |
| **Auth** | Required |

### Query parameters

| Param | Type | Notes |
|---|---|---|
| `event_type_id` | UUID | Or `username` + `event_slug`. Required. |
| `username` | string | |
| `event_slug` | string | |
| `start` | ISO 8601 | Required. |
| `end` | ISO 8601 | Optional — defaults to `start + event_type.duration_minutes`. Must be strictly after `start`. |
| `timezone` | IANA tz | Used only when searching for `next_available`. |

### Response

Slot is available:

```json
{
  "data": { "available": true, "duration_minutes": 30 },
  "meta": { "request_id": "req_…" }
}
```

Slot is not available — `reason` tells you which check failed:

```json
{
  "data": {
    "available": false,
    "reason": "slot_busy",
    "next_available": "2026-05-20T11:00:00.000Z"
  },
  "meta": { "request_id": "req_…" }
}
```

Possible `reason` values:

| Reason | Meaning |
|---|---|
| `event_type_inactive` | The event type's status is not `on`. |
| `in_past` | `start` is in the past. |
| `outside_minimum_notice` | `start` is sooner than the event type's `minimum_notice` allows. |
| `outside_future_limit` | `start` is past the event type's `future_limit_days` horizon. |
| `slot_busy` | A conflicting booking, calendar event, or buffer covers the slot. |

`next_available` is a **best-effort** lookup of the next free slot within
**7 days** after the requested `end`. It may be `null`.

### curl

```bash
curl -H "Authorization: Bearer $TOKEN" \
  "https://api.42min.us/v1/slots/check?event_type_id=01HXXX…&start=2026-05-20T10:00:00Z"
```

### Common errors

- `400 invalid_query_param` — `start` missing or invalid, or `end` not after
  `start`.
- `404 event_type_not_found`.

### When to use which

- **Listing a calendar UI** → `GET /v1/slots`. One round-trip per visible
  range; cache for a few seconds.
- **Just before creating a booking** → `GET /v1/slots/check`. Combine with
  the `Idempotency-Key`'d `POST /v1/bookings` to handle the race when the slot
  is taken between check and create.
