> ## 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.

# Scan

Create check-in and check-out scans for bookings (staff scanner, kiosk, or display). For the booking action endpoints, see [Admin Booking Lifecycle](/developers/guides/admin/booking-lifecycle).

***

## Create a scan

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

{
  "data": {
    "type": "scans",
    "attributes": {
      "scan_type": "check_in",
      "device_identifier": "front-desk-scanner",
      "latitude": null,
      "longitude": null
    }
  }
}
```

### Query parameters

| Parameter           | Required | Description                                  |
| ------------------- | -------- | -------------------------------------------- |
| `o`                 | Yes      | Organization ID                              |
| `code`              | Yes      | Booking ticket / QR code                     |
| `scannable_type`    | No       | Defaults to `bookings`                       |
| `allowed_resources` | No       | Restrict which base resources may be scanned |

### Attributes

| Attribute                | Required | Description                                                           |
| ------------------------ | -------- | --------------------------------------------------------------------- |
| `scan_type`              | Yes      | `check_in` or `check_out`                                             |
| `device_identifier`      | No       | Optional device label                                                 |
| `latitude` / `longitude` | No       | Geo coordinates when required by the resource                         |
| `meta.form_data`         | No       | Delayed check-in details (JSON:API only — not a top-level body field) |

On success the response is a `scans` resource. A successful check-in also updates the booking's `check_in_date` via the scan's presence-date sync.

***

## Statuses

| Status                   | Meaning                                                              |
| ------------------------ | -------------------------------------------------------------------- |
| `valid`                  | Scan succeeded; for check-in the booking is checked in               |
| `requires_details`       | Check-in details (legal documents / custom fields) are still missing |
| `scanned`                | Already checked in (previous successful check-in exists)             |
| `too_early` / `too_late` | Outside the configured check-in window                               |
| `unpaid`                 | Booking order is not fully paid                                      |
| `invalid`                | Booking status does not allow check-in                               |
| `resource_not_allowed`   | Booking resource is outside `allowed_resources`                      |

***

## Delayed check-in form data

When a booking still needs check-in-timed legal documents or custom fields, send `X-Supports-Dynamic-Form: true`.

Without `data.attributes.meta.form_data`:

* supported client → scan is created with `data.attributes.status: "requires_details"` and `data.attributes.meta.form_url`
* unsupported client → HTTP 400, `scans.check_in_requires_details_unsupported`

Fetch the form from `data.attributes.meta.form_url`, then create another scan with the collected values under `data.attributes.meta.form_data`.

Top-level `form_data` is **not** accepted on `POST /scans` (unlike the booking check-in action). Submit details only via JSON:API attributes:

```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"
          }
        }
      }
    }
  }
}
```

The `form_data` object uses the same shape as `POST /api/v1/bookings/{id}/check-in`. Invalid values return HTTP 422. Submitted `form_data` is processed and not persisted on the scan record.

***

## Related guides

* [Admin Booking Lifecycle](/developers/guides/admin/booking-lifecycle) — booking check-in/out actions and delayed forms
* [Display Integration](/developers/guides/internal/display-integration) — room displays that check bookings in/out
