# How Parklio works

> A five-minute mental model: what's in an account, how a command reaches a device, and
> why results arrive asynchronously.

## The pieces

```text title="Account structure"
Account
├── Account users (Super Admin, Admin, Operator)
├── API tokens
└── Lots
    ├── Gateways
    └── Zones
        ├── Products (barrier, gate, chain, bollard, brain)
        └── LPR cameras
```

- **Account:** your organization. Everything below belongs to it.
- **Lot:** a parking location. A lot holds zones and Gateways.
- **Zone:** a part of a lot, for example a level or a pricing area. Products and LPR
  cameras sit in a zone.
- **Product:** the hardware you control. Products speak only **Bluetooth (BLE)**.
- **Gateway:** an on-site box that connects to the Parklio cloud (over Ethernet or a
  mobile network) and to nearby products over Bluetooth. It's how the cloud reaches a
  product.

More detail in [Data model](/concepts/data-model).

Products and Gateways are added to an account with the **Parklio Connect app**, which
pairs each device with your account. The API has no pairing endpoints.

## Two ways to reach a product

| | Cloud path | Bluetooth path |
| --- | --- | --- |
| How | Your backend → Parklio API → Gateway → product over BLE | A phone with your app (built with the Parklio SDK) → product over BLE |
| Credentials | Your API token | An **operation token** your backend creates, which the app hands to the product |
| Needs a Gateway | Yes, online and in range | No |
| Needs internet at the product | Yes (at the Gateway) | No, once the app has the token |
| Result | Asynchronous, as a realtime event | Directly in the app |
| Start with | [Quickstart](/get-started/quickstart) | [SDK](/sdk) |

Parklio's own tools use the same paths: Zapier and the web app (PMS) go through the
cloud, and the Connect app talks to products over Bluetooth.

## Why the cloud path is asynchronous

When you send a command, such as
[`POST /v2/products/{id}/state`](/api/endpoints/products-change-state) with
`{"operation": "open"}`:

1. The API checks it can run the command, then answers **straight away** with an
   `event_id`. The device hasn't moved yet.
2. The API sends the command through the Gateways that recently saw the product,
   **one at a time, strongest Bluetooth signal first, waiting up to 30 seconds for
   each**.
3. The Gateway relays it to the product over Bluetooth, and the product reports back.
4. The API pushes the result to you over the realtime connection: a `lot_change` event
   with your `event_id` when it worked, or a `gateway_error` event with your `event_id`
   when it didn't.

So a cloud integration needs **both** the REST API (to send commands) and the
[realtime connection](/realtime/connecting) (to learn the result). Connect to realtime
first. Details in [Asynchronous operations](/concepts/asynchronous-operations).

## Status flows the other way too

Products advertise their state over Bluetooth all the time: open or closed, battery,
errors such as a jammed arm or a dirty sensor, and on a barrier whether a car is on top.
Gateways pick these up and send them to the API, which updates the product and pushes a
`lot_change` event (with no `event_id`, since nobody requested it). A product is
`online` while a connected Gateway can see it, and `offline` otherwise.

## Occupancy

Parklio can track which parking places are free or occupied, using cameras and on-site
processing. Each lot is different, so detection is set up by Parklio's technicians:
they plan camera coverage from lot photos and blueprints, then map the parking places
and tie them to your account. You read the results; you don't configure detection.

![Parking detection setup](/img/diagrams/parking_detection.svg)

From there:

- Lots and zones carry `spot_count` and `occupied_count`; read them with
  [`GET /v2/lots/{id}`](/api/endpoints/lots-find-one).
- Each parking place has an `occupancy_status` of `free`, `occupied` or `unknown`; list
  them with [`GET /v2/parking-places`](/api/endpoints/parking-places-find-all).
- Changes arrive live as realtime events; see [Events](/realtime/events).

## Next

- [Choose your path](/get-started/choose-your-path): which integration fits your product.
- [What you need](/get-started/what-you-need): the account, subscriptions and hardware.
