Timetracking
This guide explains how the Friday API tracks employee time with time records, how clock-in and clock-out work, what a switch is, and how to read time records and timetrack reports.
Prerequisites
- Plan: Timetracking or higher.
- Auth: An API key for the company, sent as
X-API-Keyon every request. - Employees: The employee must belong to the company associated with your API key and must be active.
What Is a Time Record?
A time record represents one continuous span of employee time. It starts when an employee clocks in and ends when they clock out.
An active time record has end: null.
{
"time_record_id": 1042,
"type": "work",
"start": "2026-03-05T09:00:00.000Z",
"end": null,
"employee_id": 25,
"customer_id": 3,
"project_id": 7,
"note": "Starting morning shift"
}| Field | Meaning |
|---|---|
type | Either work or break. |
start | Clock-in timestamp. |
end | Clock-out timestamp, or null while the record is active. |
employee_id | Employee whose time is being tracked. |
customer_id | Optional customer/job associated with the time. |
project_id | Optional project associated with the time. |
note / end_note | Optional notes captured at clock-in or clock-out. |
Typical Flow
1. Clock in for work → POST /time-records/clock-in
2. Optionally start break → POST /time-records/clock-in with type: "break"
3. Resume or switch work → POST /time-records/clock-in with type: "work" or "switch"
4. Clock out → POST /time-records/clock-out
5. Read history/reports → GET /time-records or /timetrack/*
The API keeps only one active record per employee at a time. When a new valid clock-in starts a different type of record, the existing active record is automatically ended first.
Clock In
POST /time-records/clock-in
Clock-in starts a new active time record for an employee. The only required field is employee_id.
If type is omitted, the API defaults to work.
{
"employee_id": 25,
"type": "work",
"customer_id": 3,
"project_id": 7,
"note": "Starting morning shift",
"start_coordinates": "40.7128,-74.0060",
"start_location": "Job site - Main St"
}| Field | Required? | Notes |
|---|---|---|
employee_id | Yes | Employee to clock in. |
type | Optional | work, break, or switch. Defaults to work. |
customer_id | Optional | Customer/job to associate with the record. May be required by company settings. |
project_id | Optional | Project to associate with the record. May be required by company settings. |
note | Optional | Clock-in note. |
start_coordinates | Conditional | Required when job geofencing applies. Format: latitude,longitude. |
start_location | Optional | Human-readable clock-in location label. |
Conflicts and validation
- If the employee already has an active record of the same type, the API returns
409. - If the employee starts a different type of record, the existing record is automatically clocked out first.
- If company settings require a customer or project and neither is provided, the API returns
400. - If a specified customer or project is disabled, the API returns
400. - If job geofencing applies and coordinates are missing, invalid, or outside the allowed perimeter, the API returns
400.
Breaks
Use type: "break" when an employee pauses work but remains in the middle of their day.
{
"employee_id": 25,
"type": "break",
"note": "Lunch break"
}An employee must already have an active work record before starting a break. If they are not clocked in, the API returns:
{
"error": "Employee must be clocked in to take a break"
}When the break starts, the active work record is ended and a break record begins.
Switches
Use type: "switch" when an employee stays clocked in but changes what they are working on, such as moving from one customer or project to another.
{
"employee_id": 25,
"type": "switch",
"customer_id": 8,
"project_id": 12,
"note": "Moving to afternoon job"
}A switch:
- Automatically clocks out the current active work record.
- Creates a new
workrecord with the new customer/project/note details. - Returns the newly created time record.
Important:
switchis a request action, not a stored time record type. The new record is stored and returned astype: "work".
Clock Out
POST /time-records/clock-out
Clock-out ends the employee's current active time record.
{
"employee_id": 25,
"end_note": "Finished for the day",
"end_coordinates": "40.7128,-74.0060",
"end_location": "Job site - Main St"
}| Field | Required? | Notes |
|---|---|---|
employee_id | Yes | Employee to clock out. |
end_note | Optional | Clock-out note. |
end_coordinates | Conditional | Required when job geofencing applies to the active record. |
end_location | Optional | Human-readable clock-out location label. |
If the employee has no active time record, the API returns 409.
Customers, Projects, and Geofencing
Time records can be associated with a customer, a project, or both. Companies may require a customer or project on clock-in. Use the Customers and Projects guide for more detail on how those objects relate.
If job geofencing applies, clock-in and clock-out require coordinates in latitude,longitude format. The API enforces the same customer/project geofencing rules configured in Friday.
Example coordinate value:
40.7128,-74.0060
If coordinates are missing or outside the allowed perimeter, the request is rejected with a clear error message.
Reading Time Records
GET /time-records
Returns a paginated list of time records sorted by start time, newest first.
| Query parameter | Purpose |
|---|---|
page, per_page | Pagination. |
employee_id | Filter by employee. |
type | Filter by work or break. |
start_after | Only records that started on or after this timestamp. |
start_before | Only records that started on or before this timestamp. |
active=true | Only currently active records. |
GET /time-records/:time_record_id
Returns one time record with additional detail fields such as coordinates, expiration, note image URLs, and employee summary.
Timetrack Reports
Use timetrack report endpoints when you need totals rather than raw records.
| Action | Endpoint |
|---|---|
| Company report | GET /timetrack/company |
| Employee report | GET /timetrack/employee/:employee_id |
| Download report | GET /timetrack/company/download |
Company and employee reports require start and end query parameters. Optional include_* parameters let you include day breakdowns, raw time records, customer reports, and project reports.
Downloads support PDF and CSV outputs.
Try It Out
Use the API Reference to test a full time tracking flow in sandbox:
Common Pitfalls
- Starting a break before work — A break requires an active work record.
- Using
switchas a record type filter —switchis only accepted in the clock-in request. Stored records areworkorbreak. - Missing customer/project requirements — Some companies require customer or project selection for clock-in.
- Disabled customer or project — Disabled jobs cannot be used for new time records.
- Missing geofence coordinates — If geofencing applies, send
start_coordinatesorend_coordinatesas required. - Wrong environment — Sandbox and production keys are separate, and each key must be used with the matching base URL.
Quick Reference
| Action | Method | Path |
|---|---|---|
| List time records | GET | /time-records |
| Get time record | GET | /time-records/:time_record_id |
| Clock in | POST | /time-records/clock-in |
| Clock out | POST | /time-records/clock-out |
| Company time report | GET | /timetrack/company |
| Employee time report | GET | /timetrack/employee/:employee_id |
| Download time report | GET | /timetrack/company/download |
Updated about 9 hours ago
