> ## Documentation Index
> Fetch the complete documentation index at: https://docs.anny.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Admin Booking Lifecycle

Admin-specific booking operations: status changes, check-in/out, and document generation.

For customer booking management, see [Customer Booking Lifecycle](/developers/guides/customer/booking-lifecycle). For creating bookings, see [Admin Booking Creation](/developers/guides/admin/booking-creation). For general conventions, see [JSON-API Conventions](/developers/guides/json-api-conventions).

***

## Prerequisites

* A valid Bearer token with admin access — see [Authentication](/developers/guides/authentication)
* Organization context (`?o={organization_id}`)

***

## Status Changes

Request path documentation:

* `paths/admin/bookings.yaml` for `PATCH /api/v1/bookings/{booking_id}`
* `paths/admin/bookings.yaml` for `GET /api/v1/bookings/{booking_id}/cancel`

### Accept a Requested Booking

When a booking has status `requested`, accept it by updating the booking status:

```http theme={null}
PATCH /api/v1/bookings/{booking_id}?o={org_id}
```

Example payload:

```json theme={null}
{
	"data": {
		"id": "{booking_id}",
		"type": "bookings",
		"attributes": {
			"status": "accepted"
		}
	}
}
```

### Reject a Requested Booking

Reject a requested booking with the same update endpoint:

```http theme={null}
PATCH /api/v1/bookings/{booking_id}?o={org_id}
```

Example payload:

```json theme={null}
{
	"data": {
		"id": "{booking_id}",
		"type": "bookings",
		"attributes": {
			"status": "rejected"
		}
	}
}
```

### Cancel a Booking

Cancel an accepted or requested booking with the dedicated cancel action:

```http theme={null}
GET /api/v1/bookings/{booking_id}/cancel?o={org_id}
```

This runs the booking cancellation flow. Refunds and invoice adjustments follow the configured cancellation policy.

***

## Check-In / Check-Out

Request path documentation:

* `paths/admin/bookings.yaml` for `POST /api/v1/bookings/{booking_id}/check-in`
* `paths/admin/bookings.yaml` for `POST /api/v1/bookings/{booking_id}/check-out`
* [Scan](/developers/models/scans) for `POST /api/v1/scans` (staff / kiosk scanner)

Record customer arrivals and departures.

### Check-In

```http theme={null}
POST /api/v1/bookings/{booking_id}/check-in?o={org_id}
X-Supports-Dynamic-Form: true
```

Optional body fields:

| Field                    | Type    | Description                                                     |
| ------------------------ | ------- | --------------------------------------------------------------- |
| `latitude` / `longitude` | number  | Required when the resource uses geo check-in                    |
| `form_data`              | object  | Submitted after collecting delayed check-in details (see below) |
| `send_notification`      | boolean | Defaults to `true`                                              |

### Check-Out

```http theme={null}
POST /api/v1/bookings/{booking_id}/check-out?o={org_id}
```

Both endpoints:

* Log a `Scan` record with the timestamp
* Update the booking's check-in/check-out status
* Can be triggered by admin users or via self-service terminals

<Note>
  Resources can be configured with auto-expiry — if a customer doesn't check in within a configured window, the booking expires automatically.
</Note>

### Delayed forms at check-in

Legal documents and custom forms can be configured with collection timing `check_in`. If those details are still missing when you check a booking in, the API does not complete the check-in until the client collects and submits them.

Advertise support for the dynamic check-in form with:

```http theme={null}
X-Supports-Dynamic-Form: true
```

Without that header (and without `form_data`), check-in fails with HTTP 400 and code `scans.check_in_requires_details_unsupported`.

**1. First attempt** — details still required:

```json theme={null}
{
  "meta": {
    "status": "requires_details",
    "form_url": "https://…/api/ui/booking-check-in-form?booking={id}&access_token=…"
  },
  "data": {
    "type": "bookings",
    "id": "{booking_id}",
    "attributes": {
      "check_in_date": null
    }
  }
}
```

**2. Load the form** from `meta.form_url` (`GET /api/ui/booking-check-in-form`). It returns the same dynamic-form shape as checkout (`components`, `validations`), limited to still-missing items (`documents.{uuid}`, `service_custom_fields.{uuid}`).

**3. Re-submit check-in** with the collected values:

```http theme={null}
POST /api/v1/bookings/{booking_id}/check-in?o={org_id}
X-Supports-Dynamic-Form: true

{
  "form_data": {
    "documents": {
      "{document_uuid}": { "accepted": true, "send_copy": false }
    },
    "service_custom_fields": {
      "{field_uuid}": "value"
    }
  }
}
```

On success, `meta.status` is the resulting scan status (for example `valid`) and `check_in_date` is set. Invalid `form_data` returns HTTP 422. Timing / geo / business-rule failures return HTTP 400 with a `scans.*` error code.

### Scanner endpoint (`POST /scans`)

Staff and kiosk clients that create scans by booking code use the same delayed-form flow. Unlike the booking check-in action, submit details only as `data.attributes.meta.form_data` (JSON:API) — top-level `form_data` is ignored.

```http theme={null}
POST /api/v1/scans?o={org_id}&code={booking_code}&scannable_type=bookings
X-Supports-Dynamic-Form: true

{
  "data": {
    "type": "scans",
    "attributes": {
      "scan_type": "check_in"
    }
  }
}
```

| Situation                                             | Result                                                                                                                               |
| ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| Header present, no `meta.form_data`, details pending  | Scan is created with `data.attributes.status: "requires_details"` and `data.attributes.meta.form_url`; booking is **not** checked in |
| Header missing, no `meta.form_data`, details pending  | HTTP 400, `scans.check_in_requires_details_unsupported`                                                                              |
| `data.attributes.meta.form_data` provided (and valid) | Details are persisted, scan resolves to `valid`, booking `check_in_date` is set                                                      |

```http theme={null}
POST /api/v1/scans?o={org_id}&code={booking_code}&scannable_type=bookings
X-Supports-Dynamic-Form: true

{
  "data": {
    "type": "scans",
    "attributes": {
      "scan_type": "check_in",
      "meta": {
        "form_data": {
          "documents": {
            "{document_uuid}": { "accepted": true, "send_copy": false }
          },
          "service_custom_fields": {
            "{field_uuid}": "value"
          }
        }
      }
    }
  }
}
```

See [Scan](/developers/models/scans) for the resource schema and create parameters.

***

## Generating Documents

Generate a PDF or ticket from a document template:

```http theme={null}
GET /api/v1/bookings/{booking_id}/generate-file/{template_id}?o={org_id}
```

| Parameter          | Description                                   |
| ------------------ | --------------------------------------------- |
| `template_id`      | UUID of the document template to use          |
| `override` (query) | `true` to regenerate if a file already exists |

Returns a `files` resource with the generated document.

***

Booking exports are documented with the other admin export endpoints in [Exports](/developers/guides/admin/exports).

***

## Common Errors

| Error                                                 | Cause                                                                                                                  | Solution                                                                     |
| ----------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
| `403` — unauthorized                                  | Insufficient admin permissions                                                                                         | Verify role has booking management permission                                |
| `422` — already checked in                            | Duplicate check-in attempt                                                                                             | Check booking status before check-in                                         |
| `400` — `scans.check_in_requires_details_unsupported` | Delayed check-in details are required but the client did not send `X-Supports-Dynamic-Form: true` (and no `form_data`) | Send the capability header, load `form_url`, then re-submit with `form_data` |
| `422` — invalid `form_data`                           | Missing required signature or custom field                                                                             | Fix validation errors from the check-in form and retry                       |
| `404` — template not found                            | Invalid document template UUID                                                                                         | Verify template exists in the organization                                   |
