TingPush Camera AI

Integration docs

TingPush public API — fetching stored plate data

Bản tiếng Việt

For developers who want plate data from TingPush cameras in their own software (parking management, accounting, attendance…) without running their own receiving server.

New here? Read TingPush data integration guide for developers first: choosing an integration path, the full API catalogue, complete sync code.

There are 2 ways to receive data from a camera — chosen in the TingPush Camera app → Cài đặt camera (Camera settings) → Gửi dữ liệu biển số (Send plate data):

How it works Docs
TingPush server (default) The camera sends to TingPush, where data is stored according to your plan. You pull it through this API, or export files. this document
Own API The camera pushes straight to your URL as soon as it reads a plate. Writing an API that receives plate reads from TingPush cameras

The TingPush apps are in Vietnamese; screen labels are quoted as they appear, with a translation in parentheses.


1. Getting ready

  1. The camera has been added to the account (app → Thêm camera, Add camera) and its Nơi nhận dữ liệu (Destination) is Máy chủ TingPush (TingPush server).
  2. The account is on a plan that includes API access (app → Tài khoản → Gói dịch vụ, Account → Plan). Contact TingPush to upgrade.
  3. Create an API key: app → Tài khoản → Khóa API → Tạo khóa (Account → API keys → Create key), or on the web at https://webrtc.tingpush.com/account. Keys look like tp_ + 40 characters and are shown only once — copy and store them like a password. Up to 10 keys per account; deleting a key revokes it immediately.

An API key sees every camera the account can see (cameras it owns + cameras shared with it), read-only. Keys created with Điều khiển thiết bị & sửa danh sách xe (Control devices & edit vehicle lists) can also open barriers and edit allow lists — see Peripherals — opening barriers, roller doors, sirens and lights from a TingPush camera section 6.

2. Calling the API

Base URL:     https://apiwebrtc.tingpush.com/api/v1
Auth:         X-Api-Key: tp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
              (or Authorization: Bearer tp_xxxx…)
Rate limit:   120 requests / minute / key — beyond that you get 429; wait a minute
Format:       JSON UTF-8, snake_case field names; times are ISO 8601 in Vietnam time (+07:00) plus "timestamp" (UNIX seconds)

Quick example:

curl -H "X-Api-Key: tp_xxx" "https://apiwebrtc.tingpush.com/api/v1/plates?limit=10"
Code Meaning
200 Success
401 Missing / wrong key, deleted key, locked account, or the plan has no API access
403 The plan doesn't include file export (/export)
404 No such record / image (or no access to that camera)
429 Too many requests

3. Endpoints

GET /api/v1/cameras — the account's cameras

[
  { "id": "LPR-9MHK902C8J5Z", "name": "Cổng vào", "role": "owner", "online": true, "last_seen": "2026-10-16T03:02:26+00:00" }
]

GET /api/v1/plates — stored plates

Parameter
camera optional camera ID (LPR-…)
plate optional plates containing this text, ignoring dashes / dots (e.g. 30A123)
from, to optional time range [from, to), ISO 8601, e.g. 2026-10-16T00:00:00+07:00
since_id optional incremental sync: records with id > since_id, oldest first — see section 4
before_id optional paging backwards: records with id < before_id, newest first
limit optional 1–1000, default 100

Without since_id: newest first. With since_id: oldest first (for syncing).

{
  "data": [
    {
      "id": 1842,
      "camera_id": "LPR-9MHK902C8J5Z",
      "camera_name": "Cổng vào",
      "plate": "51G11111",
      "plate_display": "51G-111.11",
      "raw_text": "51G-11111",
      "confidence": 0.9,
      "read_count": 3,
      "time": "2026-10-16T10:02:54+07:00",
      "timestamp": 1792119774,
      "received_at": "2026-10-16T10:02:55+07:00",
      "box": [520, 320, 760, 400],
      "frame_width": 1280,
      "frame_height": 720,
      "plate_image_url": "https://apiwebrtc.tingpush.com/api/v1/plates/1842/image/plate",
      "image_url": null,
      "allowed": true,
      "allow_name": "Nguyễn Văn A"
    }
  ],
  "next_since_id": 1842,
  "has_more": false
}
Field Meaning
id TingPush record ID, increasing, never changes — use it as your sync key
plate Normalised plate (uppercase letters + digits, no punctuation) — use it for storage / matching
plate_display Plate formatted the Vietnamese way for display
time / timestamp When the camera confirmed the plate
received_at When the server received it (a camera that was offline sends later, so received_at is after time)
confidence, read_count Confidence 0–1, and how many matching reads the camera made before confirming
box, frame_width, frame_height Plate position in the frame
plate_image_url Plate close-up (JPEG) — download with the same API key header; null if the camera doesn't send plate images
image_url Full scene image — only when the camera sends it and the plan stores scene images
allowed, allow_name true = the plate is on the allow list (the camera opened the barrier if a rule says so), false = not on it, null = the camera has no list; allow_name = owner name from the list
next_since_id (only when called with since_id) the since_id for your next call
has_more more data waiting — call again right away

`GET /api/v1/plates/

Returns one object, like an element of data.

`GET /api/v1/plates/

Returns image/jpeg. Images are deleted together with the record when the plan's retention period ends.

GET /api/v1/export?format=csv|json — file export

Same filters: camera, plate, from, to. Up to 200,000 rows per call.

  • CSV: UTF-8 with BOM (opens in Excel without breaking Vietnamese text), comma-separated, header row: id,camera_id,camera_name,plate,plate_display,time,timestamp,confidence,read_count,raw_text,plate_image_url,image_url (time as yyyy-MM-dd HH:mm:ss Vietnam time).
  • JSON: an array of objects with the same fields as the CSV.

Non-developers can export too: app → Biển số (Plates) tab → Đã lưu (Stored) → download button; or the web viewer → Biển số → Xuất Excel (Export to Excel).

GET /api/v1/events — AI events (intrusion, faces, counting)

Same parameters as /plates: camera, type (intrusion, occupancy, face, count, custom, io — peripheral open / close; several separated by commas), from, to, since_id (incremental sync), before_id, limit (1–1000, default 100).

{
  "data": [
    {
      "id": 812, "camera_id": "LPR-9MHK902C8J5Z", "camera_name": "Cổng kho", "type": "intrusion",
      "summary": "Có người xâm nhập vùng Kho",
      "data": { "zone": "Kho", "class": "person", "box": [0.67, 0.5, 0.83, 0.8], "dwell_s": 2 },
      "time": "2026-10-16T22:15:03+07:00", "timestamp": 1792170903,
      "image_url": "https://apiwebrtc.tingpush.com/api/v1/events/812/image/scene",
      "crop_image_url": "https://apiwebrtc.tingpush.com/api/v1/events/812/image/crop",
      "test": false
    }
  ],
  "next_since_id": null, "has_more": false
}

summary is generated in Vietnamese (here: "Someone entered zone Kho"); zone names are whatever the owner typed. The data fields per type are in AI events and alerts — people / vehicle counting, restricted-zone intrusion, face recognition, section 5. Images: GET /api/v1/events/{id}/image/scene|crop (with the API key).

GET /api/v1/counts — people / vehicle line counts

camera, from, to (default the last 24 hours, at most 400 days), bucket = hour | day | month (Vietnam time), by_line=true to split by line.

{
  "bucket": "hour",
  "data": [
    { "start": "2026-10-16T08:00:00+07:00", "line": null, "person_in": 42, "person_out": 37, "vehicle_in": 5, "vehicle_out": 4 }
  ]
}

GET /api/v1/occupancy — how many are inside now (in − out)

Computed by the camera; resets to 0 daily at the configured reset time. camera (optional).

{ "data": [ { "camera_id": "LPR-9MHK902C8J5Z", "camera_name": "Cửa hàng", "person": 12, "vehicle": 0, "total": 12, "max": 30,
              "updated_at": "2026-10-16T10:15:00+07:00" } ] }

Peripherals & vehicle lists — opening barriers, editing lists

GET /api/v1/cameras/{id}/outputs, POST /api/v1/cameras/{id}/outputs/{index}/trigger, GET /api/v1/platelists, GET|POST /api/v1/platelists/{id}/entries, DELETE /api/v1/platelists/{id}/entries/{plate}, POST /api/v1/platelists/{id}/import — see Peripherals — opening barriers, roller doors, sirens and lights from a TingPush camera section 6 (needs a key with control permission).

Time attendance & employees

GET /api/v1/attendance (attendance records, synced with since_id like /plates), GET /api/v1/attendance/timesheet (timesheet), GET|POST /api/v1/employees, PUT|DELETE /api/v1/employees/{id} (add / edit employees with a photo, needs a key with control permission) — see Face time attendance — a TingPush camera as a time clock section 7.

Keep a last_id (starting at 0) in your database and run this periodically (e.g. every 10–30 seconds):

loop:
    GET /api/v1/plates?since_id={last_id}&limit=500
    store each record (skip if the id already exists — UNIQUE on id)
    last_id = next_since_id
    if has_more: call again right away, otherwise: wait for the next run
  • Nothing missed, nothing duplicated: id increases in the order the server received records.
  • Images: download plate_image_url when needed (same API key header) and keep your own copy if you need it longer than the plan's retention.
  • Each call uses 1 of your 120 requests per minute — syncing every 10 seconds is comfortable.

Python

import time, requests

API = "https://apiwebrtc.tingpush.com/api/v1"
H = {"X-Api-Key": "tp_xxx"}
last_id = 0  # read from your database

while True:
    r = requests.get(f"{API}/plates", params={"since_id": last_id, "limit": 500}, headers=H, timeout=30)
    r.raise_for_status()
    page = r.json()
    for p in page["data"]:
        print(p["id"], p["plate_display"], p["time"], p["camera_name"])   # -> store in your database
    last_id = page["next_since_id"]
    if not page["has_more"]:
        time.sleep(10)

C# (.NET)

using System.Net.Http.Json;
using System.Text.Json;

var http = new HttpClient { BaseAddress = new Uri("https://apiwebrtc.tingpush.com/api/v1/") };
http.DefaultRequestHeaders.Add("X-Api-Key", "tp_xxx");
long lastId = 0; // read from your database

while (true)
{
    var page = await http.GetFromJsonAsync<JsonElement>($"plates?since_id={lastId}&limit=500");
    foreach (var p in page.GetProperty("data").EnumerateArray())
        Console.WriteLine($"{p.GetProperty("id")} {p.GetProperty("plate_display")} {p.GetProperty("time")}");
    lastId = page.GetProperty("next_since_id").GetInt64();
    if (!page.GetProperty("has_more").GetBoolean()) await Task.Delay(TimeSpan.FromSeconds(10));
}

Node.js (18+)

const API = 'https://apiwebrtc.tingpush.com/api/v1', H = { 'X-Api-Key': 'tp_xxx' };
let lastId = 0; // read from your database
for (;;) {
  const r = await fetch(`${API}/plates?since_id=${lastId}&limit=500`, { headers: H });
  if (!r.ok) throw new Error(`HTTP ${r.status}`);
  const page = await r.json();
  for (const p of page.data) console.log(p.id, p.plate_display, p.time);
  lastId = page.next_since_id;
  if (!page.has_more) await new Promise(ok => setTimeout(ok, 10000));
}

PHP

$ctx = stream_context_create(['http' => ['header' => "X-Api-Key: tp_xxx\r\n"]]);
$page = json_decode(file_get_contents("https://apiwebrtc.tingpush.com/api/v1/plates?since_id=$lastId&limit=500", false, $ctx), true);
foreach ($page['data'] as $p) echo $p['id'], ' ', $p['plate_display'], ' ', $p['time'], "\n";
$lastId = $page['next_since_id'];

Excel / Power BI / Google Sheets

Use Get data from web (Excel: Data → From Web) with the URL https://apiwebrtc.tingpush.com/api/v1/export?format=csv&from=2026-10-01T00:00:00%2B07:00 and the X-Api-Key header, or download the CSV from the app / web viewer and open it.

5. Plans and billing

Set by the TingPush administrators; see app → Tài khoản → Gói dịch vụ (Account → Plan):

Reads / month Each plate a camera sends = 1 read (resends after a network drop don't count). "Stop when used up" plans: past the limit the server stops accepting until next month (the app shows how many reads were rejected). Other plans: overage billed per 1,000 reads.
Retention Records + images older than the plan's number of days are deleted automatically — sync them to your system if you need them longer.
Scene images Stored only on plans that include them; plate close-ups are always stored.
API / file export According to the plan.
Time attendance Attendance records are accepted only on plans with attendance; they have their own retention (default 400 days).

Months follow Vietnam time. Monthly fee = plan fee + overage.

6. FAQ

  • Want data instantly instead of polling? Switch the camera to Own API so it pushes straight to your server (Writing an API that receives plate reads from TingPush cameras). Each camera has one destination.
  • No data? Check that the camera's destination is TingPush, the camera has an owner, the plan still has reads left, and the plate falls within the camera's reading hours and reading area (app → Cài đặt đọc biển số, Plate reading settings).
  • Someone else claims the camera (sold / transferred): earlier history stays with the previous owner; the new owner only sees data from when they added it.
  • Deleting the account deletes all of its plates, images and API keys immediately.