Time clock
Clock in and out, pauses, retroactive entries and the correction workflow over the append-only time-record ledger.
Clocking writes to an append-only ledger: clocking in, pausing, resuming and
clocking out each append a new entry that is never edited or deleted. Every entry
is chained to the previous one with a SHA-256 hash (per-company chain),
so any tampering is detectable. The live session state —not_started,
working, paused, finished— is derived from the ledger, not stored in a
column.
All endpoints live under https://api.factuarea.com/v1 and use the
time_entries:read / time_entries:write scopes, the same
error envelope and cursor pagination as
the rest of the API.
Clock in, pause, resume, clock out
Four write operations drive a working day. Each takes an optional occurred_at
(defaults to now) and a source, and returns the appended entry.
| Operation | Endpoint | From state |
|---|---|---|
| Clock in | POST /v1/time-entries/clock-in | not_started or finished |
| Start a pause | POST /v1/time-entries/pause | working |
| Resume | POST /v1/time-entries/resume | paused |
| Clock out | POST /v1/time-entries/clock-out | working or paused |
Two rules govern the sequence. One open day at a time: clocking in twice
returns 422 ("Ya has fichado la entrada."); pausing or clocking out with no open
day returns 422. Monotonic chronology: an occurred_at earlier than the
last event of the shift is rejected with 422. A day can have several shifts
(jornada partida) — clocking in again after clocking out opens a brand-new shift.
curl -X POST https://api.factuarea.com/v1/time-entries/clock-in \
-H "Authorization: Bearer $FACTUAREA_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "source": "web" }'Read the current open session with
GET /v1/time-entries/current, list entries with GET /v1/time-entries and fetch
one with GET /v1/time-entries/{time_entry} — all under time_entries:read. See
the schemas in the
API Reference.
Retroactive (manual) entries
POST /v1/time-entries/manual records a complete past shift (clock-in,
optional pauses and clock-out) for an employee who forgot to clock. A reason is
required — it is sealed into the hash chain as part of the evidence — and the
entry is flagged is_retroactive with source: manual. Unlike live self-service
clocking, a manual entry is a privileged action and is written to the audit log.
curl -X POST https://api.factuarea.com/v1/time-entries/manual \
-H "Authorization: Bearer $FACTUAREA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"employee_id": "01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a0b",
"started_at": "2026-02-03T09:00:00+01:00",
"ended_at": "2026-02-03T17:00:00+01:00",
"reason": "Forgot to clock in; confirmed by manager"
}'The correction workflow
A time record is never edited. To fix a mistake, an employee opens a
correction request; a manager or admin then approves or rejects it. A request
moves pending → approved or pending → rejected, both terminal.
| Operation | Endpoint | Effect |
|---|---|---|
| Request a correction | POST /v1/time-corrections | Creates a pending request. |
| Approve | POST /v1/time-corrections/{correction}/approve | Appends a correction entry to the original; emits time_entry.corrected. |
| Reject | POST /v1/time-corrections/{correction}/reject | Records a rejection with a reason; the original is untouched. |
| List / show | GET /v1/time-corrections, GET /v1/time-corrections/{correction} | Read the workflow state. |
Approval appends a new entry that references the original one — the mistake and
its fix both stay in the ledger. Two guards apply: you cannot approve your own
request (422), and a request already resolved cannot be resolved again (422).
curl -X POST https://api.factuarea.com/v1/time-corrections/01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a0b/approve \
-H "Authorization: Bearer $FACTUAREA_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "note": "Verified against the access log" }'There is no update or delete for a time record. Every correction is a new entry that keeps the original intact — that is what makes the register defensible before the Labour Inspectorate.
Verify chain integrity
GET /v1/time-entries/chain/validate recomputes the whole hash chain and reports
whether it is intact, returning the id of the first broken entry if any. It is a
read-only integrity check (rate-limited) — use it to prove the register has
not been altered.
Next steps
- Work schedules — the expected hours the ledger is measured against.
- Monthly close — freeze and seal a finished month.
- Explore the time-entries and time-corrections reference.