Why the machine itself is not the API
Attendance machines are built to talk to one server, and their protocols are awkward to use from another app. The clean setup is: machines push punches to an attendance server (ADMS push mode), and the attendance server offers a proper API to your payroll, HR or website. Your other apps never touch the machines.
Option 1 — read it with a REST API
Your app asks when it needs data. With PunchSync the API looks like this:
| Item | Value |
|---|---|
| Address | https://your-domain.com/api/v1 |
| Sign in | Header Authorization: Bearer YOUR_API_KEY |
| Limit | 120 requests a minute per key |
| Format | JSON |
| Endpoint | Returns |
|---|---|
GET /employees | Employees, page by page |
GET /punches | Raw punches — send since_id to keep a copy in sync, or from / to dates (up to 31 days) |
GET /attendance | Worked-out days: status, first in, last out, late and overtime minutes |
GET /devices | Your machines |
GET /departments | Your departments |
curl -H "Authorization: Bearer YOUR_API_KEY" https://your-domain.com/api/v1/attendance
Payroll tip: use /attendance, not raw punches. It already applies shifts, holidays and leave, so late and overtime minutes match the reports your managers see.
Option 2 — be told with webhooks
Instead of asking every few minutes, give the attendance server your app's address. New punches arrive as a POST with a JSON body — up to 100 punches at a time, in order.
- The event for new punches is
punches.created; a test button sendsping. - Answer with any 2xx code within 10 seconds. Anything else counts as not delivered.
- Failed deliveries are retried after 1, 5, 30, 120 and 360 minutes.
- The same delivery can arrive twice — keep its id and ignore repeats.
Check the signature before you trust it
Each webhook has its own secret. The X-PunchSync-Signature header looks like t=1790000000,v1=5f3a…, where v1 is the HMAC-SHA256 (hex) of the time, a dot, and the raw body. In PHP:
<?php
$secret = 'YOUR_WEBHOOK_SECRET';
$body = file_get_contents('php://input');
parse_str(str_replace(',', '&', $_SERVER['HTTP_X_PUNCHSYNC_SIGNATURE'] ?? ''), $sig);
$expected = hash_hmac('sha256', ($sig['t'] ?? '') . '.' . $body, $secret);
$fresh = abs(time() - (int) ($sig['t'] ?? 0)) < 300;
if (! $fresh || ! hash_equals($expected, $sig['v1'] ?? '')) {
http_response_code(400);
exit;
}
// Trusted: json_decode($body, true)
Refusing old timestamps stops someone from replaying a copied message.
Which one should you use?
| REST API | Webhooks | |
|---|---|---|
| Best for | Monthly payroll runs, reports, syncing employees | Live dashboards, instant alerts, door or canteen systems |
| Your app needs | To call out | A public address to receive |
| Speed | When you ask | Seconds after the punch |
Many teams use both: webhooks for live updates, and the API once a month to double-check before payroll.