--- type: API Endpoint title: Attendance routes description: POST /api/attendance/event, GET /api/attendance/state, GET /api/attendance/me — the employee's own clock in/out and stats. resource: backend/src/routes/attendance.ts tags: [api, attendance] timestamp: 2026-08-12T00:00:00Z --- # Attendance routes Mounted at `/api/attendance`. Every route requires `requireAuth` + `requireEmployee` — admins with no employee row get `403` here, by design (the owner isn't necessarily clocking in themselves). # Examples ``` POST /api/attendance/event Body: { "type": "clock_in" | "clock_out" | "break_start" | "break_end" } 201 -> { "event": AttendanceEvent, "status": LiveStatus } 400 -> invalid type 409 -> invalid transition for the current status, e.g. break_start while already clocked_out — { "error": string, "status": LiveStatus } ``` ``` GET /api/attendance/state 200 -> { "status": "clocked_out" | "working" | "on_break" } ``` ``` GET /api/attendance/me?month=YYYY-MM (or ?from=YYYY-MM-DD&to=YYYY-MM-DD) Defaults to the current calendar month if no query params are given — see parseRange in backend/src/util/dateRange.ts. 200 -> { "range": { "from": string, "to": string }, "sessions": Session[], "totalWorkedMs": number, "totalBreakMs": number, "shiftCount": number } ``` `Session` and the state machine behind these responses are documented at [attendance_events](/docs/data-model/attendance-events.md). # Related - [attendance_events](/docs/data-model/attendance-events.md) - [Admin routes](./admin-routes.md) — same stats shape, but for any employee - [Frontend stores](/docs/frontend/stores.md) — `attendanceStore` polls `GET /state` + `GET /me` every 60s and ticks a local clock every second between polls