> ## Documentation Index
> Fetch the complete documentation index at: https://docs.paypunch.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Clock In / Clock Out

> POST /api/v1/employee/timesheet/entry — create (clock in) or complete (clock out) the authenticated employee's time entry.

A single endpoint that both **clocks in** (creates a new open time entry) and
**clocks out** (completes the open entry and computes hours), selected by the
`action` field.

```http theme={null}
POST /api/v1/employee/timesheet/entry
```

**Authentication:** requires an **employee** JWT. The employee is taken from the
token's `userId`.

## Request body

<ParamField body="action" type="string" required>
  Either `clock_in` or `clock_out`.
</ParamField>

<ParamField body="notes" type="string">
  Free-text note. On clock out, if omitted the existing entry's notes are kept.
</ParamField>

<ParamField body="jobCode" type="string">
  Optional job code (recorded on clock in).
</ParamField>

<ParamField body="taskCode" type="string">
  Optional task code (recorded on clock in).
</ParamField>

<ParamField body="breakMinutes" type="integer" default="0">
  Unpaid break minutes deducted from total hours on clock out. Minimum `0`.
</ParamField>

<ParamField body="clockInIp" type="string">
  Optional client IP to record. Used for both the clock-in and clock-out IP fields.
</ParamField>

<ParamField body="clockInDevice" type="string">
  Optional device identifier to record.
</ParamField>

## Behavior

<Tabs>
  <Tab title="clock_in">
    Creates a new time entry with `status: "PENDING"` and `clockIn` set to now.
    It is associated with the company's current **unlocked** pay period (if one
    exists). If the employee already has an open entry, returns `400` `Already
            clocked in` (with the existing entry's `id` and `clockIn`).
  </Tab>

  <Tab title="clock_out">
    Finds the open entry (no `clockOut`) and completes it: sets `clockOut` to
    now, applies `breakMinutes`, and computes `totalHours`, `regularHours`, and
    `overtimeHours` using the org's `overtimeThreshold` against the employee's
    weekly hours. If there is no open entry, returns `400` `No open time entry`.
  </Tab>
</Tabs>

## Response

Both actions return `200` with `data.timeEntry` (including its `payPeriod`
summary) and a `data.message`. Clock out additionally returns `data.summary`
with `totalHours`, `regularHours`, `overtimeHours`, and `breakMinutes`.

## Examples

<CodeGroup>
  ```bash Clock in theme={null}
  curl -X POST https://app.paypunch.io/api/v1/employee/timesheet/entry \
    -H "Authorization: Bearer <employee-token>" \
    -H "Content-Type: application/json" \
    -d '{
      "action": "clock_in",
      "jobCode": "JOB-204",
      "notes": "Site A framing"
    }'
  ```

  ```bash Clock out theme={null}
  curl -X POST https://app.paypunch.io/api/v1/employee/timesheet/entry \
    -H "Authorization: Bearer <employee-token>" \
    -H "Content-Type: application/json" \
    -d '{
      "action": "clock_out",
      "breakMinutes": 30
    }'
  ```

  ```json Clock-in response (200) theme={null}
  {
    "success": true,
    "data": {
      "timeEntry": {
        "id": "t9...",
        "employeeId": "e1f2...",
        "companyId": "c9d8...",
        "payPeriodId": "pp_01...",
        "clockIn": "2026-06-17T13:00:00.000Z",
        "clockOut": null,
        "jobCode": "JOB-204",
        "status": "PENDING",
        "payPeriod": { "id": "pp_01...", "startDate": "2026-06-15T00:00:00.000Z", "endDate": "2026-06-28T00:00:00.000Z", "status": "OPEN" }
      },
      "message": "Clocked in successfully"
    }
  }
  ```

  ```json Clock-out response (200) theme={null}
  {
    "success": true,
    "data": {
      "timeEntry": {
        "id": "t9...",
        "clockIn": "2026-06-17T13:00:00.000Z",
        "clockOut": "2026-06-17T21:30:00.000Z",
        "breakMinutes": 30,
        "totalHours": 8,
        "regularHours": 8,
        "overtimeHours": 0,
        "payPeriod": { "id": "pp_01...", "status": "OPEN" }
      },
      "message": "Clocked out successfully",
      "summary": { "totalHours": 8, "regularHours": 8, "overtimeHours": 0, "breakMinutes": 30 }
    }
  }
  ```
</CodeGroup>

## Errors

| Status | `error`                                      | Cause                                                           |
| ------ | -------------------------------------------- | --------------------------------------------------------------- |
| `400`  | `Already clocked in`                         | `clock_in` while an open entry exists.                          |
| `400`  | `No open time entry`                         | `clock_out` with nothing to close.                              |
| `400`  | `Invalid action` / `Invalid time entry data` | `action` not `clock_in`/`clock_out`, or body validation failed. |
| `401`  | `Authentication required`                    | Missing/invalid employee token.                                 |
| `404`  | `Employee not found or inactive`             | Token user missing or deactivated.                              |
| `500`  | `Failed to create time entry`                | Unexpected server error.                                        |
