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.

Getting Started

  1. Sign in to your Boldet ZK dashboard.
  2. Go to DevicesAdd 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 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")
}