All API routes live under /api/. Every response follows the same envelope:
{ "success": true, "data": { ... } }
{ "success": false, "error": "Human readable message" }All protected routes require a valid JWT access token in the staffos_token cookie. Token verification happens inside each handler.
Creates a new user account with status UNVERIFIED. Sends a verification email.
Body: { name, email, password }
Authenticates a user and sets cookie tokens.
Body: { email, password, code? } where code is the 6-digit TOTP code if 2FA is enabled.
Clears cookies and removes the refresh token from the database.
Issues a new access token using the refresh token cookie.
Verifies an email address and sets status to PENDING. Notifies admins.
Resends a verification email. Body: { email }
Applies a pending email change after the user clicks the link in their new inbox.
Returns a QR code and TOTP secret for setting up 2FA. Admin or Manager only sets up their own.
Confirms and enables 2FA. Body: { code } (6-digit TOTP code to verify setup).
Disables 2FA. Body: { code } (current TOTP code to confirm).
Changes the authenticated user's password. Body: { currentPassword, newPassword }
Initiates an email change. Admin and Manager trigger a confirmation link. Staff submit a request for admin approval. Body: { newEmail }
Returns the current user's four notification preference booleans.
Updates one or more notification preferences. Body: any subset of { notifTaskAssigned, notifNewMessage, notifAnnouncements, notifWeeklyDigest }
Updates the current user's own profile photo. Body: { avatar } where avatar is an image data: URI (e.g. data:image/jpeg;base64,...) or null to remove the photo. Self only - not for editing anyone else's profile, and separate from /api/staff/[id] so an avatar change doesn't get written into that endpoint's audit log entry.
Returns a paginated list of users with employee details. Supports ?page, ?limit, ?search, ?department, ?status query params. Admin and Manager only.
Returns a single user with full employee details including department, supervisor, documents, work history, and performance reports.
Updates a user's profile fields. Body can include: { name, jobTitle, phone, address, departmentId, supervisorId, role, status }
Deletes a user and their employee record. Admin only.
Returns all users with PENDING or UNVERIFIED status. Admin and Manager only.
Approves or rejects a registration. Body: { userId, action } where action is approve or reject.
Resends a verification email to an UNVERIFIED user. Body: { userId }
Returns tasks. Staff see only their assigned tasks. Admin and Manager see all. Supports ?status, ?priority, ?departmentId, ?assigneeId filters.
Creates a task. Admin and Manager only. Body: { title, description?, priority, status, departmentId?, assigneeId?, deadline? }
Returns a single task with comments.
Updates a task. Staff can update status only on tasks assigned to them.
Deletes a task. Admin only.
Adds a comment to a task. Body: { content, authorId, fileName?, fileType?, fileData? }
Returns attendance records. Supports ?employeeId, ?month (YYYY-MM format), ?page, ?limit. Staff see only their own records.
Creates or updates an attendance record for a given employee and date. Admin and Manager only. Uses upsert on the unique (employeeId, date) constraint. Body: { employeeId, date, status, clockIn?, clockOut?, note? }
Deletes a record by id. Admin and Manager only. Body: { id }
Returns leave requests. Staff see only their own. Supports ?status and ?employeeId filters.
Creates a leave request. Working days are calculated automatically, excluding weekends. Body: { type, startDate, endDate, reason?, employeeId? } where employeeId is only honoured for Admin and Manager.
Reviews or cancels a request. Body: { id, action, reviewNote? } where action is approve, reject, or cancel. Staff can only cancel their own pending requests. Approving a leave that covers today sets the employee status to ON_LEAVE.
Deletes a leave request. Admin only. Body: { id }
Returns all system settings as a flat key-value object. Authenticated users only.
Updates one or more settings. Admin only. Body: any key-value pairs from the settings schema. Changes are audit logged.
Current toggleable feature keys: payrollEnabled, attendanceEnabled, leaveEnabled, messagesEnabled, reportsEnabled - see Roles and Permissions.
Heartbeat - marks the current user active. Called automatically every ~25 seconds while the app is open. Body: { status? } where status is "online" or "away", determined client-side from real mouse/keyboard/scroll activity (10 minutes idle -> "away"). Only affects what's shown if the user hasn't manually overridden their status.
Sets or clears a manual status override. Body: { override } where override is null (back to automatic), "away", or "dnd".
Returns { [userId]: "online" | "away" | "dnd" | "offline" } for the given comma-separated user ids. "offline" if no heartbeat in the last 60 seconds (takes priority over any override); otherwise the override if set; otherwise the auto-detected status from the last heartbeat.
Quick search across staff (name, email) and tasks (title) for the top bar's search box. Minimum 2 characters, 5 results per type, case-insensitive. Returns { staff: [...], tasks: [...] }.
Returns conversations for the current user, grouped by the other participant.
Sends a message. Body: { receiverId, content }. If the receiver has notifNewMessage enabled, an email notification is sent.
Marks a message as read.
Sends an announcement email to all active users with notifAnnouncements enabled. Admin and Manager only. Body: { subject, body }. The action is audit logged with a recipient count.
Returns all departments.
Creates a department. Admin only. Body: { name, description? }
Updates a department. Admin only.
Deletes a department if it has no employees or tasks. Admin only.
Returns performance reports. Supports ?employeeId filter.
Creates a performance report. Admin and Manager only.
Returns a full staff export as JSON for Excel or PDF generation.
Returns task completion statistics.
Returns a full JSON export of all data. Admin only.
Sends the weekly digest email to all active users with notifWeeklyDigest enabled. Protected by the Authorization: Bearer {CRON_SECRET} header. Called automatically by Vercel Cron on Monday mornings.
Tests the Gmail SMTP connection and sends a test email to GMAIL_USER. Admin only. Returns { sentTo } on success.