View Categories

Partner API Job Costing

5 min read

Partner API Job Costing #

This guide explains how to use the Friday API to track labor time by customer and project, then report on that time for job costing.


Prerequisites #

  • Plan: Timetracking or higher.
  • Auth: An API key for the company, sent as X-API-Key on every request.
  • Setup: Customers and projects should already exist in Friday. The API can list, fetch, and update them, but new customer/project setup happens in the Friday product.

How Job Costing Works #

Job costing in Friday is built from three pieces:

| Piece | Purpose |
|——-|———|
| Customer | The job, customer, or job site you want to track labor against. |
| Project | A more specific subdivision under a customer, such as a phase, location, or workstream. |
| Time record | The employee’s clock-in/clock-out span, optionally tagged with customer_id and project_id. |

When employees clock in against customers and projects, Friday can later group time by customer or project in timetrack reports.


Typical Flow #

  1. Sync customers and projects → GET /customers and GET /projects
  2. Clock employees into a job → POST /time-records/clock-in
  3. Clock employees out → POST /time-records/clock-out
  4. Request job-costing report details → GET /timetrack/company
  5. Optionally download reports → GET /timetrack/company/download

Step 1 — Sync Customers and Projects #

Use the customer and project endpoints to keep your system aligned with the jobs configured in Friday.

| Action | Endpoint |
|——–|———-|
| List customers | GET /customers |
| Get customer | GET /customers/:customer_id |
| Update customer | PATCH /customers/:customer_id |
| List projects | GET /projects |
| Get project | GET /projects/:project_id |
| Update project | PATCH /projects/:project_id |

Projects belong to customers. If your app lets users choose a job before clocking in, show the customer first, then the available projects under that customer.

See the Customers and Projects guide for the full customer/project model.


Step 2 — Clock Into a Customer or Project #

When creating a time record, include customer_id, project_id, or both.

POST /time-records/clock-in

{
“employee_id”: 25,
“type”: “work”,
“customer_id”: 3,
“project_id”: 7,
“note”: “Starting framing work”
}

The resulting time record stores the job information:

{
“data”: {
“time_record_id”: 1042,
“type”: “work”,
“start”: “2026-03-05T09:00:00.000Z”,
“end”: null,
“employee_id”: 25,
“customer_id”: 3,
“project_id”: 7,
“customers”: {
“customer_id”: 3,
“name”: “ABC Construction”
},
“projects”: {
“project_id”: 7,
“name”: “Office Renovation”
}
}
}

Some companies require a customer or project for every clock-in. If a required job is missing, the API returns a 400 error.

Disabled customers and projects cannot be used for new time records.


Step 3 — Switch Jobs During the Day #

Use type: "switch" when an employee stays clocked in but moves to a different customer or project.

{
“employee_id”: 25,
“type”: “switch”,
“customer_id”: 9,
“project_id”: 12,
“note”: “Moving to afternoon job”
}

A switch:

  1. Clocks out the current active work record.
  2. Creates a new work record with the new customer/project details.
  3. Returns the newly created time record.

switch is only a clock-in action. Stored records still have type: "work" or type: "break".


Step 4 — Get Job-Costing Breakdowns #

Use timetrack report endpoints when you need totals grouped by job.

Company report

GET /timetrack/company?start=2026-03-01T00:00:00.000Z&end=2026-03-07T23:59:59.999Z&include_customer_reports=true&include_project_reports=true

Employee report

GET /timetrack/employee/25?start=2026-03-01T00:00:00.000Z&end=2026-03-07T23:59:59.999Z&include_customer_reports=true&include_project_reports=true

| Query parameter | Purpose |
|—————–|———|
| start | Report start datetime, inclusive. |
| end | Report end datetime, inclusive. |
| timezone | Optional IANA timezone or numeric UTC offset. Defaults to America/New_York. |
| include_customer_reports=true | Include time broken down by customer. |
| include_project_reports=true | Include time broken down by project. |
| include_days=true | Include per-day breakdowns. |
| include_time_records=true | Include raw time records behind the totals. |

Example customer breakdown:

{
“customer_reports”: [
{
“customer”: {
“customer_id”: 3,
“name”: “ABC Construction”
},
“report”: {
“regular_hours”: 40,
“overtime_hours”: 3,
“total_hours”: 43
}
},
{
“customer”: {
“customer_id”: 9,
“name”: “XYZ Plumbing”
},
“report”: {
“regular_hours”: 12,
“overtime_hours”: 0,
“total_hours”: 12
}
}
]
}


Step 5 — Download Job-Costing Reports #

Use the company download endpoint when you need a PDF or CSV export.

GET /timetrack/company/download

Required query parameters:

| Parameter | Purpose |
|———–|———|
| start | Report start datetime, inclusive. |
| end | Report end datetime, inclusive. |
| type | Output format: pdf, periodTotalsCsv, dailyTotalsCsv, or timeRecordsCsv. |

Useful optional parameters:

| Parameter | Purpose |
|———–|———|
| timezone | Timezone for report grouping. |
| timetype | Format time values as decimal or minutes. |
| employeeIds | Comma-separated employee IDs to include. |
| pay_schedule_group_id | Restrict the report to one pay schedule group. |


Job Geofencing #

If the company uses job geofencing, clock-in and clock-out may require coordinates. The applicable fence comes from the customer/project on clock-in, or from the active time record on clock-out.

Send coordinates as:

latitude,longitude

Example:

{
“employee_id”: 25,
“customer_id”: 3,
“project_id”: 7,
“start_coordinates”: “40.7128,-74.0060”
}

If coordinates are missing or outside the allowed perimeter, the API rejects the request with a 400 error.


Try It Out #

Use the API Reference to test a job-costing flow in sandbox:


Common Pitfalls #

  • Using disabled jobs — Disabled customers and projects cannot be used for new clock-ins.
  • Forgetting to include customer/project report flags — Job-costing breakdowns only appear when include_customer_reports=true or include_project_reports=true.
  • Expecting switch to appear in reports — Switches create normal work records; they do not create a separate stored record type.
  • Missing geofence coordinates — If a job requires geofencing, include coordinates on clock-in and clock-out.
  • Mixing environments — Sandbox and production have separate customers, projects, time records, and API keys.

Quick Reference #

| Action | Method | Path |
|——–|——–|——|
| List customers | GET | /customers |
| List projects | GET | /projects |
| Clock into a job | POST | /time-records/clock-in |
| Switch jobs | POST | /time-records/clock-in with type: "switch" |
| Clock out | POST | /time-records/clock-out |
| Company job-costing report | GET | /timetrack/company |
| Employee job-costing report | GET | /timetrack/employee/:employee_id |
| Download report | GET | /timetrack/company/download |