🎉 Chrismass Season Offer: All prices now come with 15% OFF! Enjoy your discount today.

Developer Guide

Overview

Boldet ZK acts as a gateway between your Hardware devices and your application. It automatically sends attendance and punch logs to your webhook in real time, letting your system react instantly — no polling or manual syncing needed.

Supported Device Models

Boldet ZK supports all ZKTeco devices that use the same firmware family as the MB20-VL (ZMM series).

  • ZKTeco MB10-VL
  • ZKTeco MB20-VL
  • ZKTeco MB200
  • ZKTeco MB300
  • ZKTeco MB560-VL
  • ZKTeco EFace10
  • ZMM510 Series (ZMM510 / ZMM210 / ZMM220 / ZMM720)

ZKTeco MB20-VL have been tested and verified to work with Boldet ZK using the same push-protocol and cloud settings.

Getting Started

  1. Sign in to your Boldet ZK dashboard.
  2. Go to Devices → Add Device.
  3. Provide the following details:
    • Device Name – friendly name for your hardware unit
    • Serial Number – printed on the back or shown on the device screen
    • Webhook URL – your HTTPS endpoint to receive real-time data
  4. Click Save to register.
  5. Ensure the device is online and configured with the IP shown on your dashboard.

Webhook Data Format

Boldet ZK sends data to your webhook as JSON whenever a punch is recorded on the device.

{
  "device_sn": "ZK123456789",
  "timestamp": "2025-10-29T19:14:03Z",
  "user_id": "1"
}

Respond with HTTP 200 OK to confirm receipt. If no success response is received, Boldet will automatically retry delivery.

Security

Each request includes a secure API Key Secret we used to verify authenticity. Treat this key like a password — it ensures the data truly comes from Boldet and the device belongs to you.

💡 Security Tip: Store your API Key secret securely.

Example Integrations

Use these examples to receive and verify webhook data in your preferred language.

@http.route('/your/hook', auth="public", methods=['POST'], csrf=False)
def boldet_info_punches(self, **kwargs):
    raw_data = request.httprequest.json
    data = raw_data
    print("Received data:", data)
    return "OK", 200
const express = require('express');
const app = express();

app.use(express.json());

app.post('/your/hook', (req, res) => {
  const data = req.body;
  console.log('Received data:', data);
  res.status(200).send('OK');
});

app.listen(5000, () => console.log('Server running on port 5000'));
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $data = json_decode(file_get_contents('php://input'), true);
    if ($data) {
        error_log('Received data: ' . print_r($data, true));
        echo 'OK';
    } else {
        http_response_code(400);
        echo 'Invalid JSON';
    }
} else {
    http_response_code(405);
    echo 'Only POST allowed';
}
?>
package main

import (
    "fmt"
    "net/http"

    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default()

    r.POST("/your/hook", func(c *gin.Context) {
        var data map[string]interface{}
        if err := c.BindJSON(&data); err != nil {
            c.String(http.StatusBadRequest, "Invalid JSON")
            return
        }
        fmt.Println("Received data:", data)
        c.String(http.StatusOK, "OK")
    })

    r.Run(":5000")
}