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: ' \\\n -H 'content-type: application/json' \\\n -d '{\"email\":\"\",\"password\":\"\"}'\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’ or ‘Authorization’. If the authenticated user belongs to more than one Workplace you will need to get the User listing to obtain the user-id value\n```\ncurl -X GET \\\n 'https://api.wheniwork.com/2/login?show_pending=true' \\\n -H 'Host: api.wheniwork.com' \\\n -H 'Authorization: Bearer '\n```\n\nThe response will also include a listing of the user objects related to the person for each associated When I Work account. You can use the user ID to set the context for which account you will be acting upon by providing a When I Work user ID through the ‘W-UserID’ header.\n```\ncurl -X GET \\\n https://api.wheniwork.com/2/users \\\n -H 'Authorization: Bearer ' \\\n -H 'W-UserId: '\n```\nWhen I Work protects our application and API with rate limiting thresholds. Rate limiting utilizes thresholds based on rolling windows of time. Typical responses will be 403 level client side errors when encountering these limits. If you suspect you are encountering one of our thresholds please connect with our Customer Care team at support@wheniwork.com.\n\nYou can find additional authentication related API documentation in our [Login Service API docs](https://apidocs.wheniwork.com/external/index.html?repo=login).\n"