Protocols
Send telemetry from any EV-motorbike OEM, manufacturer, or supplier in its native wire format. One endpoint, many codecs, across three layers: GPS telematics, on-vehicle BMS/bus, and charging infrastructure.
Overview
Rootd's ingest gateway decodes the wire format a device already speaks and normalizes it into the vendor-neutral twin. You don't reflash firmware or build a translation layer. You point the feed at POST /v1/ingest/{protocol} and pick the codec by name. Battery readings flow into the digital twin; GPS fixes into the fleet map.
generic_json for custom backends.Get a token
Authentication is a bearer token scoped to your tenant. An operator mints one from the dashboard (Settings → API tokens) or via the API; the token carries the ingest role, so it can push telemetry but is still tenant-isolated. Treat it as a device secret.
01# Mint an API token (an operator does this once; it carries the ingest role,02# scoped to your tenant). Or create one in the dashboard: Settings → API tokens.03curl -X POST https://api.rootd.cc/v1/settings/tokens \04 -H "Authorization: Bearer $OPERATOR_TOKEN" \05 -H "Content-Type: application/json" \06 -d '{"scopes":[],"ttlHours":720}'07# → { "token": "<INGEST_TOKEN>" }The endpoint
| Field | Type | Description |
|---|---|---|
| {protocol} req | path | Codec name: one of the catalog below (e.g. jt808, modbus, ocpp). |
| Authorization req | header | Bearer token with the ingest role (see above). |
| Content-Type | header | JSON for generic_json/ocpp; binary protocols post raw bytes (no type needed). |
| device | query | Device id for protocols whose wire carries none (modbus, can, jbd, daly, ocpp). Ignored when the wire already identifies the device. |
| body req | raw | The native payload: a JSON document, or the raw protocol bytes (a single message or several concatenated). Max 1 MiB. |
https://api.rootd.cc. The endpoint is idempotent: replaying a frame is safe (de-duplicated on tenant + device + timestamp), so a device can retry freely after a connectivity gap.Device identity
Every reading is attributed to a device. Protocols that carry an id on the wire (a JT808 BCD phone number, a teltonika IMEI, a GB/T VIN, a GT06 login IMEI) use it automatically. Protocols that don't (raw Modbus registers, CAN frames, JBD/Daly BMS, OCPP) take the id from ?device=. Non-UUID ids are mapped to a stable battery-twin id; the raw id is preserved for the fleet map.
Protocol catalog
| Field | Type | Description |
|---|---|---|
| generic_json | generic | Vendor-neutral JSON (object or array). Battery + GPS. Carries its own device id. |
| jt808 | telematics | JT/T 808 GPS trackers (China standard). Binary, 0x7e-framed. Location + EV battery items. |
| gt06 | telematics | GT06 / Concox / Jimi trackers. Binary 0x7878. GPS (device id from login or ?device=). |
| teltonika | telematics | Teltonika Codec 8 / 8E (Europe). Binary AVL. GPS + battery via IO elements. id from ?device=. |
| gbt32960 | telematics | GB/T 32960 China national NEV reporting. Binary ## frame. Battery + GPS + alarms. id = VIN. |
| bms | bms | NW lithium protection board v2.8. Binary NW frame. Battery (voltage/current/temp/SoC/cells). |
| modbus | bms | Modbus RTU (fn 0x03). Universal BMS/charger fieldbus. Battery via register map. id from ?device=. |
| jbd | bms | JBD / Xiaoxiang smart BMS. Binary 0xDD…0x77. Battery. id from ?device=. |
| daly | bms | Daly smart BMS. Binary 13-byte frames. Battery. id from ?device=. |
| can | bus | Raw CAN frames (J1939 / CiA-454 via signal map). Battery. id from ?device=. |
| ocpp | infra | OCPP 1.6 MeterValues from charge/swap cabinets. JSON. Battery/station. id from ?device= + connectorId. |
Examples
generic_json: the simplest path; carries battery and GPS in one JSON document:
01curl -X POST https://api.rootd.cc/v1/ingest/generic_json \02 -H "Authorization: Bearer $INGEST_TOKEN" \03 -H "Content-Type: application/json" \04 -d '{"device":"BIKE-001","timestamp":"2026-06-24T09:00:00Z",05 "v":63.2,"i":-4.5,"temp":29,"soc":0.71,06 "lat":-1.286,"lon":36.817,"speed":18,"heading":75,"altitude":1680}'07# → 202 {"acceptedReadings":1,"acceptedLocations":1}Binary protocols: post the raw wire bytes (here, a JT808 0x0200 report):
01# Binary protocols (jt808, gt06, teltonika, gbt32960, bms, modbus, jbd, daly, can)02# post the raw wire bytes. Send hex through xxd, stream with --data-binary:03echo '7e0200002e8612345678900001...7e' | xxd -r -p | \04 curl -X POST https://api.rootd.cc/v1/ingest/jt808 \05 -H "Authorization: Bearer $INGEST_TOKEN" \06 --data-binary @-07# → 202 {"acceptedReadings":1,"acceptedLocations":1}Identity-less wires: supply the device with ?device= (here, Modbus):
01# Protocols whose wire carries no device id (modbus, can, jbd, daly, ocpp)02# take it from the ?device= query param:03echo '4e57002a60300002...68...' | xxd -r -p | \04 curl -X POST 'https://api.rootd.cc/v1/ingest/modbus?device=PACK-7' \05 -H "Authorization: Bearer $INGEST_TOKEN" --data-binary @-OCPP: charge/swap cabinets post MeterValues:
01curl -X POST 'https://api.rootd.cc/v1/ingest/ocpp?device=CP-001' \02 -H "Authorization: Bearer $INGEST_TOKEN" -H "Content-Type: application/json" \03 -d '[2,"uid","MeterValues",{"connectorId":1,"meterValue":[{04 "timestamp":"2026-06-24T09:00:00Z","sampledValue":[05 {"value":"63.5","measurand":"Voltage","unit":"V"},06 {"value":"80","measurand":"SoC","unit":"Percent"}]}]}]'Responses & errors
A successful POST returns 202 Accepted with the counts decoded from the payload. Control/heartbeat frames are accepted with zero counts.
01{ "acceptedReadings": 1, "acceptedLocations": 1 }| Field | Type | Description |
|---|---|---|
| 202 | Accepted | Decoded and persisted (or queued). |
| 401 | Unauthorized | Missing/invalid bearer token. |
| 403 | Forbidden | Token lacks the ingest role. |
| 404 | Not Found | Unknown {protocol} or unknown tenant. |
| 413 | Payload Too Large | Body over 1 MiB. |
| 422 | Unprocessable | Decode/validation failed: the payload is dead-lettered for inspection. |
| 429 | Too Many Requests | Per-tenant rate limit; honor Retry-After. |
| 503 | Unavailable | Downstream temporarily unhealthy; retry. |
Other protocols
Don't see your device? Three paths keep you covered:
- Cheap GPS trackers (Queclink, Ruptela, Meitrack, H02, TK103…): bridge them through an open tracker server into
generic_json. - OEM clouds (NIU, Yadea, Super Soco, Bosch eBike, Gogoro): forward their REST/webhook payloads to
generic_json. - Custom wire format: add a codec via the protocol SDK. Implement one
Decodefunction and register it. See the ingest reference.