Protocol notes¶
The ZKTeco Push/ADMS protocol has no single public specification, and firmware varies. This
page records what the default ADMSProtocolAdapter does, what is covered by fixture tests, and
what is still uncertain. Anything uncertain is isolated in an adapter method you can override.
A device can use its own adapter via device.options["protocol_adapter"].
Endpoints¶
| Endpoint | Direction | Handling |
|---|---|---|
GET cdata?SN=&options=all&pushver= |
handshake | returns GET OPTION FROM: <SN> plus options: stamps (ATTLOGStamp, OPERLOGStamp, ATTPHOTOStamp, BIODATAStamp), ErrorDelay, Delay, TransTimes, TransInterval, TransFlag, TimeZone, Realtime, Encrypt, ServerVer, PushProtVer, ADMS_HANDSHAKE_EXTRA_OPTIONS, and per-device options |
POST cdata?table=ATTLOG&Stamp= |
punches | tab-separated lines PIN, time, status, verify, workcode, reserved...; extra columns kept |
POST cdata?table=OPERLOG |
ops + enrollment | OPLOG, USER, FP, BIODATA lines |
POST cdata?table=BIODATA / FINGERTMP / USERINFO |
templates | same parser; lines may omit the BIODATA prefix |
POST cdata?table=ATTPHOTO |
photos | acknowledged and ignored (out of scope); cursor advanced |
POST cdata?table=options |
device info | ~DeviceName=..,FWVersion=..,UserCount=.. |
GET getrequest?INFO= |
command poll | INFO is parsed positionally (firmware, users, fps, logs, IP, fp algorithm, ...); returns C:<id>:<cmd> lines or OK |
POST devicecmd |
command results | ID=..&Return=..&CMD=.. per line; lines after an INFO result are key/values |
GET ping |
keep-alive | OK |
POST registry |
push 3.x | stores device info, returns stable RegistryCode= |
POST push |
push 3.x | configuration (handshake body without the header line) |
POST querydata |
push 3.x | replies to DATA QUERY in OPERLOG-style lines |
GET rtdata?type=rttime |
push 3.x | DateTime=<zk-encoded>,ServerTZ=+HHMM |
| anything else under the prefix | fdata, edata, exchange, ... |
logged and acknowledged so devices do not retry forever |
cdata.aspx and trailing slashes are accepted.
Reply semantics¶
- Parsed OK, even with some bad lines →
OK: <lines>. Bad lines are logged asparse_errordevice events and never cause a re-send loop. - Database failure → HTTP 500 and the cursor is not advanced, so the device re-sends.
- Device pending approval → HTTP 403 for data, so the device keeps its logs.
- Disabled, unknown (no auto-register), bad token or disallowed IP → HTTP 403.
Commands¶
| Type | Push 2.x (FINGERTMP) |
BIODATA firmware | Legacy (options.legacy_commands) |
|---|---|---|---|
add_user |
DATA UPDATE USERINFO PIN=\tName=\tPri=... |
same | DATA USER ... |
delete_user |
DATA DELETE USERINFO PIN= |
same | DATA DEL_USER PIN= |
add_template |
DATA UPDATE FINGERTMP PIN=\tFID=\tSize=\tValid=1\tTMP= |
DATA UPDATE BIODATA Pin=\tNo=\tIndex=0\tValid=1\tDuress=\tType=1\tMajorVer=\tMinorVer=\tFormat=0\tTmp= |
DATA FP ... |
delete_template |
DATA DELETE FINGERTMP PIN=\tFID= |
DATA DELETE BIODATA Pin=\tType=1\tNo= |
DATA DEL_FP ... |
enroll_fingerprint |
ENROLL_FP PIN=\tFID=\tRETRY=\tOVERWRITE= |
ENROLL_BIO TYPE=1\tPIN=\tNO=\tRETRY=\tOVERWRITE= |
|
query_users / query_templates / query_attlog |
DATA QUERY USERINFO/FINGERTMP/ATTLOG ... |
DATA QUERY BIODATA ... |
|
clear_logs / clear_data |
CLEAR LOG / CLEAR DATA (safety-gated) |
||
set_time |
SET OPTION DateTime=<zk-encoded> (or ISO with options.set_time_format="iso") |
||
| others | REBOOT, INFO, CHECK, RELOAD OPTIONS, LOG, SET OPTION k=v, raw |
BIODATA is used when the device reports push version ≥ 2.4.0, has ever uploaded BIODATA
(capabilities.biodata), or sets options.biodata.
Open protocol questions¶
These are handled defensively and are overridable. Please report firmware behaviour.
- Setting the clock. There is no universal command. The default renders
SET OPTION DateTime=<ZK-encoded>. Some firmware wants ISO text, and many devices instead sync from the HTTPDateheader of server replies or fromrtdata?type=rttime. Overriderender_set_time. - Device time in requests. Few firmwares send their clock. The adapter recognises
DeviceTime/DevTimeparameters and anX-Device-Timeheader. Otherwise drift is known only in pull mode or fromINFO-type data.extract_device_timeis overridable. SizeinFINGERTMP. The default sends the base64 text length, which matches our fixtures. Some documents describe the binary size. Overridetemplate_size_value.MaxAttLogCountunits. Values below 1000 are treated as ×10,000 records.BIODATAIndex. The default always sendsIndex=0(one template per finger).- Stamps. ATTLOG stamps are treated as opaque strings echoed back in the handshake.
"Force re-upload" sets them to
0. Firmware that ignores stamp resets still re-sends onDATA QUERY ATTLOG, which the re-upload action also queues when a start date is given. - Encrypted push (
exchange,Encrypt=1). Not supported;Encrypt=Noneis sent. - Photos (
ATTPHOTO,fdata). Acknowledged and discarded (fingerprint-only scope).
Fixtures for each supported variant live in tests/fixtures/adms/, and every parser and
builder is covered by tests/test_adapter.py.