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

# Visitor Journey Tracking

> This endpoint returns zone-by-zone journey events for individual visits, including dwell time and zone transitions (entered from / exited to).

### Visit

A **visit** represents a single in-store presence for a device. A visit can include multiple zone events (e.g., Entrance → Produce → Dairy → Checkout).

### Session

A **session** aligns to a visit **per device**.

* A session begins when your Digital Asset (or Wi-Fi logs) is observed in-store and records activity.
* A session ends when activity stops, and no further activity is observed.
* **Multiple interruptions/reopens within a 60-minute window are consolidated** and billed as a single session.

### Zone event

A **zone event** is a segment of the journey where the visitor is observed within a single zone, with:

* entry context (`zone_entered_from`)
* exit context (`zone_exited_to`)
* dwell time (`dwell_time_seconds`)

## Resource \[GET]

`/bi/visit-journey-events/`

This resource supports pagination. Due to increased data volume, pagination allows fetching results in batches (pages) for a specified time interval.

***

## URL Parameters

* `store_code` — *Optional*\
  Filter results to a single store.
* `datetime_gte` — *Required*\
  Start datetime (UTC) inclusive. Format: ISO 8601.
* `datetime_lte` — *Required*\
  End datetime (UTC) inclusive. Format: ISO 8601.
* `page_size` — *Optional*\
  Number of results per page.\
  **Default:** 1000, **Max:** 10000
* `page` — *Optional*\
  Page number (used when paginating).

> **Note:** For large intervals, prefer daily windows (e.g., 24h) and paginate.

***

## Response

The response is paginated:

* `count` is the total number of results across the query.
* `next` and `previous` are URLs to fetch the adjacent pages.
* `results` is an array of **zone events**.

Each object in `results` contains:

* `session_id` — *String*\
  Session identifier (aligned to “visit per device”, stitched within 60 minutes).
* `visit_id` — *String*\
  Visit identifier (store visit per device).
* `user_id` — *String | null*\
  User identifier (if available, e.g., logged-in app user). May be `null`.
* `device_id` — *String*\
  Pseudonymous device identifier (privacy-safe token).
* `store_name` — *String*\
  Store name.
* `store_code` — *String*\
  Store code.
* `zone_name` — *String*\
  Human-readable zone name.
* `zone_serial_code` — *String*\
  Internal zone code used for stable referencing across systems.
* `zone_entered_from` — *String | null*\
  Previous zone label. `null` if first event in the visit.
* `zone_exited_to` — *String | null*\
  Next zone label. `null` if last event in the visit.
* `dwell_time_seconds` — *Integer*\
  Time spent in the zone (seconds).
* `event_start` — *String*\
  Zone event start timestamp (ISO 8601 UTC).
* `event_end` — *String*\
  Zone event end timestamp (ISO 8601 UTC).
* `source` — *String*\
  Source of observation, e.g. `app_ble`, `wifi`, `camera_fused`.

***

### Example response

```json theme={null}
{
  "count": 6,
  "next": null,
  "previous": null,
  "results": [
    {
      "session_id": "ses_2c7e41b9f0d84c7a",
      "visit_id": "vst_8f2c9a1d3b7a4c1e",
      "user_id": "usr_4a91d2c8",
      "device_id": "dev_9b3f1c2a7e",
      "date_of_visit": "2025-08-12",
      "store_name": "SuperMart Downtown",
      "store_code": "SM-001",
      "zone_name": "Entrance & Promotions",
      "zone_serial_code": "L0-ENT-PRO-001",
      "zone_entered_from": "Outside",
      "zone_exited_to": "Fresh Produce",
      "dwell_time_seconds": 190,
      "event_start": "2025-08-12T13:00:00Z",
      "event_end": "2025-08-12T13:03:10Z",
      "source": "app_sdk"
    },
    {
      "session_id": "ses_2c7e41b9f0d84c7a",
      "visit_id": "vst_8f2c9a1d3b7a4c1e",
      "user_id": "usr_4a91d2c8",
      "device_id": "dev_9b3f1c2a7e",
      "date_of_visit": "2025-08-12",
      "store_name": "SuperMart Downtown",
      "store_code": "SM-001",
      "zone_name": "Fresh Produce",
      "zone_serial_code": "L0-PRD-FRU-014",
      "zone_entered_from": "Entrance & Promotions",
      "zone_exited_to": "Bakery",
      "dwell_time_seconds": 540,
      "event_start": "2025-08-12T13:03:10Z",
      "event_end": "2025-08-12T13:12:10Z",
      "source": "app_sdk"
    },
    {
      "session_id": "ses_2c7e41b9f0d84c7a",
      "visit_id": "vst_8f2c9a1d3b7a4c1e",
      "user_id": "usr_4a91d2c8",
      "device_id": "dev_9b3f1c2a7e",
      "date_of_visit": "2025-08-12",
      "store_name": "SuperMart Downtown",
      "store_code": "SM-001",
      "zone_name": "Bakery",
      "zone_serial_code": "L0-BKY-BRD-006",
      "zone_entered_from": "Fresh Produce",
      "zone_exited_to": "Dairy",
      "dwell_time_seconds": 310,
      "event_start": "2025-08-12T13:12:10Z",
      "event_end": "2025-08-12T13:17:20Z",
      "source": "app_sdk"
    },
    {
      "session_id": "ses_2c7e41b9f0d84c7a",
      "visit_id": "vst_8f2c9a1d3b7a4c1e",
      "user_id": "usr_4a91d2c8",
      "device_id": "dev_9b3f1c2a7e",
      "date_of_visit": "2025-08-12",
      "store_name": "SuperMart Downtown",
      "store_code": "SM-001",
      "zone_name": "Dairy",
      "zone_serial_code": "L0-DRY-MLK-022",
      "zone_entered_from": "Bakery",
      "zone_exited_to": "Household & Cleaning",
      "dwell_time_seconds": 460,
      "event_start": "2025-08-12T13:17:20Z",
      "event_end": "2025-08-12T13:25:00Z",
      "source": "app_sdk"
    },
    {
      "session_id": "ses_2c7e41b9f0d84c7a",
      "visit_id": "vst_8f2c9a1d3b7a4c1e",
      "user_id": "usr_4a91d2c8",
      "device_id": "dev_9b3f1c2a7e",
      "date_of_visit": "2025-08-12",
      "store_name": "SuperMart Downtown",
      "store_code": "SM-001",
      "zone_name": "Household & Cleaning",
      "zone_serial_code": "L0-HOU-CLN-031",
      "zone_entered_from": "Dairy",
      "zone_exited_to": "Checkout Queue",
      "dwell_time_seconds": 380,
      "event_start": "2025-08-12T13:25:00Z",
      "event_end": "2025-08-12T13:31:20Z",
      "source": "app_sdk"
    },
    {
      "session_id": "ses_2c7e41b9f0d84c7a",
      "visit_id": "vst_8f2c9a1d3b7a4c1e",
      "user_id": "usr_4a91d2c8",
      "device_id": "dev_9b3f1c2a7e",
      "date_of_visit": "2025-08-12",
      "store_name": "SuperMart Downtown",
      "store_code": "SM-001",
      "zone_name": "Checkout Queue",
      "zone_serial_code": "L0-CHK-QUE-001",
      "zone_entered_from": "Household & Cleaning",
      "zone_exited_to": "Cashlines",
      "dwell_time_seconds": 260,
      "event_start": "2025-08-12T13:31:20Z",
      "event_end": "2025-08-12T13:35:40Z",
      "source": "app_sdk"
    }
  ]
}
```

## Notes and common questions

**Does one visit always equal one session?**\
For billing and analytics, we treat a **session as a visit per device**, with **60-minute stitching** to avoid multiple app opens during a single visit being counted multiple times.

\*\*Can \*\*`user_id`**be missing?** \
Yes. If the visitor is not logged in, or if the integration uses privacy-safe pseudonymous identifiers only, `user_id` may be `null`.

\*\*What does \*\*`source`**mean?** \
It indicates the signal that produced the event (e.g., Wi-Fi telemetry, app BLE, camera-derived, or fused).
