DocsIDarsa.technology

Docs / AI Box And Video Analytics Software / API Reference

Smart Retail Counter API

The Smart Retail Counter API: store traffic from the door and floor cameras. It gives entries, passersby and the capture rate, visits and dwell per zone, the dwell heatmaps (per zone and hour, and over each camera's floor), queue length and measured waits, the visitor log, and the store's point-of-sale (POS) transactions for the conversion rate. It also sets the cameras' door and staff lines.

Personal data. Counting is anonymous: the API gives no identity and no image.

Calling the API

The same as the platform API: an API account's token as Authorization: Bearer <API_KEY>. Site and camera ids come from the platform API (GET /api/v1/sites, GET /api/v1/cameras). Each operation says who can call it and which scopes it needs. Errors, times, paging and the rate limit follow the platform API.

A Feed With Its Own Credential

The store's POS can send its transactions itself, signed with the site's POS key (Standard Webhooks signatures); an admin of the site makes the key on the dashboard.

1.0.0

Store Traffic

Headline figures, trend, zones, the zone and floor heatmaps, and queues.

Headline Numbers Of A Period

GET/sites/{id}/overview

Who can call it: An account with a role (viewer or admin) on the site. Token scopes: read.

Parameters

FieldTypeDescription
idrequired pathinteger
fromrequired querydate-time
torequired querydate-time

Responses

StatusMeaning
200OK
401RFC 9457 problem
403RFC 9457 problem
404RFC 9457 problem
409RFC 9457 problem
422RFC 9457 problem
502RFC 9457 problem

Request

curl -s -X GET "https://<BOX_HOST>/api/retail/v1/sites/1/overview?from=2026-11-01T00%3A00%3A00%2B07%3A00&to=2026-11-02T00%3A00%3A00%2B07%3A00" \
  -H "Authorization: Bearer <API_KEY>"
import requests

r = requests.get(
    "https://<BOX_HOST>/api/retail/v1/sites/1/overview?from=2026-11-01T00%3A00%3A00%2B07%3A00&to=2026-11-02T00%3A00%3A00%2B07%3A00",
    headers={"Authorization": "Bearer <API_KEY>"},
)
print(r.status_code, r.text)
const r = await fetch("https://<BOX_HOST>/api/retail/v1/sites/1/overview?from=2026-11-01T00%3A00%3A00%2B07%3A00&to=2026-11-02T00%3A00%3A00%2B07%3A00", {
  method: "GET",
  headers: { "Authorization": "Bearer <API_KEY>" },
});
console.log(r.status, await r.text());

Response 200

{
  "entries": 1284,
  "exits": 1241,
  "passersby": 5310,
  "capture_rate": 19.5,
  "visits": 1190,
  "engaged_rate": 41.3,
  "checkout_rate": 28.7,
  "avg_dwell_min": 11.4,
  "conversion": {
    "value": 24.1,
    "source": "pos",
    "transactions": 309
  },
  "in_store_now": 37,
  "queues_now": [
    {
      "zone": "Checkout",
      "length": 4,
      "est_wait_s": 95,
      "at": "2026-11-02T10:58:00Z",
      "long_queue_length": 6
    }
  ],
  "repeat_share": null,
  "vip_visits": 0,
  "demographics": {
    "cells": [
      {
        "age_band": "25-34",
        "gender": "female",
        "visits": 214,
        "share": 22.3
      }
    ],
    "unknown_visits": 231
  },
  "occupancy_limit": 120,
  "long_queue_length": 6,
  "store_hours": {
    "open": "10:00",
    "close": "22:00"
  }
}

Entries, Passersby And Visits Per Hour Or Day

GET/sites/{id}/trend

Who can call it: An account with a role (viewer or admin) on the site. Token scopes: read.

Parameters

FieldTypeDescription
idrequired pathinteger
fromrequired querydate-time
torequired querydate-time
bucket queryenumhour, day

Responses

StatusMeaning
200OK
401RFC 9457 problem
403RFC 9457 problem
404RFC 9457 problem
409RFC 9457 problem
422RFC 9457 problem
502RFC 9457 problem

Request

curl -s -X GET "https://<BOX_HOST>/api/retail/v1/sites/1/trend?from=2026-11-01T00%3A00%3A00%2B07%3A00&to=2026-11-02T00%3A00%3A00%2B07%3A00&bucket=hour" \
  -H "Authorization: Bearer <API_KEY>"
import requests

r = requests.get(
    "https://<BOX_HOST>/api/retail/v1/sites/1/trend?from=2026-11-01T00%3A00%3A00%2B07%3A00&to=2026-11-02T00%3A00%3A00%2B07%3A00&bucket=hour",
    headers={"Authorization": "Bearer <API_KEY>"},
)
print(r.status_code, r.text)
const r = await fetch("https://<BOX_HOST>/api/retail/v1/sites/1/trend?from=2026-11-01T00%3A00%3A00%2B07%3A00&to=2026-11-02T00%3A00%3A00%2B07%3A00&bucket=hour", {
  method: "GET",
  headers: { "Authorization": "Bearer <API_KEY>" },
});
console.log(r.status, await r.text());

Response 200

{
  "bucket": "hour",
  "buckets": [
    {
      "start": "2026-11-02T08:00:00Z",
      "entries": 12,
      "passersby": 12,
      "visits": 12,
      "engaged": 12,
      "checkout": 12,
      "capture_rate": 12
    }
  ]
}

Visits And Dwell Per Zone

GET/sites/{id}/zones

Who can call it: An account with a role (viewer or admin) on the site. Token scopes: read.

Parameters

FieldTypeDescription
idrequired pathinteger
fromrequired querydate-time
torequired querydate-time

Responses

StatusMeaning
200OK
401RFC 9457 problem
403RFC 9457 problem
404RFC 9457 problem
409RFC 9457 problem
422RFC 9457 problem
502RFC 9457 problem

Request

curl -s -X GET "https://<BOX_HOST>/api/retail/v1/sites/1/zones?from=2026-11-01T00%3A00%3A00%2B07%3A00&to=2026-11-02T00%3A00%3A00%2B07%3A00" \
  -H "Authorization: Bearer <API_KEY>"
import requests

r = requests.get(
    "https://<BOX_HOST>/api/retail/v1/sites/1/zones?from=2026-11-01T00%3A00%3A00%2B07%3A00&to=2026-11-02T00%3A00%3A00%2B07%3A00",
    headers={"Authorization": "Bearer <API_KEY>"},
)
print(r.status_code, r.text)
const r = await fetch("https://<BOX_HOST>/api/retail/v1/sites/1/zones?from=2026-11-01T00%3A00%3A00%2B07%3A00&to=2026-11-02T00%3A00%3A00%2B07%3A00", {
  method: "GET",
  headers: { "Authorization": "Bearer <API_KEY>" },
});
console.log(r.status, await r.text());

Response 200

{
  "zones": [
    {
      "zone": "Loading bay",
      "kind": "default",
      "visits": 12,
      "avg_dwell_s": 60,
      "total_dwell_min": 12
    }
  ]
}

Dwell Minutes Per Zone And Local Hour

GET/sites/{id}/heatmap

Who can call it: An account with a role (viewer or admin) on the site. Token scopes: read.

Parameters

FieldTypeDescription
idrequired pathinteger
fromrequired querydate-time
torequired querydate-time

Responses

StatusMeaning
200OK
401RFC 9457 problem
403RFC 9457 problem
404RFC 9457 problem
409RFC 9457 problem
422RFC 9457 problem
502RFC 9457 problem

Request

curl -s -X GET "https://<BOX_HOST>/api/retail/v1/sites/1/heatmap?from=2026-11-01T00%3A00%3A00%2B07%3A00&to=2026-11-02T00%3A00%3A00%2B07%3A00" \
  -H "Authorization: Bearer <API_KEY>"
import requests

r = requests.get(
    "https://<BOX_HOST>/api/retail/v1/sites/1/heatmap?from=2026-11-01T00%3A00%3A00%2B07%3A00&to=2026-11-02T00%3A00%3A00%2B07%3A00",
    headers={"Authorization": "Bearer <API_KEY>"},
)
print(r.status_code, r.text)
const r = await fetch("https://<BOX_HOST>/api/retail/v1/sites/1/heatmap?from=2026-11-01T00%3A00%3A00%2B07%3A00&to=2026-11-02T00%3A00%3A00%2B07%3A00", {
  method: "GET",
  headers: { "Authorization": "Bearer <API_KEY>" },
});
console.log(r.status, await r.text());

Response 200

{
  "zones": [
    "Loading bay"
  ],
  "hours": 12,
  "dwell_min": [
    [
      12
    ]
  ]
}

One Camera's Floor Heatmap: Seconds Per Cell Of The Grid Over Its Floor Area

GET/sites/{id}/floor-heatmap

The site's cameras with a floor area (still on the site) and, for camera (else the first), its floor area as last reported: the grid size, the polygon (normalised frame coordinates) and the seconds shoppers stood in each cell, added up over the hours that overlap the period (seconds[row][col], 0 for none; cells of the grid's box outside the polygon stay 0). Anonymous: no track, no image. floor is null when no camera of the site has a floor area. 404 floor_not_found: the camera has none on this site.

Who can call it: An account with a role (viewer or admin) on the site. Token scopes: read.

Parameters

FieldTypeDescription
idrequired pathinteger
fromrequired querydate-time
torequired querydate-time
camera queryintegerThe camera (one of cameras); default: the first

Responses

StatusMeaning
200OK
401RFC 9457 problem
403RFC 9457 problem
404RFC 9457 problem
409RFC 9457 problem
422RFC 9457 problem
502RFC 9457 problem

Request

curl -s -X GET "https://<BOX_HOST>/api/retail/v1/sites/1/floor-heatmap?from=2026-11-01T00%3A00%3A00%2B07%3A00&to=2026-11-02T00%3A00%3A00%2B07%3A00&camera=1" \
  -H "Authorization: Bearer <API_KEY>"
import requests

r = requests.get(
    "https://<BOX_HOST>/api/retail/v1/sites/1/floor-heatmap?from=2026-11-01T00%3A00%3A00%2B07%3A00&to=2026-11-02T00%3A00%3A00%2B07%3A00&camera=1",
    headers={"Authorization": "Bearer <API_KEY>"},
)
print(r.status_code, r.text)
const r = await fetch("https://<BOX_HOST>/api/retail/v1/sites/1/floor-heatmap?from=2026-11-01T00%3A00%3A00%2B07%3A00&to=2026-11-02T00%3A00%3A00%2B07%3A00&camera=1", {
  method: "GET",
  headers: { "Authorization": "Bearer <API_KEY>" },
});
console.log(r.status, await r.text());

Response 200

{
  "cameras": [
    {
      "camera": 12,
      "zone": "Loading bay",
      "name": "Main gate"
    }
  ],
  "floor": {
    "camera": 12,
    "zone": "Loading bay",
    "name": "Main gate",
    "cols": 12,
    "rows": 12,
    "polygon": [
      [
        12,
        12
      ]
    ],
    "seconds": [
      [
        12
      ]
    ],
    "total_s": 60,
    "max_s": 60,
    "last_report": "2026-11-02T08:00:00Z"
  }
}

Queue Length And Measured Wait Per Hour Or Day

GET/sites/{id}/queues

Who can call it: An account with a role (viewer or admin) on the site. Token scopes: read.

Parameters

FieldTypeDescription
idrequired pathinteger
fromrequired querydate-time
torequired querydate-time
bucket queryenumhour, day

Responses

StatusMeaning
200OK
401RFC 9457 problem
403RFC 9457 problem
404RFC 9457 problem
409RFC 9457 problem
422RFC 9457 problem
502RFC 9457 problem

Request

curl -s -X GET "https://<BOX_HOST>/api/retail/v1/sites/1/queues?from=2026-11-01T00%3A00%3A00%2B07%3A00&to=2026-11-02T00%3A00%3A00%2B07%3A00&bucket=hour" \
  -H "Authorization: Bearer <API_KEY>"
import requests

r = requests.get(
    "https://<BOX_HOST>/api/retail/v1/sites/1/queues?from=2026-11-01T00%3A00%3A00%2B07%3A00&to=2026-11-02T00%3A00%3A00%2B07%3A00&bucket=hour",
    headers={"Authorization": "Bearer <API_KEY>"},
)
print(r.status_code, r.text)
const r = await fetch("https://<BOX_HOST>/api/retail/v1/sites/1/queues?from=2026-11-01T00%3A00%3A00%2B07%3A00&to=2026-11-02T00%3A00%3A00%2B07%3A00&bucket=hour", {
  method: "GET",
  headers: { "Authorization": "Bearer <API_KEY>" },
});
console.log(r.status, await r.text());

Response 200

{
  "bucket": "hour",
  "samples": [
    {
      "start": "2026-11-02T08:00:00Z",
      "zone": "Loading bay",
      "avg_length": 12,
      "max_length": 12,
      "avg_wait_s": 60
    }
  ]
}

How Often Visits Are Followed Across Cameras, Per Hour And In Total

GET/sites/{id}/journey-stats

A visit is followed across the store's cameras by the shopper's appearance: the door camera opens it, a track on a camera without a door joins it when it looks like the same shopper, and the door closes it (or it ends 20 minutes after the last sighting). These counts show how often that joining happens: joined_share is the share of the tracks on cameras without a door that joined a visit; the others became visits of their own, seen only inside. Counted per UTC hour. Anonymous: counts only.

Who can call it: An account with a role (viewer or admin) on the site. Token scopes: read.

Parameters

FieldTypeDescription
idrequired pathinteger
fromrequired querydate-time
torequired querydate-time

Responses

StatusMeaning
200OK
401RFC 9457 problem
403RFC 9457 problem
404RFC 9457 problem
409RFC 9457 problem
422RFC 9457 problem
502RFC 9457 problem

Request

curl -s -X GET "https://<BOX_HOST>/api/retail/v1/sites/1/journey-stats?from=2026-11-01T00%3A00%3A00%2B07%3A00&to=2026-11-02T00%3A00%3A00%2B07%3A00" \
  -H "Authorization: Bearer <API_KEY>"
import requests

r = requests.get(
    "https://<BOX_HOST>/api/retail/v1/sites/1/journey-stats?from=2026-11-01T00%3A00%3A00%2B07%3A00&to=2026-11-02T00%3A00%3A00%2B07%3A00",
    headers={"Authorization": "Bearer <API_KEY>"},
)
print(r.status_code, r.text)
const r = await fetch("https://<BOX_HOST>/api/retail/v1/sites/1/journey-stats?from=2026-11-01T00%3A00%3A00%2B07%3A00&to=2026-11-02T00%3A00%3A00%2B07%3A00", {
  method: "GET",
  headers: { "Authorization": "Bearer <API_KEY>" },
});
console.log(r.status, await r.text());

Response 200

{
  "from": "2026-11-02T08:00:00Z",
  "to": "2026-11-02T08:00:00Z",
  "totals": {
    "opened": 12,
    "joined": 12,
    "unjoined": 12,
    "closed_door": 12,
    "timed_out": 12
  },
  "joined_share": 12,
  "hours": [
    {
      "start": "2026-11-02T08:00:00Z",
      "opened": 12,
      "joined": 12,
      "unjoined": 12,
      "closed_door": 12,
      "timed_out": 12,
      "joined_share": 12
    }
  ]
}

Visitor Log

Every visit, newest first, and its export.

The Visitor Log, Newest First, Paged

GET/sites/{id}/logs

Who can call it: An account with a role (viewer or admin) on the site. Token scopes: read.

Parameters

FieldTypeDescription
idrequired pathinteger
fromrequired querydate-time
torequired querydate-time
limit queryinteger
before querystring

Responses

StatusMeaning
200OK
401RFC 9457 problem
403RFC 9457 problem
404RFC 9457 problem
409RFC 9457 problem
422RFC 9457 problem
502RFC 9457 problem

Request

curl -s -X GET "https://<BOX_HOST>/api/retail/v1/sites/1/logs?from=2026-11-01T00%3A00%3A00%2B07%3A00&to=2026-11-02T00%3A00%3A00%2B07%3A00&limit=50&before=2026-11-02T08%3A00%3A00Z" \
  -H "Authorization: Bearer <API_KEY>"
import requests

r = requests.get(
    "https://<BOX_HOST>/api/retail/v1/sites/1/logs?from=2026-11-01T00%3A00%3A00%2B07%3A00&to=2026-11-02T00%3A00%3A00%2B07%3A00&limit=50&before=2026-11-02T08%3A00%3A00Z",
    headers={"Authorization": "Bearer <API_KEY>"},
)
print(r.status_code, r.text)
const r = await fetch("https://<BOX_HOST>/api/retail/v1/sites/1/logs?from=2026-11-01T00%3A00%3A00%2B07%3A00&to=2026-11-02T00%3A00%3A00%2B07%3A00&limit=50&before=2026-11-02T08%3A00%3A00Z", {
  method: "GET",
  headers: { "Authorization": "Bearer <API_KEY>" },
});
console.log(r.status, await r.text());

Response 200

{
  "items": [
    {
      "id": "31:7712",
      "entered": "2026-11-02T10:31:02Z",
      "exited": "2026-11-02T10:44:40Z",
      "dwell_s": 818,
      "engaged": true,
      "reached_checkout": true,
      "age_band": "25-34",
      "gender": "female",
      "repeat_visitor": null,
      "entry_line": "Main door",
      "cameras": [
        31,
        32
      ],
      "zones": [
        {
          "zone": "Aisle 2",
          "kind": "display",
          "dwell_s": 240
        }
      ],
      "path": [
        {
          "camera": 31,
          "camera_name": "Main door",
          "entered": "2026-11-02T10:31:02Z",
          "dwell_s": 95,
          "zones": []
        },
        {
          "camera": 32,
          "camera_name": "Aisles",
          "entered": "2026-11-02T10:32:37Z",
          "dwell_s": 723,
          "zones": [
            {
              "zone": "Aisle 2",
              "kind": "display",
              "entered": "2026-11-02T10:35:10Z",
              "dwell_s": 240
            }
          ]
        }
      ]
    }
  ],
  "next_before": "2026-11-02T10:31:02Z"
}

The Visitor Log Of A Period As CSV Or XLSX (Times In The Site's Time Zone, At Most 20 000 Rows; The Path Column Lists Each Visit's Cameras In Order, With Their Zones)

GET/sites/{id}/logs/export

Who can call it: An account with a role (viewer or admin) on the site. Token scopes: read, export.

Parameters

FieldTypeDescription
idrequired pathinteger
fromrequired querydate-time
torequired querydate-time
format queryenumcsv, xlsx
language queryenumen, id

Responses

StatusMeaning
200the file
401RFC 9457 problem
403RFC 9457 problem
404RFC 9457 problem
409RFC 9457 problem
422RFC 9457 problem
502RFC 9457 problem

Request

curl -s -X GET "https://<BOX_HOST>/api/retail/v1/sites/1/logs/export?from=2026-11-01T00%3A00%3A00%2B07%3A00&to=2026-11-02T00%3A00%3A00%2B07%3A00&format=csv&language=en" \
  -H "Authorization: Bearer <API_KEY>"
import requests

r = requests.get(
    "https://<BOX_HOST>/api/retail/v1/sites/1/logs/export?from=2026-11-01T00%3A00%3A00%2B07%3A00&to=2026-11-02T00%3A00%3A00%2B07%3A00&format=csv&language=en",
    headers={"Authorization": "Bearer <API_KEY>"},
)
print(r.status_code, r.text)
const r = await fetch("https://<BOX_HOST>/api/retail/v1/sites/1/logs/export?from=2026-11-01T00%3A00%3A00%2B07%3A00&to=2026-11-02T00%3A00%3A00%2B07%3A00&format=csv&language=en", {
  method: "GET",
  headers: { "Authorization": "Bearer <API_KEY>" },
});
console.log(r.status, await r.text());

Point Of Sale

Transactions from the store's POS (signed feed or CSV) for the conversion rate.

Upload POS Transactions As CSV (start,end,transactions)

POST/sites/{id}/pos/upload

Who can call it: An account that is an admin of the site. Token scopes: write.

Parameters

FieldTypeDescription
idrequired pathinteger

Responses

StatusMeaning
200OK
401RFC 9457 problem
403RFC 9457 problem
404RFC 9457 problem
409RFC 9457 problem
422RFC 9457 problem
502RFC 9457 problem

Request

curl -s -X POST "https://<BOX_HOST>/api/retail/v1/sites/1/pos/upload" \
  -H "Authorization: Bearer <API_KEY>"
import requests

r = requests.post(
    "https://<BOX_HOST>/api/retail/v1/sites/1/pos/upload",
    headers={"Authorization": "Bearer <API_KEY>"},
)
print(r.status_code, r.text)
const r = await fetch("https://<BOX_HOST>/api/retail/v1/sites/1/pos/upload", {
  method: "POST",
  headers: { "Authorization": "Bearer <API_KEY>" },
});
console.log(r.status, await r.text());

Response 200

{
  "stored": 12
}

The Site's POS Intervals Of A Period, And Whether It Has A Key

GET/sites/{id}/pos

Who can call it: An account with a role (viewer or admin) on the site. Token scopes: read.

Parameters

FieldTypeDescription
idrequired pathinteger
fromrequired querydate-time
torequired querydate-time

Responses

StatusMeaning
200OK
401RFC 9457 problem
403RFC 9457 problem
404RFC 9457 problem
409RFC 9457 problem
422RFC 9457 problem
502RFC 9457 problem

Request

curl -s -X GET "https://<BOX_HOST>/api/retail/v1/sites/1/pos?from=2026-11-01T00%3A00%3A00%2B07%3A00&to=2026-11-02T00%3A00%3A00%2B07%3A00" \
  -H "Authorization: Bearer <API_KEY>"
import requests

r = requests.get(
    "https://<BOX_HOST>/api/retail/v1/sites/1/pos?from=2026-11-01T00%3A00%3A00%2B07%3A00&to=2026-11-02T00%3A00%3A00%2B07%3A00",
    headers={"Authorization": "Bearer <API_KEY>"},
)
print(r.status_code, r.text)
const r = await fetch("https://<BOX_HOST>/api/retail/v1/sites/1/pos?from=2026-11-01T00%3A00%3A00%2B07%3A00&to=2026-11-02T00%3A00%3A00%2B07%3A00", {
  method: "GET",
  headers: { "Authorization": "Bearer <API_KEY>" },
});
console.log(r.status, await r.text());

Response 200

{
  "key": true,
  "intervals": [
    {
      "start": "2026-11-02T08:00:00Z",
      "end": "2026-11-02T08:00:00Z",
      "transactions": 12,
      "source": "pos"
    }
  ]
}

POS Transactions Sent By The Store's POS, Signed With The Site's Key

POST/pos/{site}

The POS signs the body with the site's POS key the Standard Webhooks way: webhook-id, webhook-timestamp (within 5 minutes) and webhook-signature. A timestamp more than 5 minutes off, a repeated message id or a bad signature is refused. An interval is stored once per site and start: a later report of the same interval replaces it.

Authentication: The site's point-of-sale key (made by an admin of the site on the dashboard); no API token.

Parameters

FieldTypeDescription
siterequired pathinteger
webhook-idrequired headerstringA unique id for this message, at most 128 characters. A repeated id is refused.
webhook-timestamprequired headerstringThe time of signing in Unix seconds; it must be within 5 minutes of the box's clock.
webhook-signaturerequired headerstringv1, and the base64 HMAC-SHA256 of <webhook-id>.<webhook-timestamp>.<body> with the site's key (the base64 part after whsec_). Several signatures may be given, separated by spaces.

Body

FieldTypeDescription
intervalsrequiredobject[]
intervals[].startrequireddate-time
intervals[].endrequireddate-time
intervals[].transactionsrequiredinteger

Responses

StatusMeaning
200OK
401RFC 9457 problem
403RFC 9457 problem
404RFC 9457 problem
409RFC 9457 problem
422RFC 9457 problem
502RFC 9457 problem

Request

curl -s -X POST "https://<BOX_HOST>/api/retail/v1/pos/1" \
  -H "webhook-id: <WEBHOOK_ID>" \
  -H "webhook-timestamp: <WEBHOOK_TIMESTAMP>" \
  -H "webhook-signature: <WEBHOOK_SIGNATURE>" \
  -H "Content-Type: application/json" \
  -d '{"intervals":[{"start":"2026-11-02T10:00:00+07:00","end":"2026-11-02T11:00:00+07:00","transactions":42}]}'
import requests

r = requests.post(
    "https://<BOX_HOST>/api/retail/v1/pos/1",
    headers={"webhook-id": "<WEBHOOK_ID>", "webhook-timestamp": "<WEBHOOK_TIMESTAMP>", "webhook-signature": "<WEBHOOK_SIGNATURE>"},
    json={
      "intervals": [
        {
          "start": "2026-11-02T10:00:00+07:00",
          "end": "2026-11-02T11:00:00+07:00",
          "transactions": 42
        }
      ]
    },
)
print(r.status_code, r.text)
const r = await fetch("https://<BOX_HOST>/api/retail/v1/pos/1", {
  method: "POST",
  headers: { "webhook-id": "<WEBHOOK_ID>", "webhook-timestamp": "<WEBHOOK_TIMESTAMP>", "webhook-signature": "<WEBHOOK_SIGNATURE>", "Content-Type": "application/json" },
  body: JSON.stringify({
    "intervals": [
      {
        "start": "2026-11-02T10:00:00+07:00",
        "end": "2026-11-02T11:00:00+07:00",
        "transactions": 42
      }
    ]
  }),
});
console.log(r.status, await r.text());

Response 200

{
  "stored": 12
}

Settings

Opening hours, the occupancy limit, queue and visit rules, retention, each camera's door and staff lines, and its latest door crossings (the door-line test).

The Site's Smart Retail Counter Settings

GET/sites/{id}/settings

Who can call it: An account with a role (viewer or admin) on the site. Token scopes: read.

Parameters

FieldTypeDescription
idrequired pathinteger

Responses

StatusMeaning
200OK
401RFC 9457 problem
403RFC 9457 problem
404RFC 9457 problem
409RFC 9457 problem
422RFC 9457 problem
502RFC 9457 problem

Request

curl -s -X GET "https://<BOX_HOST>/api/retail/v1/sites/1/settings" \
  -H "Authorization: Bearer <API_KEY>"
import requests

r = requests.get(
    "https://<BOX_HOST>/api/retail/v1/sites/1/settings",
    headers={"Authorization": "Bearer <API_KEY>"},
)
print(r.status_code, r.text)
const r = await fetch("https://<BOX_HOST>/api/retail/v1/sites/1/settings", {
  method: "GET",
  headers: { "Authorization": "Bearer <API_KEY>" },
});
console.log(r.status, await r.text());

Response 200

{
  "engaged_min_s": 60,
  "long_queue_length": 12,
  "occupancy_limit": 12,
  "open": "08:00",
  "close": "08:00",
  "stats_days": 30,
  "identity_days": 12,
  "version": 3,
  "visit_timeout_s": 60
}

Change The Site's Smart Retail Counter Settings (Applied To Every Camera Of The Site)

PUT/sites/{id}/settings

Who can call it: An account that is an admin of the site. Token scopes: write.

Parameters

FieldTypeDescription
idrequired pathinteger

Body

FieldTypeDescription
engaged_min_srequirednumber
long_queue_lengthrequiredintegerPeople in a queue zone that raise retail.long_queue; a queue zone may set its own (long_queue_length on the zone in the camera's geometry), this is the default
occupancy_limitinteger
openrequiredstring
closerequiredstring
stats_daysrequiredinteger
identity_daysrequiredinteger
versioninteger
visit_timeout_sinteger

Responses

StatusMeaning
200OK
401RFC 9457 problem
403RFC 9457 problem
404RFC 9457 problem
409RFC 9457 problem
422RFC 9457 problem
502RFC 9457 problem

Request

curl -s -X PUT "https://<BOX_HOST>/api/retail/v1/sites/1/settings" \
  -H "Authorization: Bearer <API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{"engaged_min_s":60,"long_queue_length":12,"occupancy_limit":12,"open":"08:00","close":"08:00","stats_days":30,"identity_days":12,"version":3,"visit_timeout_s":60}'
import requests

r = requests.put(
    "https://<BOX_HOST>/api/retail/v1/sites/1/settings",
    headers={"Authorization": "Bearer <API_KEY>"},
    json={
      "engaged_min_s": 60,
      "long_queue_length": 12,
      "occupancy_limit": 12,
      "open": "08:00",
      "close": "08:00",
      "stats_days": 30,
      "identity_days": 12,
      "version": 3,
      "visit_timeout_s": 60
    },
)
print(r.status_code, r.text)
const r = await fetch("https://<BOX_HOST>/api/retail/v1/sites/1/settings", {
  method: "PUT",
  headers: { "Authorization": "Bearer <API_KEY>", "Content-Type": "application/json" },
  body: JSON.stringify({
    "engaged_min_s": 60,
    "long_queue_length": 12,
    "occupancy_limit": 12,
    "open": "08:00",
    "close": "08:00",
    "stats_days": 30,
    "identity_days": 12,
    "version": 3,
    "visit_timeout_s": 60
  }),
});
console.log(r.status, await r.text());

Response 200

{
  "engaged_min_s": 60,
  "long_queue_length": 12,
  "occupancy_limit": 12,
  "open": "08:00",
  "close": "08:00",
  "stats_days": 30,
  "identity_days": 12,
  "version": 3,
  "visit_timeout_s": 60
}

The Camera's Door And Staff Lines

GET/cameras/{id}/lines

Who can call it: An account with a role (viewer or admin) on the site. Token scopes: read.

Parameters

FieldTypeDescription
idrequired pathinteger

Responses

StatusMeaning
200OK
401RFC 9457 problem
403RFC 9457 problem
404RFC 9457 problem
409RFC 9457 problem
422RFC 9457 problem
502RFC 9457 problem

Request

curl -s -X GET "https://<BOX_HOST>/api/retail/v1/cameras/1/lines" \
  -H "Authorization: Bearer <API_KEY>"
import requests

r = requests.get(
    "https://<BOX_HOST>/api/retail/v1/cameras/1/lines",
    headers={"Authorization": "Bearer <API_KEY>"},
)
print(r.status_code, r.text)
const r = await fetch("https://<BOX_HOST>/api/retail/v1/cameras/1/lines", {
  method: "GET",
  headers: { "Authorization": "Bearer <API_KEY>" },
});
console.log(r.status, await r.text());

Response 200

{
  "camera": 12,
  "door_lines": [
    "<door_line>"
  ],
  "staff_lines": [
    "<staff_line>"
  ],
  "default": "<default>"
}

Set The Camera's Door And Staff Lines (IDs Of The Geometry's Lines)

PUT/cameras/{id}/lines

Who can call it: An account that is an admin of the site. Token scopes: write.

Parameters

FieldTypeDescription
idrequired pathinteger

Body

FieldTypeDescription
door_linesstring[]
staff_linesstring[]

Responses

StatusMeaning
200OK
401RFC 9457 problem
403RFC 9457 problem
404RFC 9457 problem
409RFC 9457 problem
422RFC 9457 problem
502RFC 9457 problem

Request

curl -s -X PUT "https://<BOX_HOST>/api/retail/v1/cameras/1/lines" \
  -H "Authorization: Bearer <API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{"door_lines":["<door_line>"],"staff_lines":["<staff_line>"]}'
import requests

r = requests.put(
    "https://<BOX_HOST>/api/retail/v1/cameras/1/lines",
    headers={"Authorization": "Bearer <API_KEY>"},
    json={
      "door_lines": [
        "<door_line>"
      ],
      "staff_lines": [
        "<staff_line>"
      ]
    },
)
print(r.status_code, r.text)
const r = await fetch("https://<BOX_HOST>/api/retail/v1/cameras/1/lines", {
  method: "PUT",
  headers: { "Authorization": "Bearer <API_KEY>", "Content-Type": "application/json" },
  body: JSON.stringify({
    "door_lines": [
      "<door_line>"
    ],
    "staff_lines": [
      "<staff_line>"
    ]
  }),
});
console.log(r.status, await r.text());

Response 200

{
  "camera": 12,
  "door_lines": [
    "<door_line>"
  ],
  "staff_lines": [
    "<staff_line>"
  ]
}

The Camera's Latest Door Crossings (The Door-Line Test)

GET/cameras/{id}/crossings

The door crossings reported for the camera after after, oldest first, at most 500 per call; a door line can be checked live with it. Without after: no crossings, only the cursor to start from. Anonymous: no track or identity.

Who can call it: An account with a role (viewer or admin) on the site. Token scopes: read.

Parameters

FieldTypeDescription
idrequired pathinteger
after queryintegerThe cursor of the previous call

Responses

StatusMeaning
200OK
401RFC 9457 problem
403RFC 9457 problem
404RFC 9457 problem
409RFC 9457 problem

Request

curl -s -X GET "https://<BOX_HOST>/api/retail/v1/cameras/1/crossings?after=2026-11-02T08%3A00%3A00Z" \
  -H "Authorization: Bearer <API_KEY>"
import requests

r = requests.get(
    "https://<BOX_HOST>/api/retail/v1/cameras/1/crossings?after=2026-11-02T08%3A00%3A00Z",
    headers={"Authorization": "Bearer <API_KEY>"},
)
print(r.status_code, r.text)
const r = await fetch("https://<BOX_HOST>/api/retail/v1/cameras/1/crossings?after=2026-11-02T08%3A00%3A00Z", {
  method: "GET",
  headers: { "Authorization": "Bearer <API_KEY>" },
});
console.log(r.status, await r.text());

Response 200

{
  "camera": 12,
  "cursor": 12,
  "crossings": [
    {
      "line": "<line>",
      "direction": "in",
      "staff": true,
      "time": "2026-11-02T08:00:00Z"
    }
  ]
}
Was this page helpful?