# Classes and group sessions – Tiempo

> Run classes with a fixed number of places: a session booking with seats, attendees who hold and confirm a place, weekly timetables as series, and waitlists from webhooks.

Source: https://tiempo.one/docs/classes

Yoga, spin, pilates, kids’ swimming, a group workshop: a class takes an instructor and a room for an hour, and has a number of places that customers book one by one. In Tiempo the class is a **session** (a booking with `seats`), and each customer is an **attendee** taking one or more of them.

The session occupies the instructor and the room like any booking, so nobody can book the studio for a private session on top of it. Seats are counted under a lock, so the last place goes to exactly one person.

## Put a class on the timetable

Create the session as `confirmed` with its segments and `seats`. Keep the class type, price and description in your app, with the booking id; `metadata` is handy for your own ids.

Thursday yoga, 12 places

```bash
curl -X POST "$TIEMPO/v1/bookings" \
  -H "Authorization: Bearer $TIEMPO_KEY" \
  -H "Tiempo-Account: $ACCOUNT" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "confirmed",
    "seats": 12,
    "segments": [
      {
        "resource": "res_maya",
        "start": "2026-11-19T18:00:00Z",
        "end": "2026-11-19T19:00:00Z"
      },
      {
        "resource": "res_studio_1",
        "start": "2026-11-19T18:00:00Z",
        "end": "2026-11-19T19:00:00Z"
      }
    ],
    "metadata": {
      "class_id": "cls_vinyasa"
    }
  }'
```

## Customers take a place

Adding an attendee without a status holds the place while they pay, just like a booking hold, and it lapses if they leave. Confirm it after payment. When the class is full, you get `409 seats_unavailable` with `seats_available`, so you can offer the waitlist.

Attendees have the same lifecycle as bookings: cancel, mark `completed` or `no_show` after the class starts. The session shows `seats_taken`. Cancelling the session cancels its attendees too.

Hold one place

```bash
curl -X POST "$TIEMPO/v1/bookings/bkg_…/attendees" \
  -H "Authorization: Bearer $TIEMPO_KEY" \
  -H "Tiempo-Account: $ACCOUNT" \
  -H "Idempotency-Key: order_5521-place" \
  -H "Content-Type: application/json" \
  -d '{
    "seats": 1,
    "metadata": {
      "customer_id": "cus_204"
    }
  }'
```

Full

```json
{
  "error": {
    "type": "conflict_error",
    "code": "seats_unavailable",
    "message": "Requested 1 seat(s) but only 0 available.",
    "seats_available": 0
  }
}
```

## A weekly timetable

A [series](https://tiempo.one/docs/series) creates the class every week (or any RRULE) as real sessions, a rolling window ahead. Each occurrence keeps its local time through clock changes. If one clashes with something already booked, it’s skipped and you get `series.occurrence_skipped` rather than a double-booked studio.

Customers book a place on an occurrence like any session. To change the timetable from a date, edit the series in place; to cancel one week, cancel that session.

Tuesdays and Thursdays at 07:00

```bash
curl -X POST "$TIEMPO/v1/series" \
  -H "Authorization: Bearer $TIEMPO_KEY" \
  -H "Tiempo-Account: $ACCOUNT" \
  -H "Content-Type: application/json" \
  -d '{
    "rrule": "FREQ=WEEKLY;BYDAY=TU,TH",
    "start_date": "2026-11-17",
    "start_time": "07:00",
    "timezone": "Europe/London",
    "template": {
      "seats": 12,
      "segments": [
        {
          "resource": "res_maya",
          "offset_minutes": 0,
          "duration_minutes": 60
        },
        {
          "resource": "res_studio_1",
          "offset_minutes": 0,
          "duration_minutes": 60
        }
      ]
    }
  }'
```

## Waitlists

Tiempo doesn’t keep a waitlist, because who gets offered a place first (and whether they pay a deposit) is your product’s decision. It tells you when a place frees up: listen for `attendee.cancelled` and `attendee.expired`, then offer the place to the next person and hold it for them with a new attendee.

Private sessions in the same studio are ordinary bookings on the same resources. See the [attendees reference](https://tiempo.one/docs/attendees) for every field.

The machine-readable description is at [/openapi.json](https://tiempo.one/openapi.json). Try calls in [Swagger UI](https://tiempo.one/swagger-ui.html).[Tiempo home](https://tiempo.one/)[Dashboard](https://tiempo.one/app)
