Time Tracking integrations

This guide is for partners connecting an external time & attendance system (physical clocks, biometric terminals, mobile clock-in apps, workforce management platforms) with Factorial's Time Tracking module.

The goal is to push clock-in / clock-out events into Factorial in near real time, so that Factorial can act as the single source of truth for worked time, overtime, and payroll pre-processing.

Authentication

Factorial supports OAuth 2 and API Keys authentication methods.

Recommendation is using an OAuth 2.0 company token with time_tracking OAuth Scope

⚠️

OAuth 2.0 with a company token is mandatory for partner integrations.

Employee identification

Factorial's API identifies employees by their internal employee_id. You must maintain a mapping between your device. These are a few options

  1. company_identifier. A customer-controlled field on the employee (badge number, HR code, personnel number). Fetch employees via GET /employees/employees and match on it.
  2. A custom field that can be retrieved by CustomFields > Value

You can cache the mapping locally and refresh it periodically, or subscribe to employees/employee/* webhooks to keep it fresh.


Time format

  • All timestamps: ISO-8601 with timezone offset (e.g. 2024-06-23T11:00:00+02:00).
  • Dates: YYYY-MM-DD.
  • Always send the offset the employee was in when the event happened

Integration flow

There are two possible topologies. You can pick the one that better matches your case.

A) Real-time streaming (physical clocks, terminals, mobile apps)

  1. Employee taps / scans on your device.
  2. Resolve device id → Factorial employee_id from your cached mapping.
  3. Call Attendance > Shift > Toggle clocks with employee_id and the ISO-8601 timestamp. Factorial figures out whether it's an entry or an exit based on the employee's current shift state.
  4. Store the returned id.
  5. On failure, retry with idempotency: Attendance > Shift to check whether the shift already exists before retrying.

Alternatives when your device semantically distinguishes events:

B) Batch sync (end-of-day upload from a workforce management system)

  1. Collect completed shifts for the period.
  2. For each shift, call POST /attendance/shifts with the full shift (employee, date, clock-in, clock-out).
  3. Store the returned id.
  4. On a schedule, GET /attendance/shifts?updated_at=... to pull manual corrections done in Factorial back into your system.

Two-way sync

Subscribe to attendance/shift/* webhooks (clock_in, clock_out, create, update, delete) to reflect manual edits made in Factorial back to your system. See Webhooks reference.

Best practices

  • Always include timezone offsets in timestamps — the #1 source of bugs.
  • Respect the open-shift model. A clock_in opens a shift until a matching clock_out. Don't send two consecutive clock_in events for the same employee.
  • Use breaks endpoints rather than closing and reopening shifts.
  • Idempotency. The API does not deduplicate — check existing shifts before retrying.
  • API versioning. Endpoints are versioned (/api/YYYY-MM-DD/...). Monitor the changelog.

We're excited to see the integration you build! 🚀