Skip to main content
If you are reading attendance out of OnTime, this is the page that determines whether your numbers are right.

Punches are facts, days are derivations

A punch is an immutable event. A day record is a derivation over that day’s punches, the employee’s shift template, approved leave, approved overtime, and the holiday calendar. The day record is re-derived, not incrementally patched. Every writer — a punch landing, an approval, the nightly close — runs the same derivation and produces the same row from the same inputs.
This is why approvals are described as inputs to the day rather than writers of it. An approved overtime request is read again on every later derivation, so a manager’s decision survives the employee’s next punch on that date.

Deduplication

Biometric punches deduplicate on the triple (deviceId, transId, logTime). A terminal replaying its buffer after a network outage cannot double-count — the same event arriving twice is recognised and ignored.
If you are ingesting attendance and reconciling against your own records, do not assume a punch you see today is one you have not seen before. Use the punch’s own id.

Today is not final

A day’s record changes until the day is closed. Reading today’s attendance gives you a provisional answer.Most consequentially: Absent is never written to a day still in progress. An employee who has not punched yet is not a no-show, so a query for today’s absences returns nothing — even at 4pm, even for someone who never turned up.

The nightly close

A daily sweep finalizes every employee’s record for the previous day. Two properties an integration should rely on:

It closes yesterday, never today

Closing a day still in progress would hand the derivation a live clock. So Absent for a given date lands the following morning, not at midnight.

It re-derives rather than asserts

Running it twice, or after a punch has already reconciled the day, produces the same row. It is a check, not a job — a missed run is picked up by the next one.

What this means for your queries

1

Read closed days, not today

For anything where the number matters — payroll feeds, absence reports, compliance — query dates that have been closed. Yesterday is safe from mid-morning; today is not safe at all.
2

Expect a day to change after you read it

An approved regularization rewrites a past day, and payroll data is corrected all the time. A monthly export should re-read the month rather than accumulating dailies.
3

Treat a frozen day as final

A day inside a frozen payroll month will not re-derive. That is the strongest “this is settled” signal available.

Frozen days

Freezing a payroll cycle marks every day record in the month frozen. Afterwards:
  • New punches for those dates are refused with 409 day_frozen.
  • Approvals that would rewrite one of those days are refused, and the whole approval rolls back — the request stays pending rather than being marked approved with no effect.
An administrator can lift the freeze on an individual day through an audited override. There is no bulk unfreeze.

Day statuses

Two known gaps in status derivation. A holiday that is worked still reconciles as Present rather than a distinct holiday-worked status. And a weekly-off day with no punches reconciles to Absent rather than WeeklyOff in cases outside the shift template’s configured weekly offs.If you compute loss of pay from Absent, the second one matters — cross-check against the employee’s shift and the holiday calendar rather than trusting Absent alone.