DocsIDarsa.technology

Docs / AI Box And Video Analytics Software / API Reference

Traffic Monitor API

The Traffic Monitor API: vehicle counts, classes, speeds and plates on a road's cameras. It gives the volumes and their trend, corridor analytics (peak hour, speeds, class share, approaches), incidents (speeding, wrong way, stopped vehicles, congestion, watchlist hits), the vehicle log with each passage's crop, the plate watchlist, and the site's DATEX II v3 feed for traffic management centres.

Speeds are advisory estimates for traffic management; they are no basis for enforcement.

Personal data. Plates are personal data. A token sees plates and crops only with the personal_data scope; without it the log, its export and the incidents are answered without plates and crops, and plate search and the watchlist are refused. Plate searches are recorded in the audit log.

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.

Feeds With Their Own Credentials

Two operations are for other systems and use a credential of their own, made by an admin of the site on the dashboard: the DATEX II pull feed (a feed token) and the signed watchlist push (the site's watchlist key, Standard Webhooks signatures).

1.0.0

Traffic

Volumes, trend, corridor analytics and incidents.

Vehicles, Speeds, Plates Read, Incidents, Congested Lanes Now

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 querystringRFC 3339
torequired querystringRFC 3339

Responses

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

Request

curl -s -X GET "https://<BOX_HOST>/api/traffic/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/traffic/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/traffic/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

{
  "vehicles": 18452,
  "by_class": {
    "car": 7311,
    "motorcycle": 9870,
    "bus": 212,
    "truck": 1003,
    "bicycle": 56
  },
  "flow_per_min": 12.8,
  "speeds_measured": 15207,
  "mean_speed_kmh": 38.6,
  "p85_speed_kmh": 51,
  "plates_read_pct": 0,
  "incidents": {
    "speeding": 41,
    "wrong_way": 3,
    "stopped": 5,
    "congestion": 2,
    "watchlist": 0
  },
  "congested_now": [
    {
      "camera_id": 21,
      "lane": "Lane 2",
      "occupancy": 82,
      "since": "2026-11-02T09:41:00Z"
    }
  ]
}

Vehicles And Mean Speed 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 querystringRFC 3339
torequired querystringRFC 3339
bucket querystringhour or day

Responses

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

Request

curl -s -X GET "https://<BOX_HOST>/api/traffic/v1/sites/1/trend?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/traffic/v1/sites/1/trend?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/traffic/v1/sites/1/trend?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

{
  "bucket": "hour",
  "buckets": [
    {
      "start": "<start>",
      "vehicles": 12,
      "mean_speed_kmh": 12
    }
  ]
}

Corridor Analytics: Peak Hour And Factor, Heatmap, Speed Histogram, Class Share, Approaches

GET/sites/{id}/analytics

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

Parameters

FieldTypeDescription
idrequired pathinteger
fromrequired querystringRFC 3339
torequired querystringRFC 3339

Responses

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

Request

curl -s -X GET "https://<BOX_HOST>/api/traffic/v1/sites/1/analytics?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/traffic/v1/sites/1/analytics?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/traffic/v1/sites/1/analytics?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

{
  "summary": {
    "vehicles": 12,
    "daily_average": 12,
    "mean_speed_kmh": 12,
    "p85_speed_kmh": 12,
    "peak_hour": {
      "start": "<start>",
      "vehicles": 12,
      "phf": 12
    }
  },
  "heatmap": [
    {
      "day": "<day>",
      "hours": [
        7
      ]
    }
  ],
  "speed_histogram": {
    "bucket_kmh": 12,
    "counts": [
      12
    ]
  },
  "class_share": [
    {
      "day": "<day>",
      "counts": {
        "car": 12,
        "motorcycle": 12,
        "bus": 12,
        "truck": 12,
        "bicycle": 12
      }
    }
  ],
  "approaches": [
    {
      "camera_id": 1,
      "line": "<line>",
      "direction": "in",
      "vehicles": 12,
      "mean_speed_kmh": 12
    }
  ]
}

Speeding, Wrong Way, Stopped Vehicles, Congestion And Watchlist Hits, Newest First

GET/sites/{id}/incidents

Who can call it: An account with a role (viewer or admin) on the site. Token scopes: read. Without personal_data the answer is the anonymous form: no names, plates, pictures or footage.

Parameters

FieldTypeDescription
idrequired pathinteger
fromrequired querystringRFC 3339
torequired querystringRFC 3339
kind querystring
limit queryinteger

Responses

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

Request

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

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

Response 200

{
  "items": [
    {
      "id": "<id>",
      "time": "2026-11-02T08:00:00Z",
      "camera_id": 1,
      "kind": "speeding",
      "lane": "Lane 1",
      "zone": "Loading bay",
      "class": "car",
      "plate": "B 1234 XYZ",
      "speed_kmh": 12,
      "limit_kmh": 12,
      "state": "ok",
      "occupancy": 12,
      "stopped_s": 60
    }
  ]
}

Vehicle Log

Every passage with its class, speed, lane and plate; the export and crops.

The Vehicle Log, Newest First, Paged; A Plate Search Is Audited

GET/sites/{id}/logs

Who can call it: An account with a role (viewer or admin) on the site. Token scopes: read. Without personal_data the answer is the anonymous form: no names, plates, pictures or footage.

Parameters

FieldTypeDescription
idrequired pathinteger
fromrequired querystringRFC 3339
torequired querystringRFC 3339
plate querystringa plate search; API tokens need personal_data for it
class querystring
camera queryinteger
limit queryinteger
before querystringnext_before of the previous page

Responses

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

Request

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

r = requests.get(
    "https://<BOX_HOST>/api/traffic/v1/sites/1/logs?from=2026-11-01T00%3A00%3A00%2B07%3A00&to=2026-11-02T00%3A00%3A00%2B07%3A00&camera=1&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/traffic/v1/sites/1/logs?from=2026-11-01T00%3A00%3A00%2B07%3A00&to=2026-11-02T00%3A00%3A00%2B07%3A00&camera=1&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": "21:90311",
      "time": "2026-11-02T09:44:12Z",
      "camera_id": 21,
      "line": "count",
      "direction": "in",
      "lane": "Lane 1",
      "class": "car",
      "colour": "white",
      "speed_kmh": 42.5,
      "plate": null,
      "media": null,
      "photo": null
    },
    {
      "id": "21:90310",
      "time": "2026-11-02T09:44:09Z",
      "camera_id": 21,
      "line": "count",
      "direction": "in",
      "lane": "Lane 2",
      "class": "motorcycle",
      "colour": null,
      "speed_kmh": null,
      "plate": null,
      "media": null,
      "photo": null
    }
  ],
  "next_before": "2026-11-02T09:44:09Z"
}

The Vehicle Log As CSV Or XLSX (EN/ID, Local Times, At Most 20 000 Rows; Audited)

GET/sites/{id}/logs/export

Who can call it: An account with a role (viewer or admin) on the site. Token scopes: read, export. Without personal_data the answer is the anonymous form: no names, plates, pictures or footage.

Parameters

FieldTypeDescription
idrequired pathinteger
fromrequired querystringRFC 3339
torequired querystringRFC 3339
format querystringcsv or xlsx
language querystringen or id

Responses

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

Request

curl -s -X GET "https://<BOX_HOST>/api/traffic/v1/sites/1/logs/export?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/traffic/v1/sites/1/logs/export?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/traffic/v1/sites/1/logs/export?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());

A Passage's Crop (The Vehicle And Its Plate); Only A Reference That A Passage Of This Site Holds

GET/sites/{id}/media/{ref}

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

Parameters

FieldTypeDescription
idrequired pathinteger
refrequired pathstring

Responses

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

Request

curl -s -X GET "https://<BOX_HOST>/api/traffic/v1/sites/1/media/{ref}" \
  -H "Authorization: Bearer <API_KEY>"
import requests

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

Watchlist

Plates to watch for, their hits, the CSV import and the signed feed from other systems.

Import A CSV (plate,reason[,notes]): Adds Or Updates Entries; Audited

POST/sites/{id}/watchlist/upload

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

Parameters

FieldTypeDescription
idrequired pathinteger

Responses

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

Request

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

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

Response 200

{
  "added": 12,
  "updated": 12,
  "removed": 12
}

Signed Watchlist Update From Another System

POST/feeds/watchlist/{site}

Adds or updates plates (upsert) and removes plates (remove) on the site's watchlist. The call is signed with the site's watchlist key the Standard Webhooks way: webhook-id, webhook-timestamp (within 5 minutes) and webhook-signature: v1,<base64 HMAC-SHA256 of id.timestamp.body>. A repeated message id, a bad signature and a site without a key all get the same 401. Every import is recorded in the audit log.

Authentication: The site's watchlist 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
upsertobject[]
upsert[].platerequiredstringan Indonesian plate, stored as B 1234 XYZ
upsert[].reasonrequiredenumstolen, wanted, tax_arrears, other
upsert[].notesstring
removestring[]

Responses

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

Request

curl -s -X POST "https://<BOX_HOST>/api/traffic/v1/feeds/watchlist/1" \
  -H "webhook-id: <WEBHOOK_ID>" \
  -H "webhook-timestamp: <WEBHOOK_TIMESTAMP>" \
  -H "webhook-signature: <WEBHOOK_SIGNATURE>" \
  -H "Content-Type: application/json" \
  -d '{"upsert":[{"plate":"B 1234 XYZ","reason":"stolen","notes":"Blue pickup"}],"remove":["D 5678 AB"]}'
import requests

r = requests.post(
    "https://<BOX_HOST>/api/traffic/v1/feeds/watchlist/1",
    headers={"webhook-id": "<WEBHOOK_ID>", "webhook-timestamp": "<WEBHOOK_TIMESTAMP>", "webhook-signature": "<WEBHOOK_SIGNATURE>"},
    json={
      "upsert": [
        {
          "plate": "B 1234 XYZ",
          "reason": "stolen",
          "notes": "Blue pickup"
        }
      ],
      "remove": [
        "D 5678 AB"
      ]
    },
)
print(r.status_code, r.text)
const r = await fetch("https://<BOX_HOST>/api/traffic/v1/feeds/watchlist/1", {
  method: "POST",
  headers: { "webhook-id": "<WEBHOOK_ID>", "webhook-timestamp": "<WEBHOOK_TIMESTAMP>", "webhook-signature": "<WEBHOOK_SIGNATURE>", "Content-Type": "application/json" },
  body: JSON.stringify({
    "upsert": [
      {
        "plate": "B 1234 XYZ",
        "reason": "stolen",
        "notes": "Blue pickup"
      }
    ],
    "remove": [
      "D 5678 AB"
    ]
  }),
});
console.log(r.status, await r.text());

Response 200

{
  "added": 12,
  "updated": 12,
  "removed": 12
}

The Site's Watchlist

GET/sites/{id}/watchlist

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

Parameters

FieldTypeDescription
idrequired pathinteger
q querystringpart of a plate

Responses

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

Request

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

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

Response 200

{
  "items": [
    {
      "id": 1,
      "entry_id": "<entry_id>",
      "plate": "B 1234 XYZ",
      "reason": "stolen",
      "notes": "Shift A",
      "active": true,
      "added_by": "<added_by>",
      "source": "manual",
      "created": "<created>",
      "updated": "<updated>"
    }
  ],
  "key": true
}

Add A Plate To The Watchlist (Pushed To The Site's Cameras; Audited)

POST/sites/{id}/watchlist

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

Parameters

FieldTypeDescription
idrequired pathinteger

Body

FieldTypeDescription
platerequiredstringan Indonesian plate, stored as B 1234 XYZ
reasonrequiredenumstolen, wanted, tax_arrears, other
notesstring

Responses

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

Request

curl -s -X POST "https://<BOX_HOST>/api/traffic/v1/sites/1/watchlist" \
  -H "Authorization: Bearer <API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{"plate":"B 1234 XYZ","reason":"stolen","notes":"Shift A"}'
import requests

r = requests.post(
    "https://<BOX_HOST>/api/traffic/v1/sites/1/watchlist",
    headers={"Authorization": "Bearer <API_KEY>"},
    json={
      "plate": "B 1234 XYZ",
      "reason": "stolen",
      "notes": "Shift A"
    },
)
print(r.status_code, r.text)
const r = await fetch("https://<BOX_HOST>/api/traffic/v1/sites/1/watchlist", {
  method: "POST",
  headers: { "Authorization": "Bearer <API_KEY>", "Content-Type": "application/json" },
  body: JSON.stringify({
    "plate": "B 1234 XYZ",
    "reason": "stolen",
    "notes": "Shift A"
  }),
});
console.log(r.status, await r.text());

Response 200

{
  "id": 1,
  "entry_id": "<entry_id>",
  "plate": "B 1234 XYZ",
  "reason": "stolen",
  "notes": "Shift A",
  "active": true,
  "added_by": "<added_by>",
  "source": "manual",
  "created": "<created>",
  "updated": "<updated>"
}

Change, Pause Or Resume An Entry (Audited)

PATCH/watchlist/{entry}

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

Parameters

FieldTypeDescription
entryrequired pathinteger

Body

FieldTypeDescription
reasonenumstolen, wanted, tax_arrears, other
notesstring
activeboolean

Responses

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

Request

curl -s -X PATCH "https://<BOX_HOST>/api/traffic/v1/watchlist/1" \
  -H "Authorization: Bearer <API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{"reason":"stolen","notes":"Shift A","active":true}'
import requests

r = requests.patch(
    "https://<BOX_HOST>/api/traffic/v1/watchlist/1",
    headers={"Authorization": "Bearer <API_KEY>"},
    json={
      "reason": "stolen",
      "notes": "Shift A",
      "active": True
    },
)
print(r.status_code, r.text)
const r = await fetch("https://<BOX_HOST>/api/traffic/v1/watchlist/1", {
  method: "PATCH",
  headers: { "Authorization": "Bearer <API_KEY>", "Content-Type": "application/json" },
  body: JSON.stringify({
    "reason": "stolen",
    "notes": "Shift A",
    "active": true
  }),
});
console.log(r.status, await r.text());

Response 200

{
  "id": 1,
  "entry_id": "<entry_id>",
  "plate": "B 1234 XYZ",
  "reason": "stolen",
  "notes": "Shift A",
  "active": true,
  "added_by": "<added_by>",
  "source": "manual",
  "created": "<created>",
  "updated": "<updated>"
}

Delete An Entry (Audited)

DELETE/watchlist/{entry}

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

Parameters

FieldTypeDescription
entryrequired pathinteger

Responses

StatusMeaning
204OK
401RFC 9457 problem details
403RFC 9457 problem details
404RFC 9457 problem details
409RFC 9457 problem details
422RFC 9457 problem details
502RFC 9457 problem details

Request

curl -s -X DELETE "https://<BOX_HOST>/api/traffic/v1/watchlist/1" \
  -H "Authorization: Bearer <API_KEY>"
import requests

r = requests.delete(
    "https://<BOX_HOST>/api/traffic/v1/watchlist/1",
    headers={"Authorization": "Bearer <API_KEY>"},
)
print(r.status_code, r.text)
const r = await fetch("https://<BOX_HOST>/api/traffic/v1/watchlist/1", {
  method: "DELETE",
  headers: { "Authorization": "Bearer <API_KEY>" },
});
console.log(r.status, await r.text());

The Latest Watchlist Hits

GET/sites/{id}/watchlist/hits

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

Parameters

FieldTypeDescription
idrequired pathinteger
limit queryinteger

Responses

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

Request

curl -s -X GET "https://<BOX_HOST>/api/traffic/v1/sites/1/watchlist/hits?limit=50" \
  -H "Authorization: Bearer <API_KEY>"
import requests

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

Response 200

{
  "items": [
    {
      "id": "<id>",
      "time": "2026-11-02T08:00:00Z",
      "camera_id": 1,
      "plate": "B 1234 XYZ",
      "reason": "Unpaid toll",
      "entry_id": "<entry_id>"
    }
  ]
}

DATEX II

The site's DATEX II v3 feed: camera locations, the pull token, the push target.

The Camera's Location For The DATEX II Feed

GET/cameras/{id}/location

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 details
403RFC 9457 problem details
404RFC 9457 problem details
409RFC 9457 problem details
422RFC 9457 problem details
502RFC 9457 problem details

Request

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

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

Response 200

{
  "camera": 12,
  "latitude": -6.2,
  "longitude": 106.8,
  "road": "<road>",
  "direction": "in",
  "version": 3
}

Set The Camera's Location (Latitude, Longitude, Road, DATEX II Direction); Audited

PUT/cameras/{id}/location

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

Parameters

FieldTypeDescription
idrequired pathinteger

Body

FieldTypeDescription
latituderequirednumber
longituderequirednumber
roadstring
directionenumnorthBound, northEastBound, eastBound, southEastBound, southBound, southWestBound, westBound, northWestBound, bothWays, inboundTowardsTown, outboundFromTown, unknown

Responses

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

Request

curl -s -X PUT "https://<BOX_HOST>/api/traffic/v1/cameras/1/location" \
  -H "Authorization: Bearer <API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{"latitude":-6.2,"longitude":106.8,"road":"<road>","direction":"northBound"}'
import requests

r = requests.put(
    "https://<BOX_HOST>/api/traffic/v1/cameras/1/location",
    headers={"Authorization": "Bearer <API_KEY>"},
    json={
      "latitude": -6.2,
      "longitude": 106.8,
      "road": "<road>",
      "direction": "northBound"
    },
)
print(r.status_code, r.text)
const r = await fetch("https://<BOX_HOST>/api/traffic/v1/cameras/1/location", {
  method: "PUT",
  headers: { "Authorization": "Bearer <API_KEY>", "Content-Type": "application/json" },
  body: JSON.stringify({
    "latitude": -6.2,
    "longitude": 106.8,
    "road": "<road>",
    "direction": "northBound"
  }),
});
console.log(r.status, await r.text());

Response 200

{
  "camera": 12,
  "latitude": -6.2,
  "longitude": 106.8,
  "road": "<road>",
  "direction": "in",
  "version": 3
}

The Site's DATEX II Feed: Pull Token Set, Push Target, Interval, Last Push

GET/sites/{id}/datex

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

Parameters

FieldTypeDescription
idrequired pathinteger

Responses

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

Request

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

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

Response 200

{
  "site": 12,
  "pull_token": true,
  "pull_url": "https://<RECEIVER_HOST>/hooks/arsa",
  "push_url": "https://<RECEIVER_HOST>/hooks/arsa",
  "interval_s": 60,
  "last_push": "<last_push>",
  "last_status": "<last_status>",
  "push_secret": "<push_secret>",
  "shown_once": true
}

Set The Push Target And Interval; A New Target Gets A New Signing Secret, Shown Once; Audited

PUT/sites/{id}/datex

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

Parameters

FieldTypeDescription
idrequired pathinteger

Body

FieldTypeDescription
push_urlstring
interval_srequiredinteger

Responses

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

Request

curl -s -X PUT "https://<BOX_HOST>/api/traffic/v1/sites/1/datex" \
  -H "Authorization: Bearer <API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{"push_url":"https://<RECEIVER_HOST>/hooks/arsa","interval_s":60}'
import requests

r = requests.put(
    "https://<BOX_HOST>/api/traffic/v1/sites/1/datex",
    headers={"Authorization": "Bearer <API_KEY>"},
    json={
      "push_url": "https://<RECEIVER_HOST>/hooks/arsa",
      "interval_s": 60
    },
)
print(r.status_code, r.text)
const r = await fetch("https://<BOX_HOST>/api/traffic/v1/sites/1/datex", {
  method: "PUT",
  headers: { "Authorization": "Bearer <API_KEY>", "Content-Type": "application/json" },
  body: JSON.stringify({
    "push_url": "https://<RECEIVER_HOST>/hooks/arsa",
    "interval_s": 60
  }),
});
console.log(r.status, await r.text());

Response 200

{
  "site": 12,
  "pull_token": true,
  "pull_url": "https://<RECEIVER_HOST>/hooks/arsa",
  "push_url": "https://<RECEIVER_HOST>/hooks/arsa",
  "interval_s": 60,
  "last_push": "<last_push>",
  "last_status": "<last_status>",
  "push_secret": "<push_secret>",
  "shown_once": true
}

The Site's DATEX II v3 Feed

GET/feeds/datex/{site}/{doc}

DATEX II v3 XML (EN 16157, valid against the v3.7 schemas): measurement-sites, measured-data (the last complete interval) or situations (now). Send the site's feed token as Authorization: Bearer <FEED_TOKEN>.

Authentication: The site's DATEX II feed token (made by an admin of the site on the dashboard); no API token.

Parameters

FieldTypeDescription
siterequired pathinteger
docrequired pathenummeasurement-sites, measured-data, situations

Responses

StatusMeaning
200a DATEX II d2:payload
401RFC 9457 problem details
403RFC 9457 problem details
404RFC 9457 problem details
409RFC 9457 problem details
422RFC 9457 problem details
502RFC 9457 problem details

Request

curl -s -X GET "https://<BOX_HOST>/api/traffic/v1/feeds/datex/1/measurement-sites" \
  -H "Authorization: Bearer <FEED_TOKEN>"
import requests

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

Settings

Speed limit, slow and stopped vehicles, congestion, retention of statistics and plates.

The Site's Traffic Monitor 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 details
403RFC 9457 problem details
404RFC 9457 problem details
409RFC 9457 problem details
422RFC 9457 problem details
502RFC 9457 problem details

Request

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

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

Response 200

{
  "passage_hold_s": 60,
  "stopped_s": 60,
  "slow_kmh": 12,
  "speed_limit_kmh": 12,
  "congestion_window_s": 60,
  "stats_days": 30,
  "plate_days": 12,
  "version": 3
}

Change The Site's Traffic Monitor 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
passage_hold_srequirednumber
stopped_srequirednumber
slow_kmhrequirednumber
speed_limit_kmhnumber
congestion_window_srequirednumber
stats_daysrequiredinteger
plate_daysrequiredintegerplates are blanked after this
versioninteger

Responses

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

Request

curl -s -X PUT "https://<BOX_HOST>/api/traffic/v1/sites/1/settings" \
  -H "Authorization: Bearer <API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{"passage_hold_s":60,"stopped_s":60,"slow_kmh":12,"speed_limit_kmh":12,"congestion_window_s":60,"stats_days":30,"plate_days":12,"version":3}'
import requests

r = requests.put(
    "https://<BOX_HOST>/api/traffic/v1/sites/1/settings",
    headers={"Authorization": "Bearer <API_KEY>"},
    json={
      "passage_hold_s": 60,
      "stopped_s": 60,
      "slow_kmh": 12,
      "speed_limit_kmh": 12,
      "congestion_window_s": 60,
      "stats_days": 30,
      "plate_days": 12,
      "version": 3
    },
)
print(r.status_code, r.text)
const r = await fetch("https://<BOX_HOST>/api/traffic/v1/sites/1/settings", {
  method: "PUT",
  headers: { "Authorization": "Bearer <API_KEY>", "Content-Type": "application/json" },
  body: JSON.stringify({
    "passage_hold_s": 60,
    "stopped_s": 60,
    "slow_kmh": 12,
    "speed_limit_kmh": 12,
    "congestion_window_s": 60,
    "stats_days": 30,
    "plate_days": 12,
    "version": 3
  }),
});
console.log(r.status, await r.text());

Response 200

{
  "passage_hold_s": 60,
  "stopped_s": 60,
  "slow_kmh": 12,
  "speed_limit_kmh": 12,
  "congestion_window_s": 60,
  "stats_days": 30,
  "plate_days": 12,
  "version": 3
}
Was this page helpful?