Days, punches, and the requests that correct them. Read the attendance settings before interpreting any record — a late_minutes of 20 means nothing until you know the grace period was 15.
/v1/attendance_sites needs a plan that includes GPS attendance & field visits (geo_attendance). On a plan without it, requests return 402 with code: plan_upgrade_required and feature naming what an upgrade would add.
List attendance records
GET/v1/attendance_records
Query parameters
| Name | Type | Required | Description |
|---|
limit | integer | No | Page size. Values above 100 are clamped. |
starting_after | string | No | Opaque cursor from a previous response’s next_cursor. |
updated_since | timestamp | No | Return records changed at or after this instant. Tracks the record itself, not its child collections. |
employee_id | string | No | Only records belonging to this employee. |
date_from | date | No | Inclusive lower bound on the record's own date. |
date_to | date | No | Inclusive upper bound — the named day is included. |
status | string (enum) | No | Only days with this status. |
Responses
| Status | Meaning |
|---|
200 | A page of attendance records. |
401 | The API key is missing, malformed, revoked or expired. |
403 | The key does not carry the required scopes. |
429 | Rate limit exceeded. See the RateLimit-* headers. |
Mark attendance
POST/v1/attendance_records
Marks one day for one employee. There is at most one record per (employee, date), so this REPLACES an existing day rather than adding a second one — which is why it answers 200 and not 201.
Unless is_manual_override is set, a status the punches contradict is re-graded by the workspace's own late thresholds: sending present for a day with a two-hour late clock-in can come back as absent. That is usually what you want, and occasionally the opposite.
| Name | Type | Required | Description |
|---|
Idempotency-Key | string | No | A unique value per logical request. Replaying it returns the original response with Idempotent-Replay: true. |
Responses
| Status | Meaning |
|---|
200 | The resulting attendance record. |
400 | The request body failed validation. |
401 | The API key is missing, malformed, revoked or expired. |
403 | The key does not carry the required scopes. |
409 | The request conflicts with the current state. |
429 | Rate limit exceeded. See the RateLimit-* headers. |
Retrieve an attendance record
GET/v1/attendance_records/{id}
Path parameters
| Name | Type | Required | Description |
|---|
id | string | Yes | The identifier returned as id on the object. |
Responses
| Status | Meaning |
|---|
200 | The attendance record. |
401 | The API key is missing, malformed, revoked or expired. |
403 | The key does not carry the required scopes. |
404 | No such attendance record in this workspace. |
429 | Rate limit exceeded. See the RateLimit-* headers. |
List attendance punches
GET/v1/attendance_punches
Query parameters
| Name | Type | Required | Description |
|---|
limit | integer | No | Page size. Values above 100 are clamped. |
starting_after | string | No | Opaque cursor from a previous response’s next_cursor. |
employee_id | string | No | Only records belonging to this employee. |
punch_type | in · out | No | Only clock-ins, or only clock-outs. |
punched_after | timestamp | No | Inclusive lower bound on punch_time. |
punched_before | timestamp | No | Exclusive upper bound on punch_time. |
Responses
| Status | Meaning |
|---|
200 | A page of attendance punches. |
401 | The API key is missing, malformed, revoked or expired. |
403 | The key does not carry the required scopes. |
429 | Rate limit exceeded. See the RateLimit-* headers. |
Create an attendance punch
POST/v1/attendance_punches
Records a punch and applies it to the day, exactly as a device punch is applied — attribution date, lateness grading and the checkout window all behave identically.
punch_time may be backdated, since a time clock that lost connectivity has to be able to push what it buffered. It may not be post-dated.
A punch that changes no attendance record answers 409, not 201: a clock-in when the employee is already clocked in, a clock-out with no open record, or a clock-out past the checkout window. The punch is still written to the log in every one of those cases, so a 409 here means "the punch was kept but the day did not move", never "nothing happened".
| Name | Type | Required | Description |
|---|
Idempotency-Key | string | No | A unique value per logical request. Replaying it returns the original response with Idempotent-Replay: true. |
Responses
| Status | Meaning |
|---|
201 | The resulting attendance punch. |
400 | The request body failed validation. |
401 | The API key is missing, malformed, revoked or expired. |
403 | The key does not carry the required scopes. |
409 | The punch was recorded in the log but changed no attendance record. detail says which case applied. |
429 | Rate limit exceeded. See the RateLimit-* headers. |
Retrieve an attendance punch
GET/v1/attendance_punches/{id}
Path parameters
| Name | Type | Required | Description |
|---|
id | string | Yes | The identifier returned as id on the object. |
Responses
| Status | Meaning |
|---|
200 | The attendance punch. |
401 | The API key is missing, malformed, revoked or expired. |
403 | The key does not carry the required scopes. |
404 | No such attendance punch in this workspace. |
429 | Rate limit exceeded. See the RateLimit-* headers. |
Retrieve the attendance settings
GET/v1/attendance_settings
A workspace singleton, so there is no id. Read-only: these rules change how existing pay is calculated, which is not something an integration should be able to do in a single call.
Read it before interpreting any attendance record — a late_minutes of 20 means nothing until you know the grace period was 15.
Responses
| Status | Meaning |
|---|
200 | The settings. |
401 | The API key is missing, malformed, revoked or expired. |
403 | The key does not carry the required scopes. |
429 | Rate limit exceeded. See the RateLimit-* headers. |
List attendance regularizations
GET/v1/attendance_regularizations
Query parameters
| Name | Type | Required | Description |
|---|
limit | integer | No | Page size. Values above 100 are clamped. |
starting_after | string | No | Opaque cursor from a previous response’s next_cursor. |
updated_since | timestamp | No | Return records changed at or after this instant. Tracks the record itself, not its child collections. |
employee_id | string | No | Only records belonging to this employee. |
status | pending · approved · rejected | No | Only requests in this state. |
date_from | date | No | Inclusive lower bound on the record's own date. |
date_to | date | No | Inclusive upper bound — the named day is included. |
Responses
| Status | Meaning |
|---|
200 | A page of attendance regularizations. |
401 | The API key is missing, malformed, revoked or expired. |
403 | The key does not carry the required scopes. |
429 | Rate limit exceeded. See the RateLimit-* headers. |
Create an attendance regularization
POST/v1/attendance_regularizations
Asks to correct one day's attendance. Refused for an employee whose shift does not require punches — there is no missing-punch state to fix.
| Name | Type | Required | Description |
|---|
Idempotency-Key | string | No | A unique value per logical request. Replaying it returns the original response with Idempotent-Replay: true. |
Responses
| Status | Meaning |
|---|
201 | The resulting attendance regularization. |
400 | The request body failed validation. |
401 | The API key is missing, malformed, revoked or expired. |
403 | The key does not carry the required scopes. |
409 | A regularisation for this employee and date is already awaiting a decision. |
429 | Rate limit exceeded. See the RateLimit-* headers. |
Retrieve an attendance regularization
GET/v1/attendance_regularizations/{id}
Path parameters
| Name | Type | Required | Description |
|---|
id | string | Yes | The identifier returned as id on the object. |
Responses
| Status | Meaning |
|---|
200 | The attendance regularization. |
401 | The API key is missing, malformed, revoked or expired. |
403 | The key does not carry the required scopes. |
404 | No such attendance regularization in this workspace. |
429 | Rate limit exceeded. See the RateLimit-* headers. |
Approve an attendance regularization
POST/v1/attendance_regularizations/{id}/approve
Approving REWRITES that day's attendance record and stamps it source: regularization, which then protects it from the automatic recompute. Answers 409 if the request was already decided, or if it is the API key creator’s own and another approver can decide it.
Path parameters
| Name | Type | Required | Description |
|---|
id | string | Yes | The identifier returned as id on the object. |
Responses
| Status | Meaning |
|---|
200 | The decided attendance regularization. |
401 | The API key is missing, malformed, revoked or expired. |
403 | The key does not carry the required scopes. |
404 | No such attendance regularization in this workspace. |
409 | This request has already been decided, or it is the API key creator’s own and another approver can decide it. |
429 | Rate limit exceeded. See the RateLimit-* headers. |
Reject an attendance regularization
POST/v1/attendance_regularizations/{id}/reject
Approving REWRITES that day's attendance record and stamps it source: regularization, which then protects it from the automatic recompute. Answers 409 if the request was already decided, or if it is the API key creator’s own and another approver can decide it.
Path parameters
| Name | Type | Required | Description |
|---|
id | string | Yes | The identifier returned as id on the object. |
Responses
| Status | Meaning |
|---|
200 | The decided attendance regularization. |
401 | The API key is missing, malformed, revoked or expired. |
403 | The key does not carry the required scopes. |
404 | No such attendance regularization in this workspace. |
409 | This request has already been decided, or it is the API key creator’s own and another approver can decide it. |
429 | Rate limit exceeded. See the RateLimit-* headers. |
List overtime requests
GET/v1/overtime_requests
Query parameters
| Name | Type | Required | Description |
|---|
limit | integer | No | Page size. Values above 100 are clamped. |
starting_after | string | No | Opaque cursor from a previous response’s next_cursor. |
updated_since | timestamp | No | Return records changed at or after this instant. Tracks the record itself, not its child collections. |
employee_id | string | No | Only records belonging to this employee. |
status | pending · approved · rejected | No | Only requests in this state. |
date_from | date | No | Inclusive lower bound on the record's own date. |
date_to | date | No | Inclusive upper bound — the named day is included. |
Responses
| Status | Meaning |
|---|
200 | A page of overtime requests. |
401 | The API key is missing, malformed, revoked or expired. |
403 | The key does not carry the required scopes. |
429 | Rate limit exceeded. See the RateLimit-* headers. |
Create an overtime request
POST/v1/overtime_requests
Claims overtime for one day. A workspace with auto-approval enabled returns the request already approved.
| Name | Type | Required | Description |
|---|
Idempotency-Key | string | No | A unique value per logical request. Replaying it returns the original response with Idempotent-Replay: true. |
Responses
| Status | Meaning |
|---|
201 | The resulting overtime request. |
400 | The request body failed validation. |
401 | The API key is missing, malformed, revoked or expired. |
403 | The key does not carry the required scopes. |
409 | An overtime request for this employee and date is already awaiting a decision. |
429 | Rate limit exceeded. See the RateLimit-* headers. |
Retrieve an overtime request
GET/v1/overtime_requests/{id}
Path parameters
| Name | Type | Required | Description |
|---|
id | string | Yes | The identifier returned as id on the object. |
Responses
| Status | Meaning |
|---|
200 | The overtime request. |
401 | The API key is missing, malformed, revoked or expired. |
403 | The key does not carry the required scopes. |
404 | No such overtime request in this workspace. |
429 | Rate limit exceeded. See the RateLimit-* headers. |
Approve an overtime request
POST/v1/overtime_requests/{id}/approve
Whether approval is what makes the minutes count toward pay depends on overtime_require_approval in the attendance settings. Answers 409 if the request was already decided, or if it is the API key creator’s own and another approver can decide it.
Path parameters
| Name | Type | Required | Description |
|---|
id | string | Yes | The identifier returned as id on the object. |
Responses
| Status | Meaning |
|---|
200 | The decided overtime request. |
401 | The API key is missing, malformed, revoked or expired. |
403 | The key does not carry the required scopes. |
404 | No such overtime request in this workspace. |
409 | This request has already been decided, or it is the API key creator’s own and another approver can decide it. |
429 | Rate limit exceeded. See the RateLimit-* headers. |
Reject an overtime request
POST/v1/overtime_requests/{id}/reject
Whether approval is what makes the minutes count toward pay depends on overtime_require_approval in the attendance settings. Answers 409 if the request was already decided, or if it is the API key creator’s own and another approver can decide it.
Path parameters
| Name | Type | Required | Description |
|---|
id | string | Yes | The identifier returned as id on the object. |
Responses
| Status | Meaning |
|---|
200 | The decided overtime request. |
401 | The API key is missing, malformed, revoked or expired. |
403 | The key does not carry the required scopes. |
404 | No such overtime request in this workspace. |
409 | This request has already been decided, or it is the API key creator’s own and another approver can decide it. |
429 | Rate limit exceeded. See the RateLimit-* headers. |
List rest day swaps
GET/v1/rest_day_swaps
Query parameters
| Name | Type | Required | Description |
|---|
limit | integer | No | Page size. Values above 100 are clamped. |
starting_after | string | No | Opaque cursor from a previous response’s next_cursor. |
updated_since | timestamp | No | Return records changed at or after this instant. Tracks the record itself, not its child collections. |
employee_id | string | No | Only records belonging to this employee. |
Responses
| Status | Meaning |
|---|
200 | A page of rest day swaps. |
401 | The API key is missing, malformed, revoked or expired. |
403 | The key does not carry the required scopes. |
429 | Rate limit exceeded. See the RateLimit-* headers. |
Create a rest day swap
POST/v1/rest_day_swaps
worked_date must be a rest day for that employee — a weekly off or a holiday — off_date must be an ordinary working day, and both must fall in the same calendar month.
| Name | Type | Required | Description |
|---|
Idempotency-Key | string | No | A unique value per logical request. Replaying it returns the original response with Idempotent-Replay: true. |
Responses
| Status | Meaning |
|---|
201 | The resulting rest day swap. |
400 | The request body failed validation. |
401 | The API key is missing, malformed, revoked or expired. |
403 | The key does not carry the required scopes. |
409 | One of the dates is already part of another swap. A rest day can be swapped once, and a substitute day can absorb one swap. |
429 | Rate limit exceeded. See the RateLimit-* headers. |
Retrieve a rest day swap
GET/v1/rest_day_swaps/{id}
Path parameters
| Name | Type | Required | Description |
|---|
id | string | Yes | The identifier returned as id on the object. |
Responses
| Status | Meaning |
|---|
200 | The rest day swap. |
401 | The API key is missing, malformed, revoked or expired. |
403 | The key does not carry the required scopes. |
404 | No such rest day swap in this workspace. |
429 | Rate limit exceeded. See the RateLimit-* headers. |
Delete a rest day swap
DELETE/v1/rest_day_swaps/{id}
Removes the swap, restoring both days to their ordinary classification.
Path parameters
| Name | Type | Required | Description |
|---|
id | string | Yes | The identifier returned as id on the object. |
Responses
| Status | Meaning |
|---|
200 | The deleted rest day swap, so you have what was removed. |
401 | The API key is missing, malformed, revoked or expired. |
403 | The key does not carry the required scopes. |
404 | No such rest day swap in this workspace. |
429 | Rate limit exceeded. See the RateLimit-* headers. |
List employee shifts
GET/v1/employee_shifts
Query parameters
| Name | Type | Required | Description |
|---|
limit | integer | No | Page size. Values above 100 are clamped. |
starting_after | string | No | Opaque cursor from a previous response’s next_cursor. |
employee_id | string | No | Only records belonging to this employee. |
shift_id | string | No | Only assignments of this shift. |
current | boolean | No | Only the assignment in force today. |
Responses
| Status | Meaning |
|---|
200 | A page of employee shifts. |
401 | The API key is missing, malformed, revoked or expired. |
403 | The key does not carry the required scopes. |
429 | Rate limit exceeded. See the RateLimit-* headers. |
Create an employee shift
POST/v1/employee_shifts
Assigns a shift from a date, closing any open assignment the day before this one starts.
Worth doing straight after creating an employee. Employee creation does not assign a shift, and an employee without one has no expected hours — so attendance has nothing to grade against and payroll cannot classify their days.
| Name | Type | Required | Description |
|---|
Idempotency-Key | string | No | A unique value per logical request. Replaying it returns the original response with Idempotent-Replay: true. |
Responses
| Status | Meaning |
|---|
201 | The resulting employee shift. |
400 | The request body failed validation. |
401 | The API key is missing, malformed, revoked or expired. |
403 | The key does not carry the required scopes. |
409 | The request conflicts with the current state. |
429 | Rate limit exceeded. See the RateLimit-* headers. |
Retrieve an employee shift
GET/v1/employee_shifts/{id}
Path parameters
| Name | Type | Required | Description |
|---|
id | string | Yes | The identifier returned as id on the object. |
Responses
| Status | Meaning |
|---|
200 | The employee shift. |
401 | The API key is missing, malformed, revoked or expired. |
403 | The key does not carry the required scopes. |
404 | No such employee shift in this workspace. |
429 | Rate limit exceeded. See the RateLimit-* headers. |
Delete an employee shift
DELETE/v1/employee_shifts/{id}
Removes the assignment and recomputes attendance over the period it covered, so any grading that depended on it resolves again.
Path parameters
| Name | Type | Required | Description |
|---|
id | string | Yes | The identifier returned as id on the object. |
Responses
| Status | Meaning |
|---|
200 | The deleted employee shift, so you have what was removed. |
401 | The API key is missing, malformed, revoked or expired. |
403 | The key does not carry the required scopes. |
404 | No such employee shift in this workspace. |
429 | Rate limit exceeded. See the RateLimit-* headers. |
List attendance sites
GET/v1/attendance_sites
Query parameters
| Name | Type | Required | Description |
|---|
limit | integer | No | Page size. Values above 100 are clamped. |
starting_after | string | No | Opaque cursor from a previous response’s next_cursor. |
updated_since | timestamp | No | Return records changed at or after this instant. Tracks the record itself, not its child collections. |
status | active · inactive | No | Only sites in this state. |
Responses
| Status | Meaning |
|---|
200 | A page of attendance sites. |
401 | The API key is missing, malformed, revoked or expired. |
402 | The workspace's plan does not include GPS attendance & field visits (plan_upgrade_required). |
403 | The key does not carry the required scopes. |
429 | Rate limit exceeded. See the RateLimit-* headers. |
Create an attendance site
POST/v1/attendance_sites
Creates a geofenced site. radius_meters defaults to 150 and is bounded to 10–10000, matching what the app itself accepts.
A site with no assigned employees accepts no punches — see the assignments sub-resource.
| Name | Type | Required | Description |
|---|
Idempotency-Key | string | No | A unique value per logical request. Replaying it returns the original response with Idempotent-Replay: true. |
Responses
| Status | Meaning |
|---|
201 | The resulting attendance site. |
400 | The request body failed validation. |
401 | The API key is missing, malformed, revoked or expired. |
402 | The workspace's plan does not include GPS attendance & field visits (plan_upgrade_required). |
403 | The key does not carry the required scopes. |
409 | The request conflicts with the current state. |
429 | Rate limit exceeded. See the RateLimit-* headers. |
Retrieve an attendance site
GET/v1/attendance_sites/{id}
Path parameters
| Name | Type | Required | Description |
|---|
id | string | Yes | The identifier returned as id on the object. |
Responses
| Status | Meaning |
|---|
200 | The attendance site. |
401 | The API key is missing, malformed, revoked or expired. |
402 | The workspace's plan does not include GPS attendance & field visits (plan_upgrade_required). |
403 | The key does not carry the required scopes. |
404 | No such attendance site in this workspace. |
429 | Rate limit exceeded. See the RateLimit-* headers. |
Update an attendance site
PATCH/v1/attendance_sites/{id}
Only the fields present in the body are changed. branch_id: null detaches the site from its branch.
Path parameters
| Name | Type | Required | Description |
|---|
id | string | Yes | The identifier returned as id on the object. |
Responses
| Status | Meaning |
|---|
200 | The updated attendance site. |
401 | The API key is missing, malformed, revoked or expired. |
402 | The workspace's plan does not include GPS attendance & field visits (plan_upgrade_required). |
403 | The key does not carry the required scopes. |
404 | No such attendance site in this workspace. |
429 | Rate limit exceeded. See the RateLimit-* headers. |
Delete an attendance site
DELETE/v1/attendance_sites/{id}
Permanent. Assignments go with it; punch-attempt history survives with the site reference cleared.
Path parameters
| Name | Type | Required | Description |
|---|
id | string | Yes | The identifier returned as id on the object. |
Responses
| Status | Meaning |
|---|
200 | The deleted attendance site, so you have what was removed. |
401 | The API key is missing, malformed, revoked or expired. |
402 | The workspace's plan does not include GPS attendance & field visits (plan_upgrade_required). |
403 | The key does not carry the required scopes. |
404 | No such attendance site in this workspace. |
429 | Rate limit exceeded. See the RateLimit-* headers. |
List the employees assigned to a site
GET/v1/attendance_sites/{id}/assignments
Path parameters
| Name | Type | Required | Description |
|---|
id | string | Yes | The identifier returned as id on the object. |
Responses
| Status | Meaning |
|---|
200 | The assigned employee ids. |
401 | The API key is missing, malformed, revoked or expired. |
402 | The workspace's plan does not include GPS attendance & field visits (plan_upgrade_required). |
403 | The key does not carry the required scopes. |
404 | No such attendance site in this workspace. |
429 | Rate limit exceeded. See the RateLimit-* headers. |
Replace the employees assigned to a site
PUT/v1/attendance_sites/{id}/assignments
Send the COMPLETE list, not a delta — it replaces whatever was assigned. An empty array unassigns everyone, which leaves the site accepting no punches.
Path parameters
| Name | Type | Required | Description |
|---|
id | string | Yes | The identifier returned as id on the object. |
Responses
| Status | Meaning |
|---|
200 | The assigned employee ids after the change. |
400 | One of the employees is not in this workspace. |
401 | The API key is missing, malformed, revoked or expired. |
402 | The workspace's plan does not include GPS attendance & field visits (plan_upgrade_required). |
403 | The key does not carry the required scopes. |
404 | No such attendance site in this workspace. |
429 | Rate limit exceeded. See the RateLimit-* headers. |