# Bookings API – Tiempo

> Time held on one or more resources. A booking starts pending (a hold that expires after 15 minutes by default) and becomes confirmed when you confirm it.

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

Time held on one or more resources. A booking starts pending (a hold that expires after 15 minutes by default) and becomes confirmed when you confirm it. Placing a booking locks its resources first, so when two requests race for the same time exactly one wins.

Booking lifecycle: pending becomes confirmed, or ends expired or cancelled; a confirmed booking ends completed, no-show or cancelled, and can be flagged conflicted after a rota change.

## Create a booking

`POST /v1/bookings`

Places a booking: pending by default, or confirmed straight away with status "confirmed". All segments are placed together or not at all. Give a segment resources (candidates in order of preference) instead of resource for “anyone available”. A 409 booking_conflict lists the reason for each segment.

Send the business’s id in `Tiempo-Account`.

### Body parameters

-   `segments` (array of objects, required)
    
    The time to hold: one entry per resource and period. Segments can be on different resources and needn’t touch.
    
    -   `resource` (string)
        
        A resource id.
        
    -   `resources` (array of strings)
        
        Candidate resource ids in your order of preference; Tiempo takes the first that fits.
        
    -   `start` (timestamp, required)
        
        An ISO-8601 instant.
        
    -   `end` (timestamp, required)
        
        An ISO-8601 instant, after start.
        
    -   `quantity` (integer)
        
        Units of capacity to take. Defaults to 1 (for blocks, the whole capacity).
        
    -   `location` (string)
        
        A location id.
        
    -   `buffer_before_minutes` (integer)
        
        Minutes the resource is also held before the time (travel, setup), 0–1440. On a booking segment it overrides the resource’s default; the appointment’s start and end don’t change.
        
    -   `buffer_after_minutes` (integer)
        
        Minutes the resource is also held after the time (cleanup, turnaround), 0–1440. On a booking segment it overrides the resource’s default. Buffers must fit in working hours and can’t overlap blocks or other bookings.
        
-   `status` (string)
    
    pending (a hold) or confirmed.
    
-   `expires_at` (timestamp)
    
    When a hold lapses. Defaults to 15 minutes; at most your platform’s longest hold ahead, 24 hours unless an owner or admin changes it in the dashboard (up to 7 days).
    
-   `seats` (integer)
    
    Makes the booking a session that attendees take seats in.
    
-   `conflict_policy` (string)
    
    reject (default) refuses time that isn’t free or isn’t working hours. capacity_only ignores working hours, overrides and blocks (staff booking a client in after hours) but still never overlaps another booking. allow places it anyway (a deliberate overbook) and flags it.
    
-   `replaces` (string)
    
    A booking this one replaces. Its time doesn’t count against the new booking, and it’s cancelled when the new one is confirmed.
    
-   `metadata` (map)
    
    Up to 50 keys of your own (strings, keys up to 40 characters, values up to 500). Returned on every read and webhook. On update, an empty string removes a key.
    

### Returns

The booking. Sends booking.created (and booking.confirmed if created confirmed).

POST /v1/bookings

```bash
curl -X POST "https://api.tiempo.one/v1/bookings" \
  -H "Authorization: Bearer tpt_4qZ8m1VwXc0L…" \
  -H "Tiempo-Account: acct_01m42yt93ayvyrwr3yczhv6yhw" \
  -H "Content-Type: application/json" \
  -d '{
    "segments": [
      {
        "resource": "res_ann",
        "start": "2026-11-16T10:00:00Z",
        "end": "2026-11-16T10:45:00Z"
      }
    ],
    "metadata": {
      "your_booking_id": "apt_8812"
    }
  }'
```

200Response

```json
{
  "id": "bkg_01m42ytcajvtw8pmzf8dydhmz5",
  "object": "booking",
  "livemode": false,
  "status": "pending",
  "expires_at": "2026-10-04T08:14:53Z",
  "start": "2026-11-16T10:00:00Z",
  "end": "2026-11-16T10:45:00Z",
  "segments": [
    {
      "resource": "res_01m42ytc9b53589z4rp11zedjy",
      "location": null,
      "start": "2026-11-16T10:00:00Z",
      "end": "2026-11-16T10:45:00Z",
      "quantity": 1,
      "buffer_before_minutes": 0,
      "buffer_after_minutes": 10
    }
  ],
  "seats": null,
  "seats_taken": null,
  "conflict_policy": "reject",
  "conflicted": false,
  "conflicts": null,
  "series": null,
  "occurrence_key": null,
  "replaces": null,
  "replaced_by": null,
  "cancellation_reason": null,
  "confirmed_at": null,
  "cancelled_at": null,
  "metadata": {
    "your_booking_id": "apt_8812"
  },
  "created_at": "2026-10-04T07:59:53Z",
  "updated_at": "2026-10-04T07:59:53Z"
}
```

## List bookings

`GET /v1/bookings`

Bookings overlapping a window, newest made first or, with order=start, earliest first. Give the window as local dates (from_date and to_date, inclusive, in the business’s timezone unless you pass timezone), so “next Thursday” or “the week of 18 December” needs no timezone maths; or as instants with from and to. conflicted=true finds the bookings a rota change broke.

Send the business’s id in `Tiempo-Account`.

### Query parameters

-   `status` (string)
    
    Only objects with this status.
    
-   `resource` (string)
    
    Only those involving this resource. On the calendar, repeat it for several.
    
-   `location` (string)
    
    Only those at this location.
    
-   `series` (string)
    
    Only this series’ occurrences.
    
-   `from` (timestamp)
    
    Only those ending after this instant.
    
-   `to` (timestamp)
    
    Only those starting before this instant.
    
-   `from_date` (date)
    
    From this local date (YYYY-MM-DD), inclusive.
    
-   `to_date` (date)
    
    To this local date (YYYY-MM-DD), inclusive.
    
-   `timezone` (string)
    
    The timezone of from_date and to_date. Defaults to the business’s (for the calendar, the location’s first).
    
-   `conflicted` (boolean)
    
    true for bookings a rota, block or capacity change no longer fits.
    
-   `order` (string)
    
    created (default): newest made first. start: earliest first, by start time.
    
-   `limit` (integer)
    
    1 to 100. Defaults to 20.
    
-   `starting_after` (string)
    
    An object id from the previous page; returns the page after it.
    
-   `ending_before` (string)
    
    An object id; returns the page before it.
    
-   `metadata[key]` (string)
    
    Only objects whose metadata has this key and value. Repeat for several.
    

GET /v1/bookings

```bash
curl "https://api.tiempo.one/v1/bookings?from_date=2026-12-14&to_date=2026-12-20&order=start" \
  -H "Authorization: Bearer tpt_4qZ8m1VwXc0L…" \
  -H "Tiempo-Account: acct_01m42yt93ayvyrwr3yczhv6yhw"
```

200Response

```json
{
  "object": "list",
  "data": [
    {
      "id": "bkg_01m42ytcajvtw8pmzf8dydhmz5",
      "object": "booking",
      "livemode": false,
      "status": "pending",
      "expires_at": "2026-10-04T08:14:53Z",
      "start": "2026-11-16T10:00:00Z",
      "end": "2026-11-16T10:45:00Z",
      "segments": [
        {
          "resource": "res_01m42ytc9b53589z4rp11zedjy",
          "location": null,
          "start": "2026-11-16T10:00:00Z",
          "end": "2026-11-16T10:45:00Z",
          "quantity": 1,
          "buffer_before_minutes": 0,
          "buffer_after_minutes": 10
        }
      ],
      "seats": null,
      "seats_taken": null,
      "conflict_policy": "reject",
      "conflicted": false,
      "conflicts": null,
      "series": null,
      "occurrence_key": null,
      "replaces": null,
      "replaced_by": null,
      "cancellation_reason": null,
      "confirmed_at": null,
      "cancelled_at": null,
      "metadata": {
        "your_booking_id": "apt_8812"
      },
      "created_at": "2026-10-04T07:59:53Z",
      "updated_at": "2026-10-04T07:59:53Z"
    }
  ],
  "has_more": false
}
```

## Retrieve a booking

`GET /v1/bookings/{id}`

Send the business’s id in `Tiempo-Account`.

### Path parameters

-   `id` (string, required)
    
    The object’s id.
    

GET /v1/bookings/{id}

```bash
curl "https://api.tiempo.one/v1/bookings/bkg_01m42ytcajvtw8pmzf8dydhmz5" \
  -H "Authorization: Bearer tpt_4qZ8m1VwXc0L…" \
  -H "Tiempo-Account: acct_01m42yt93ayvyrwr3yczhv6yhw"
```

200Response

```json
{
  "id": "bkg_01m42ytcajvtw8pmzf8dydhmz5",
  "object": "booking",
  "livemode": false,
  "status": "pending",
  "expires_at": "2026-10-04T08:14:53Z",
  "start": "2026-11-16T10:00:00Z",
  "end": "2026-11-16T10:45:00Z",
  "segments": [
    {
      "resource": "res_01m42ytc9b53589z4rp11zedjy",
      "location": null,
      "start": "2026-11-16T10:00:00Z",
      "end": "2026-11-16T10:45:00Z",
      "quantity": 1,
      "buffer_before_minutes": 0,
      "buffer_after_minutes": 10
    }
  ],
  "seats": null,
  "seats_taken": null,
  "conflict_policy": "reject",
  "conflicted": false,
  "conflicts": null,
  "series": null,
  "occurrence_key": null,
  "replaces": null,
  "replaced_by": null,
  "cancellation_reason": null,
  "confirmed_at": null,
  "cancelled_at": null,
  "metadata": {
    "your_booking_id": "apt_8812"
  },
  "created_at": "2026-10-04T07:59:53Z",
  "updated_at": "2026-10-04T07:59:53Z"
}
```

## Update a booking

`POST /v1/bookings/{id}`

Extends a hold (expires_at, up to your platform’s longest hold: 24 hours unless you’ve changed it), changes seats on a session, or updates metadata.

Send the business’s id in `Tiempo-Account`.

### Path parameters

-   `id` (string, required)
    
    The object’s id.
    

### Body parameters

-   `expires_at` (timestamp)
    
    When a hold lapses. Defaults to 15 minutes; at most your platform’s longest hold ahead, 24 hours unless an owner or admin changes it in the dashboard (up to 7 days).
    
-   `seats` (integer)
    
    Makes the booking a session that attendees take seats in.
    
-   `metadata` (map)
    
    Up to 50 keys of your own (strings, keys up to 40 characters, values up to 500). Returned on every read and webhook. On update, an empty string removes a key.
    

POST /v1/bookings/{id}

```bash
curl -X POST "https://api.tiempo.one/v1/bookings/bkg_01m42ytcajvtw8pmzf8dydhmz5" \
  -H "Authorization: Bearer tpt_4qZ8m1VwXc0L…" \
  -H "Tiempo-Account: acct_01m42yt93ayvyrwr3yczhv6yhw" \
  -H "Content-Type: application/json" \
  -d '{
    "expires_at": "2026-10-04T08:44:53Z"
  }'
```

200Response

```json
{
  "id": "bkg_01m42ytcajvtw8pmzf8dydhmz5",
  "object": "booking",
  "livemode": false,
  "status": "pending",
  "expires_at": "2026-10-04T08:14:53Z",
  "start": "2026-11-16T10:00:00Z",
  "end": "2026-11-16T10:45:00Z",
  "segments": [
    {
      "resource": "res_01m42ytc9b53589z4rp11zedjy",
      "location": null,
      "start": "2026-11-16T10:00:00Z",
      "end": "2026-11-16T10:45:00Z",
      "quantity": 1,
      "buffer_before_minutes": 0,
      "buffer_after_minutes": 10
    }
  ],
  "seats": null,
  "seats_taken": null,
  "conflict_policy": "reject",
  "conflicted": false,
  "conflicts": null,
  "series": null,
  "occurrence_key": null,
  "replaces": null,
  "replaced_by": null,
  "cancellation_reason": null,
  "confirmed_at": null,
  "cancelled_at": null,
  "metadata": {
    "your_booking_id": "apt_8812"
  },
  "created_at": "2026-10-04T07:59:53Z",
  "updated_at": "2026-10-04T07:59:53Z"
}
```

## Confirm a booking

`POST /v1/bookings/{id}/confirm`

Turns a hold into a kept booking, usually once the customer has paid. An expired hold can’t be confirmed (409); its time may already be gone.

Send the business’s id in `Tiempo-Account`.

### Path parameters

-   `id` (string, required)
    
    The object’s id.
    

### Returns

The confirmed booking. Sends booking.confirmed. This is when it counts towards usage.

POST /v1/bookings/{id}/confirm

```bash
curl -X POST "https://api.tiempo.one/v1/bookings/bkg_01m42ytcajvtw8pmzf8dydhmz5/confirm" \
  -H "Authorization: Bearer tpt_4qZ8m1VwXc0L…" \
  -H "Tiempo-Account: acct_01m42yt93ayvyrwr3yczhv6yhw"
```

200Response

```json
{
  "id": "bkg_01m42ytcajvtw8pmzf8dydhmz5",
  "object": "booking",
  "livemode": false,
  "status": "pending",
  "expires_at": "2026-10-04T08:14:53Z",
  "start": "2026-11-16T10:00:00Z",
  "end": "2026-11-16T10:45:00Z",
  "segments": [
    {
      "resource": "res_01m42ytc9b53589z4rp11zedjy",
      "location": null,
      "start": "2026-11-16T10:00:00Z",
      "end": "2026-11-16T10:45:00Z",
      "quantity": 1,
      "buffer_before_minutes": 0,
      "buffer_after_minutes": 10
    }
  ],
  "seats": null,
  "seats_taken": null,
  "conflict_policy": "reject",
  "conflicted": false,
  "conflicts": null,
  "series": null,
  "occurrence_key": null,
  "replaces": null,
  "replaced_by": null,
  "cancellation_reason": null,
  "confirmed_at": null,
  "cancelled_at": null,
  "metadata": {
    "your_booking_id": "apt_8812"
  },
  "created_at": "2026-10-04T07:59:53Z",
  "updated_at": "2026-10-04T07:59:53Z"
}
```

## Reschedule a booking

`POST /v1/bookings/{id}/reschedule`

Moves a booking to new segments in place: same id, and its own current time doesn’t count against it. Sends booking.rescheduled with the previous segments.

Send the business’s id in `Tiempo-Account`.

### Path parameters

-   `id` (string, required)
    
    The object’s id.
    

### Body parameters

-   `segments` (array of objects, required)
    
    The time to hold: one entry per resource and period. Segments can be on different resources and needn’t touch.
    
    -   `resource` (string)
        
        A resource id.
        
    -   `resources` (array of strings)
        
        Candidate resource ids in your order of preference; Tiempo takes the first that fits.
        
    -   `start` (timestamp, required)
        
        An ISO-8601 instant.
        
    -   `end` (timestamp, required)
        
        An ISO-8601 instant, after start.
        
    -   `quantity` (integer)
        
        Units of capacity to take. Defaults to 1 (for blocks, the whole capacity).
        
    -   `location` (string)
        
        A location id.
        
    -   `buffer_before_minutes` (integer)
        
        Minutes the resource is also held before the time (travel, setup), 0–1440. On a booking segment it overrides the resource’s default; the appointment’s start and end don’t change.
        
    -   `buffer_after_minutes` (integer)
        
        Minutes the resource is also held after the time (cleanup, turnaround), 0–1440. On a booking segment it overrides the resource’s default. Buffers must fit in working hours and can’t overlap blocks or other bookings.
        
-   `conflict_policy` (string)
    
    reject (default) refuses time that isn’t free or isn’t working hours. capacity_only ignores working hours, overrides and blocks (staff booking a client in after hours) but still never overlaps another booking. allow places it anyway (a deliberate overbook) and flags it.
    

POST /v1/bookings/{id}/reschedule

```bash
curl -X POST "https://api.tiempo.one/v1/bookings/bkg_01m42ytcajvtw8pmzf8dydhmz5/reschedule" \
  -H "Authorization: Bearer tpt_4qZ8m1VwXc0L…" \
  -H "Tiempo-Account: acct_01m42yt93ayvyrwr3yczhv6yhw" \
  -H "Content-Type: application/json" \
  -d '{
    "segments": [
      {
        "resource": "res_ann",
        "start": "2026-11-16T11:00:00Z",
        "end": "2026-11-16T11:45:00Z"
      }
    ]
  }'
```

200Response

```json
{
  "id": "bkg_01m42ytcajvtw8pmzf8dydhmz5",
  "object": "booking",
  "livemode": false,
  "status": "pending",
  "expires_at": "2026-10-04T08:14:53Z",
  "start": "2026-11-16T10:00:00Z",
  "end": "2026-11-16T10:45:00Z",
  "segments": [
    {
      "resource": "res_01m42ytc9b53589z4rp11zedjy",
      "location": null,
      "start": "2026-11-16T10:00:00Z",
      "end": "2026-11-16T10:45:00Z",
      "quantity": 1,
      "buffer_before_minutes": 0,
      "buffer_after_minutes": 10
    }
  ],
  "seats": null,
  "seats_taken": null,
  "conflict_policy": "reject",
  "conflicted": false,
  "conflicts": null,
  "series": null,
  "occurrence_key": null,
  "replaces": null,
  "replaced_by": null,
  "cancellation_reason": null,
  "confirmed_at": null,
  "cancelled_at": null,
  "metadata": {
    "your_booking_id": "apt_8812"
  },
  "created_at": "2026-10-04T07:59:53Z",
  "updated_at": "2026-10-04T07:59:53Z"
}
```

## Cancel a booking

`POST /v1/bookings/{id}/cancel`

Frees the time straight away. Cancelling a session cancels its attendees.

Send the business’s id in `Tiempo-Account`.

### Path parameters

-   `id` (string, required)
    
    The object’s id.
    

### Body parameters

-   `reason` (string)
    
    Your note, kept on the object and its webhook.
    

POST /v1/bookings/{id}/cancel

```bash
curl -X POST "https://api.tiempo.one/v1/bookings/bkg_01m42ytcajvtw8pmzf8dydhmz5/cancel" \
  -H "Authorization: Bearer tpt_4qZ8m1VwXc0L…" \
  -H "Tiempo-Account: acct_01m42yt93ayvyrwr3yczhv6yhw" \
  -H "Content-Type: application/json" \
  -d '{
    "reason": "customer_request"
  }'
```

200Response

```json
{
  "id": "bkg_01m42ytcajvtw8pmzf8dydhmz5",
  "object": "booking",
  "livemode": false,
  "status": "pending",
  "expires_at": "2026-10-04T08:14:53Z",
  "start": "2026-11-16T10:00:00Z",
  "end": "2026-11-16T10:45:00Z",
  "segments": [
    {
      "resource": "res_01m42ytc9b53589z4rp11zedjy",
      "location": null,
      "start": "2026-11-16T10:00:00Z",
      "end": "2026-11-16T10:45:00Z",
      "quantity": 1,
      "buffer_before_minutes": 0,
      "buffer_after_minutes": 10
    }
  ],
  "seats": null,
  "seats_taken": null,
  "conflict_policy": "reject",
  "conflicted": false,
  "conflicts": null,
  "series": null,
  "occurrence_key": null,
  "replaces": null,
  "replaced_by": null,
  "cancellation_reason": null,
  "confirmed_at": null,
  "cancelled_at": null,
  "metadata": {
    "your_booking_id": "apt_8812"
  },
  "created_at": "2026-10-04T07:59:53Z",
  "updated_at": "2026-10-04T07:59:53Z"
}
```

## Complete a booking

`POST /v1/bookings/{id}/complete`

Records that it happened, or that it’s been paid for: allowed before it starts. The time stays taken until the booking ends; only cancelling frees it.

Send the business’s id in `Tiempo-Account`.

### Path parameters

-   `id` (string, required)
    
    The object’s id.
    

POST /v1/bookings/{id}/complete

```bash
curl -X POST "https://api.tiempo.one/v1/bookings/bkg_01m42ytcajvtw8pmzf8dydhmz5/complete" \
  -H "Authorization: Bearer tpt_4qZ8m1VwXc0L…" \
  -H "Tiempo-Account: acct_01m42yt93ayvyrwr3yczhv6yhw"
```

200Response

```json
{
  "id": "bkg_01m42ytcajvtw8pmzf8dydhmz5",
  "object": "booking",
  "livemode": false,
  "status": "pending",
  "expires_at": "2026-10-04T08:14:53Z",
  "start": "2026-11-16T10:00:00Z",
  "end": "2026-11-16T10:45:00Z",
  "segments": [
    {
      "resource": "res_01m42ytc9b53589z4rp11zedjy",
      "location": null,
      "start": "2026-11-16T10:00:00Z",
      "end": "2026-11-16T10:45:00Z",
      "quantity": 1,
      "buffer_before_minutes": 0,
      "buffer_after_minutes": 10
    }
  ],
  "seats": null,
  "seats_taken": null,
  "conflict_policy": "reject",
  "conflicted": false,
  "conflicts": null,
  "series": null,
  "occurrence_key": null,
  "replaces": null,
  "replaced_by": null,
  "cancellation_reason": null,
  "confirmed_at": null,
  "cancelled_at": null,
  "metadata": {
    "your_booking_id": "apt_8812"
  },
  "created_at": "2026-10-04T07:59:53Z",
  "updated_at": "2026-10-04T07:59:53Z"
}
```

## Mark a booking as a no-show

`POST /v1/bookings/{id}/no_show`

Records that the customer didn’t come. Only once the booking has started (409 booking_not_started before). The time stays taken.

Send the business’s id in `Tiempo-Account`.

### Path parameters

-   `id` (string, required)
    
    The object’s id.
    

POST /v1/bookings/{id}/no_show

```bash
curl -X POST "https://api.tiempo.one/v1/bookings/bkg_01m42ytcajvtw8pmzf8dydhmz5/no_show" \
  -H "Authorization: Bearer tpt_4qZ8m1VwXc0L…" \
  -H "Tiempo-Account: acct_01m42yt93ayvyrwr3yczhv6yhw"
```

200Response

```json
{
  "id": "bkg_01m42ytcajvtw8pmzf8dydhmz5",
  "object": "booking",
  "livemode": false,
  "status": "pending",
  "expires_at": "2026-10-04T08:14:53Z",
  "start": "2026-11-16T10:00:00Z",
  "end": "2026-11-16T10:45:00Z",
  "segments": [
    {
      "resource": "res_01m42ytc9b53589z4rp11zedjy",
      "location": null,
      "start": "2026-11-16T10:00:00Z",
      "end": "2026-11-16T10:45:00Z",
      "quantity": 1,
      "buffer_before_minutes": 0,
      "buffer_after_minutes": 10
    }
  ],
  "seats": null,
  "seats_taken": null,
  "conflict_policy": "reject",
  "conflicted": false,
  "conflicts": null,
  "series": null,
  "occurrence_key": null,
  "replaces": null,
  "replaced_by": null,
  "cancellation_reason": null,
  "confirmed_at": null,
  "cancelled_at": null,
  "metadata": {
    "your_booking_id": "apt_8812"
  },
  "created_at": "2026-10-04T07:59:53Z",
  "updated_at": "2026-10-04T07:59:53Z"
}
```

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)
