openapi: 3.0.3
info:
version: 1.0.0
title: When I Work API Documentation Accounts Punch API
description: 'The When I Work API is thorough, flexible, and restful. Its methods are logically grouped and follow standard conventions. Make a selection from the left to jump to the method group you would like to know more about.
When designing your integration, When I Work recommends leveraging our Webhooks subscriptions if you plan to regularly pull data to sync records in your data store. This may be preferable to using our API for tasks like staying up to date about shifts or time entries in your account. Frequent large API requests may run into rate limitations.
Find out more about Webhooks at our [Help Center](https://help.wheniwork.com/articles/webhooks-reference/) or contact our [Customer Care team](mailto:support@wheniwork.com) for assistance.
For more information about obtaining an API key, or general API questions, please refer to the [Help Center](https://help.wheniwork.com/articles/api-services-reference-guide/).
'
servers:
- url: https://api.wheniwork.com
description: Production
security:
- W-Token: []
tags:
- name: Punch
description: 'A punch is an event where a user clocks in or clocks out. Punches can be managed to restrict where an employee can clock in/out and from what devices.
If a user forgets to clock out, they will be allowed to clock in after 9 hours from the end of their scheduled shift. If there is no scheduled shift, the user can clock in again after 18 hours from when they originally clocked in.
'
paths:
/2/times/clockin:
post:
summary: Clock In
description: Punch the current user or another user in. The punch creator's ID will also be recorded.
tags:
- Punch
requestBody:
$ref: '#/components/requestBodies/ClockInRequest'
responses:
'200':
description: Valid
content:
application/json:
schema:
$ref: '#/components/schemas/PunchResponse'
'400':
description: Bad request contains missing or invalid parameters
content:
application/json:
schema:
$ref: '#/components/schemas/V2Error'
'403':
description: Forbidden access, account setting or permissions do not allow this action
content:
application/json:
schema:
$ref: '#/components/schemas/V2Error'
/2/times/clockout:
post:
summary: Clock Out
description: Punch the current user or another user out. The punch creator's ID will also be recorded.
tags:
- Punch
requestBody:
$ref: '#/components/requestBodies/ClockOutRequest'
responses:
'200':
description: Valid
content:
application/json:
schema:
$ref: '#/components/schemas/PunchResponse'
'400':
description: Bad request contains missing or invalid parameters
content:
application/json:
schema:
$ref: '#/components/schemas/V2Error'
'403':
description: Forbidden access, account setting or permissions do not allow this action
content:
application/json:
schema:
$ref: '#/components/schemas/V2Error'
/2/punch/state:
get:
summary: Punch State
description: Gets a users punch state and allowed actions
tags:
- Punch
parameters:
- in: query
description: User ID if looking up the punch state for another user, may allow additional actions
name: userId
required: false
schema:
type: integer
- in: query
description: Location ID (schedule) used to verify if the user can punch in at this location
name: locationId
required: false
schema:
type: integer
- in: query
description: Job site used to verify if the user can punch in at this site
name: siteId
required: false
schema:
type: integer
- in: query
description: Shift ID used to verify if the user can punch into this shift
name: shiftId
required: false
schema:
type: integer
- in: query
description: Type of device used to perform the punch
name: deviceType
required: false
schema:
type: string
enum:
- web
- mobile
- terminal
- in: query
description: Current latitude used to verify punch restrictions for strict location validation
name: latitude
required: false
schema:
type: number
- in: query
description: Current longitude used to verify punch restrictions for strict location validation
name: longitude
required: false
schema:
type: number
- in: query
description: Expand the location search area by a given confidence to the provided location
name: confidence
required: false
schema:
type: number
responses:
'200':
description: The current punch state and allowed actions for the user
content:
application/json:
schema:
type: object
properties:
canClockIn:
description: Can the user be clocked in
type: boolean
example: false
canClockOut:
description: Can the user be clocked out
type: boolean
example: false
canStartBreak:
description: Can the user start a break
type: boolean
example: false
canEndBreak:
description: Can the user end their break
type: boolean
example: true
needsBreakConfirmation:
description: True if the user is required to report on unused paid breaks
type: boolean
example: false
needsUnpaidBreakConfirmation:
description: True if the user is required to report on unused unpaid breaks
type: boolean
example: false
punchStartTime:
description: Time when the user punched in, date in ISO 8601 format (UTC timezone)
type: string
example: '2017-09-27T18:28:52'
punchTimeId:
description: The ID of the time object associated with the punch
type: integer
example: 1
errorCode:
description: 'Error code describing why punch in or punch out is not allowed
* `101` - Bad device location received
* `102` - Bad shift location received
* `103` - Out of range for shift location
* `104` - Not near the punch location
* `105` - Clock-in time too early
* `106` - No shift scheduled, or manual selection required (see: availableShifts)
'
type: integer
enum:
- 101
- 102
- 103
- 104
- 105
- 106
schedules:
example: 1
oneOf:
- schedule: null
type: integer
description: The schedule ID to punch in at or the schedule currently punched in at
- scheduled: null
type: string
description: URL used to load a listing of possible schedules
jobSites:
example: 1
oneOf:
- site: null
type: integer
description: The job site ID to punch in at or the job site currently punched in at
- sites: null
type: string
description: URL used to load a listing of possible job sites
positions:
example: 1
oneOf:
- position: null
type: integer
description: The position ID to punch in at or position currently punched in as
- positions: null
type: string
description: URL used to load a listing of possible positions
shift:
example: 1
description: The shift ID that should be used when punching in or the shift ID currently punched in as
type: integer
break:
description: The break object currently punched into if currently on a punched break
type: object
$ref: '#/components/schemas/PunchStateRootShiftBreak'
availableShifts:
description: A list of available shift IDs the user is allowed to punch in to
example:
- 4
- 6
- 7
type: array
items:
type: integer
recordingUnpaidBreaksAllowed:
description: True if the user is allowed to record unpaid breaks
type: boolean
example: true
recordingPaidBreaksAllowed:
description: True if the user is allowed to record paid breaks
type: boolean
example: true
scheduledBreaks:
type: array
description: A list of scheduled breaks if the clocked in time has a shift which has scheduled breaks. (Only provided when clocked in, there's a shift, and the shift has scheduled breaks)
items:
type: object
$ref: '#/components/schemas/PunchStateScheduledBreak'
unscheduledBreaks:
type: array
description: A list of any taken unscheduled breaks. (Only provided when clocked in and there are shift breaks for the time)
items:
type: object
$ref: '#/components/schemas/PunchStateNestedShiftBreak'
'400':
description: Bad request contains missing or invalid parameters
content:
application/json:
schema:
type: object
properties:
errors:
description: A list of validation errors
example:
- Invalid value for userID
- Missing required parameter deviceType
type: array
items:
type: string
'403':
description: Forbidden access, account setting or permissions do not allow this action
content:
application/json:
schema:
type: object
properties:
errors:
description: A list of validation errors
example:
- Web punch state not active on account
type: array
items:
type: string
'404':
description: Not found, requested resource could not be found
content:
application/json:
schema:
type: object
properties:
errors:
description: A list of validation errors
example:
- User not found
type: array
items:
type: string
components:
schemas:
PunchResponse:
type: object
properties:
time:
description: The Time object that the punch is associated with
$ref: '#/components/schemas/Time'
overtime_alert:
description: Was an over-time alert triggered
type: boolean
example: false
user:
description: The User that has punched in
$ref: '#/components/schemas/User'
punches:
description: 'Array of punches associated with the current Time
* Punch in/out
* Punch break start/stop
'
type: array
PunchStateRootShiftBreak:
allOf:
- $ref: '#/components/schemas/PunchStateShiftBreakBase'
- type: object
properties:
start:
description: The break start time
type: string
format: date-time
example: 2025-05-19T10:45:00-0400
end:
description: The break end time. Will always be an empty string; once the break has an end, it is no longer returned by this endpoint under the `break` key
type: string
format: date-time
example: ''
length:
description: The break length from the database model once the break is complete, in minutes. Until the break is complete, this value remains zero. However, once the break is complete, the `break` object is not longer returned by this endpoint. Hence, break length should be calculated based on the `start` instead
type: integer
example: 0
Time:
type: object
properties:
id:
type: integer
readOnly: true
example: 10000
description: The time id
account_id:
type: integer
readOnly: true
example: 10000
description: The account id
user_id:
type: integer
example: 101
description: The user assigned to the time.
creator_id:
type: integer
readOnly: true
example: 100
description: The user that created the time.
position_id:
type: integer
example: 19483
description: Position the time belongs to. 0 if unassigned.
location_id:
type: integer
example: 1045
description: Location the time belongs to. 0 if unassigned.
site_id:
type: integer
example: 4351
description: Site the time belongs to. 0 if unassigned.
shift_id:
type: integer
example: 5451
description: A shift tied to this time. 0 if unassigned.
start_time:
type: string
format: date-time
example: Fri, 07 Mar 2016 08:30:00 -0600
description: The start time
end_time:
type: string
format: date-time
example: Fri, 07 Mar 2016 14:30:00 -0600
description: The end time
rounded_start_time:
type: string
format: date-time
example: Fri, 07 Mar 2016 08:30:00 -0600
description: The rounded start time. If rounding is not enabled this field will not be present.
rounded_end_time:
type: string
format: date-time
example: Fri, 07 Mar 2016 14:30:00 -0600
description: The rounded end time. If rounding is not enabled this field will not be present.
notes:
type: string
example: A time note
description: Notes for a time
length:
type: float
readOnly: true
example: 8
description: The length of the time in hours.
rounded_length:
type: float
readOnly: true
example: 8
description: The rounded length calculated from the rounded_start_time and rounded_end_time. If rounding is not enabled this field will not be present.
hourly_rate:
type: float
readOnly: true
example: 15
description: The base hourly rate for this time.
cash_tips:
type: string
format: decimal
nullable: true
description: 'Any cash tips reported for the shift.
Note: the tips feature is required to see and use this field.
'
example: '123.45'
alert_type:
type: integer
readOnly: true
example: 16
description: The type of alert for this time
is_approved:
type: boolean
example: false
description: If the time is approved
modified_by:
type: integer
readOnly: true
example: 18438
description: The user that modified the time
sync_id:
type: string
readOnly: true
example: ''
description: The quickbooks sync id
sync_hash:
type: string
readOnly: true
example: ''
description: The quickbooks sync hash
updated_at:
type: string
readOnly: true
format: date-time
example: Tue, 17 Mar 2020 14:48:43 -0700
description: When the time was updated
created_at:
type: string
readOnly: true
format: date-time
example: Tue, 17 Mar 2020 14:25:48 -0700
description: When the time was created
split_time:
type: string
readOnly: true
format: date-time
example: Fri, 07 Mar 2016 00:00:00 -0600
description: If the time crosses payroll periods, when to split it
is_alerted:
type: boolean
readOnly: true
example: false
description: If alert_type > 0
paid_break_note:
type: string
default: null
readOnly: true
example: I am a note entered for the shift break paid record
description: The note associated with the shift break paid record. The include_paid_break_note query param must be set to true for this to be returned.
PunchStateShiftBreakBase:
type: object
properties:
id:
description: The shift break id
type: integer
example: 2
account_id:
description: The account id associated with the break
type: integer
example: 3
time_id:
description: The time id associated with the break
type: integer
example: 1
type:
description: The type of break (1=paid, 2=unpaid)
type: integer
example: 2
creator_id:
description: The id of the user who created the break
type: integer
example: 238
auto_deducted:
description: Whether the break was auto deducted (0 = false, 1 = true)
type: integer
example: 0
edited_by:
description: The id of the user who edited the break
type: integer
example: 238
skipped:
description: Whether the break was skipped (0 = false, 1 = true)
type: integer
example: 0
created_at:
description: Date and time the break was created at
type: string
format: date-time
example: 2025-05-19T11:25:04-0400
updated_at:
description: Date and time the break was last updated
type: string
format: date-time
example: 2025-05-19T11:25:04-0400
scheduledbreaks_id:
description: The scheduled break associated with this shift break, if it is a scheduled break. Otherwise `0`
type: integer
example: 0
PunchStateNestedShiftBreak:
allOf:
- $ref: '#/components/schemas/PunchStateShiftBreakBase'
- type: object
properties:
start:
description: The break start time. Null if the break does not have an start time. Perhaps because it was added on Timesheets.
type: string
format: date-time
nullable: true
example: 2025-05-19T10:00:00-0400
end:
description: The break end time. Null if the break does not have an end time. Perhaps because it was added on Timesheets.
type: string
format: date-time
nullable: true
example: 2025-05-19T10:08:00-0400
length:
description: The length of the break if it's completed, in minutes. Length will be zero until the break has ended
type: integer
example: 6
User:
properties:
account_id:
description: ID of the primary account for this user.
type: integer
activated:
description: Whether the manager has activated this user.
type: boolean
email:
description: The email address of this user.
format: email
type: string
employee_code:
description: 'The user''s employee code. This code can be used to clock in instead of
the user''s email address, or it can be used to help map users in When
I Work to other services.
'
type: string
first_name:
description: The first name of this user.
type: string
hourly_rate:
description: 'The base hourly rate for this user. The user can have additional wages
based on the position they are working at the time. There is no currency
attached, so customers are expected to input correct values for their
currency or do their own conversion from USD.
'
format: float
type: number
hours_max:
description: 'The max hours that this user prefers to work. A manager may still
schedule the user beyond this value.
'
format: float
type: number
hours_preferred:
description: The preferred number of hours for this user to work.
format: float
type: number
id:
description: Unique identifier for the user.
type: integer
is_deleted:
description: Whether the user has been deleted.
type: boolean
is_hidden:
description: Whether the user has been hidden from the scheduler.
type: boolean
is_payroll:
description: 'Whether the user has access to payroll. (Only available for managers
and supervisors.)
'
type: boolean
is_private:
description: 'Whether the user has privacy enabled, which will hide their contact
details from other employees. Supervisors+ can not hide their
email/phone from other employees.
'
type: boolean
is_trusted:
description: Whether the user can edit their own timesheet.
type: boolean
last_login:
description: The date and time when this user last logged in.
format: date-time
type: string
last_name:
description: The last name of this user.
type: string
locations:
description: An array of location IDs to be applied to this user.
items:
type: integer
type: array
login_id:
description: Unique identifier for the login belonging to the user.
type: integer
notes:
description: Notes about this user. Visible only to supervisors+.
type: string
phone_number:
description: The phone number of this user.
type: string
positions:
description: An array of position IDs to be assigned to this user.
items:
type: integer
type: array
role:
description: The user's role.
enum:
- 1 = Admin
- 2 = Manager
- 3 = Employee (Default)
- 4 = Lead (Unused)
- 5 = Supervisor
type: integer
type:
description: 'A bitwise flag representing additional wage options:
1 = hourly employee
2 = salaried employee
4 = Exempt from overtime
'
type: integer
type: object
PunchStateScheduledBreak:
allOf:
- type: object
properties:
id:
type: integer
description: Scheduled Break Id
example: 1
account_id:
type: integer
description: Account Id associated with this break
example: 3
start_time:
description: The start time of the break. Null if the break does not have a start time
type: string
example: '2025-05-19T14:30:00+00:00'
end_time:
description: The end time of the break. Null if the break does not have an end time. Calculated from the start time of the break and the length
type: string
example: '2025-05-19T14:45:00+00:00'
length:
description: The length of the break (seconds)
type: integer
example: 900
paid:
description: Whether the break is a paid rest break (true) or unpaid meal break (false)
type: boolean
example: true
created_by:
description: The id of the user who created the break
type: integer
example: 201
created_at:
description: Date and time the break was created at
type: string
example: '2025-05-10T14:45:00+00:00'
updated_by:
description: The id of the user who last edited the break
type: string
example: '202'
updated_at:
description: Date and time the break was last updated
type: string
example: '2025-05-10T15:45:00+00:00'
sort:
type: integer
description: Breaks are sorted by start time if it is available. If no start time is provided, breaks are sorted by their position in the request. In a mixed list, breaks without a start time keep their original position, while breaks with a start time are sorted amongst themselves
shift_id:
type: integer
example: 1234
description: The ID of the shift that the break applies to
readOnly: true
shift_break:
type: object
description: When not null, at least a start time was created for an associated shift break. Otherwise, no breaks have been taken for this scheduled break
$ref: '#/components/schemas/PunchStateNestedShiftBreak'
V2Error:
type: object
required:
- error
properties:
error:
type: string
description: A description of the specific error
code:
oneOf:
- type: integer
- type: string
description: The API error code
requestBodies:
ClockOutRequest:
description: Clock Out (Punch) request data
content:
application/json:
schema:
type: object
properties:
id:
type: integer
description: The ID of the user you are creating the clock-in for
example: 14
notes:
type: string
description: Optional notes that can be added to the punch that will show up on the timesheets
example: Punching out late there was a delay in the shift change
required: false
coordinates:
type: array
description: The GPS coordinates of the clock-out. This is an optional parameter.
example:
- 44.983791
- -93.2774416
required: false
altitude:
type: number
description: The altitude that the user is currently at in meters.
example: 20
required: false
accuracy:
type: number
description: The accuracy in meters of the coordinates being sent.
example: 20
required: false
terminal:
type: boolean
description: Is the user clocking out from a terminal (web or mobile/tablet terminal app)
example: true
required: false
default: false
cashTips:
description: The amount of cash tips reported for the shift.
type: string
format: decimal
example: '54.32'
ClockInRequest:
description: Clock In (Punch) request data
content:
application/json:
schema:
type: object
properties:
id:
type: integer
description: The ID of the user you are creating the clock-in for
example: 14
site_id:
type: integer
description: The ID of the job site to punch in at. This is an optional parameter.
example: 1
required: false
position_id:
type: integer
description: The ID of the position the user is clocking in as. This is an optional parameter.
example: 102
required: false
shift_id:
type: integer
description: The Shift ID for the shift to punch in for, 0 if punching into an unscheduled shift.
example: 0
required: false
location_id:
type: integer
description: The Schedule ID for the schedule the user is punching in at. This is an optional parameter.
example: 1
required: false
notes:
type: string
description: Optional notes that can be added to the punch that will show up on the timesheets.
example: Punching in today, running a little late due to traffic problems
required: false
coordinates:
type: array
description: The GPS coordinates of the clock-in. This is an optional parameter.
example:
- 44.937422
- -93.084009
required: false
altitude:
type: number
description: The altitude that the user is currently at in meters.
example: 20
required: false
accuracy:
type: number
description: The accuracy in meters of the coordinates being sent.
example: 20
required: false
terminal:
type: boolean
description: Is the user clocking in from a terminal (web or mobile/tablet terminal app)
example: true
required: false
default: false
securitySchemes:
W-Token:
type: http
scheme: bearer
bearerFormat: JSON Web Token
description: "Authentication with When I Work is based on a token model using [JSON Web Tokens](https://jwt.io/). First, you authenticate using a private developer key and the username and password of a When I Work user. Your developer key can be used like the following in the headers.\n```\ncurl -X POST \\\n https://api.login.wheniwork.com/login \\\n -H 'W-Key: <INSERT_DEVELOPER_KEY_HERE>' \\\n -H 'content-type: application/json' \\\n -d '{\"email\":\"<INSERT_USERNAME_HERE>\",\"password\":\"<INSERT_PASSWORD_HERE>\"}'\n```\n\nAuthenticating returns back a person object containing a token that is used to authenticate all future requests. You can now use this token to fetch all the users tied to your person. The token may be included in the headers, as a cookie, or in the query string using the key ‘W-Token
# --- truncated at 32 KB (33 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/when-i-work/refs/heads/main/openapi/when-i-work-punch-api-openapi.yml