---
updatedAt: 2026-11-05T20:54:34.000Z
agentTools:
  siteIndex: https://docs.gusto.com/llms.txt
  projectIndex: https://docs.gusto.com/embedded-payroll/llms.txt
---

# Payroll by Workweek

This guide covers the API behavior your integration will encounter once Payroll by Workweek is enabled—new fields, allowed values, immutability rules, and validation errors.

## Company earning types: `category` and `included_in_overtime_pay`

When creating a custom earning type with [POST earning\_types](https://docs.gusto.com/embedded-payroll/reference/post-v1-companies-company_id-earning_types), you specify a `category` that tells Gusto how that earning should be treated for overtime purposes under the Fair Labor Standards Act (FLSA).

Here's what the response from [GET earning\_types](https://docs.gusto.com/embedded-payroll/reference/get-v1-companies-company_id-earning_types) looks like with the new fields:

```json
// GET /v1/companies/:company_id/earning_types
{
  "custom": [
    {
      "name": "Sales Commission",
      "uuid": "d614c0e2-395f-4251-bb2e-2255ea8385ac",
      "active": true,
      "category": "Commission",
      "included_in_overtime_pay": true
    },
    {
      "name": "Cash Tips",
      "uuid": "08a9b469-02e9-4754-a9e5-5be6aa6b3cb4",
      "active": true,
      "category": "Other",
      "included_in_overtime_pay": false
    }
  ]
}
```

### Allowed category values

`category` accepts one of the following exact string values:

| `category` value     | Default `included_in_overtime_pay` | Overtime treatment                            |
| -------------------- | ---------------------------------- | --------------------------------------------- |
| `Commission`         | `true`                             | Determined automatically by FLSA rules        |
| `DiscretionaryBonus` | `false`                            | Determined automatically by FLSA rules        |
| `ServiceCharges`     | `true`                             | Determined automatically by FLSA rules        |
| `OnCallPay`          | `true`                             | Determined automatically by FLSA rules        |
| `Other`              | You set it (defaults to `true`)    | You set `included_in_overtime_pay` explicitly |

For every category except `Other`, the default shown above is fixed and returned on reads—you can't override it. For `Other`, you set `included_in_overtime_pay` yourself at creation. If you omit it, it defaults to `true`.

<Callout icon="📘" theme="info">
  These are the literal strings the API expects and returns (for example, `DiscretionaryBonus`, not "Discretionary bonus"). Sending any other value is rejected—see [Validation and error responses](#validation-and-error-responses) below.
</Callout>

### Setting `included_in_overtime_pay`

For every category **except `Other`**, overtime treatment is fixed by FLSA rules and Gusto sets `included_in_overtime_pay` for you automatically—omit it from your request. Passing `included_in_overtime_pay` alongside a non-`Other` category is rejected—see [Validation and error responses](#validation-and-error-responses) below.

If none of the standard categories fit your use case, use category `Other` and set `included_in_overtime_pay` explicitly yourself when calling [POST earning\_types](https://docs.gusto.com/embedded-payroll/reference/post-v1-companies-company_id-earning_types):

```json
// POST /v1/companies/:company_id/earning_types
{
  "name": "Custom Incentive",
  "category": "Other",
  "included_in_overtime_pay": true
}
```

`category` and `included_in_overtime_pay` are set once at creation with [POST earning\_types](https://docs.gusto.com/embedded-payroll/reference/post-v1-companies-company_id-earning_types) and **cannot be changed afterward** on an existing earning type. See [Immutability and reactivation](#immutability-and-reactivation) for the details and the exact rules around reactivating a previously deactivated earning type.

### Example: an included overtime calculation

Here's how a single workweek's gross pay is calculated when a non-discretionary earning is included in overtime pay:

| Item                                   | Value   |
| -------------------------------------- | ------- |
| Regular hours                          | 40      |
| Overtime hours                         | 5       |
| Double overtime hours                  | 2       |
| Base hourly rate                       | $25.00  |
| Earning marked as included in overtime | $100.00 |

1. **Total qualifying pay:** (47 hrs × $25.00) + $100.00 included earning = **$1,275.00**
2. **Weighted hourly rate:** $1,275.00 ÷ 47 hrs = **$27.13/hr**
3. **Overtime premium:** $27.13 × 5 hrs × 0.5 = **$67.82**
4. **Double overtime premium:** $27.13 × 2 hrs × 1 = **$54.26**
5. **Total gross pay for the week:** $1,175.00 (straight-time) + $100.00 (included earning) + $67.82 (overtime premium) + $54.26 (double overtime premium) = **$1,397.08**

## Pay schedules: `workweek_start_day`

Because overtime is calculated per workweek, pay schedules now support a `workweek_start_day` field on both reads and writes. Here's what you'll see on [GET pay\_schedules](https://docs.gusto.com/embedded-payroll/reference/get-v1-companies-company_id-pay_schedules):

```json
// GET /v1/companies/:company_id/pay_schedules/:pay_schedule_id
{
  "uuid": "3124ec28-18bd-43cd-808a-60e2200256a9",
  "frequency": "Every other week",
  "workweek_start_day": "Monday"
}
```

We recommend that nonexempt employees on weekly or biweekly schedules have their workweek start day aligned with their pay period start date.

### Change constraints

* `workweek_start_day` must be a valid day of the week. An unrecognized value is rejected with `"is not a valid day of the week"`.
* Once set, the workweek start day **can only be changed once per pay period**. Attempting to change it again before the window opens is rejected with `"can only be changed once per pay period. Please wait until {date} to change it again."`, where `{date}` is the ISO-8601 date on which the next change becomes available.

## Draft payroll responses include `gross_pay`

Employee compensation entries in unprocessed (draft) payroll responses—from `prepare`, `update`, and `create` actions—now include an estimated `gross_pay`. Previously this was only available once a payroll was calculated or processed. You no longer need to calculate it yourself or make an extra request per employee just to get an estimate while building a payroll.

Here's an excerpt from a draft payroll response:

```json
// excerpt from a draft payroll response
{
  "employee_uuid": "85a6fd1c-d691-41b9-a4f0-ce95870fc673",
  "gross_pay": "2500.12"
  // ...
}
```

## Workweek breakdowns on the payroll read and write API

On payrolls where per-workweek data applies, payroll endpoints support reading and writing pay data broken out by workweek—so you can specify exactly how much was earned in each workweek within a pay period and see that same breakdown reflected back. Workweek breakdowns are what Gusto uses to calculate overtime pay, so **when to collect them from your end users is driven by whether the earning type counts toward overtime**.

Items in `hourly_compensations` do not report `compensation_multiplier` under Payroll by Workweek—overtime premiums are calculated per workweek instead.

### When workweek breakdowns are required

Use `included_in_overtime_pay` on each earning type as the switch for whether your UI needs to collect a workweek breakdown. The rules:

* **Regular hours** need a workweek breakdown only when the payroll includes overtime (or double overtime). No OT, no breakdown required—regular hours drive the FQOT calculation
* **Additional earnings with `included_in_overtime_pay: true`**—Bonus, Commission, Correction Payments, and any custom earning the company has flagged this way—need a workweek breakdown. These drive the overtime pay calculation.
* **Earnings with `included_in_overtime_pay: false`**—Cash Tips, Paycheck Tips, Reimbursements, and custom "not included" earnings—do not require a workweek breakdown. Your UI should not prompt end users to supply one. The API will accept breakdowns on these earnings if you send them, but they're informational—they don't affect gross pay or the overtime calculation.
* **Overtime hours** are reported in their own entry in `hourly_compensations` (alongside `Regular Hours`), just like any other pay type

To determine which earnings require breakdowns for a given company, call [GET earning\_types](https://docs.gusto.com/embedded-payroll/reference/get-v1-companies-company_id-earning_types) and read `included_in_overtime_pay` on each returned earning type. This covers both standard and custom earnings and handles per-company configuration automatically.

### What you'll see in responses

* A top-level `workweeks` array, listing each workweek's date range within the pay period. This appears **only on the unprocessed payroll responses from `create`, `update`, and `prepare`**—it is not returned by the `show` endpoint. When per-workweek data can't be determined for a payroll, this resolves to an empty array.
* A `pay_adjustments` array on each employee's compensation block, reflecting overtime premium corrections carried over from a previous workweek—for example, when earnings from an earlier pay period are adjusted retroactively, or an off-cycle payroll covers the workweeks and includes additional pay. Each entry has a `name` and an `amount`. This appears **only on the `show` payroll response for calculated or processed payrolls**—not on `create`, `update`, or `prepare`. Because of this, `workweeks` and `pay_adjustments` never appear in the same response.
* A `breakdowns` array on each `fixed_compensations` and `hourly_compensations` entry that has per-workweek detail to report. In the example below, `Bonus` (`included_in_overtime_pay: true`) is broken out across both workweeks—this is the kind of breakdown your UI should be collecting. An earning entered as a single pay-period total has no per-workweek detail and is returned as a single amount with no `breakdowns` array.

<Callout icon="📘" theme="info">
  ### Exempt employee breakdowns

  Breakdowns can be written for—and may appear on—exempt employees' compensation entries. Because exempt employees are not eligible for overtime, any breakdowns on their earnings are informational only and do not affect their pay.
</Callout>

Here's what an unprocessed payroll response from [PUT payrolls/prepare](https://docs.gusto.com/embedded-payroll/reference/put-v1-companies-company_id-payrolls-payroll_id-prepare) looks like—note the top-level `workweeks` array and the absence of `pay_adjustments`:

```json
// PUT /v1/companies/:company_id/payrolls/:payroll_id/prepare
{
  "payroll_uuid": "11bd39d8-af3f-4020-9ea4-067ae62ad8bd",
  "pay_period": {
    "start_date": "2026-10-01",
    "end_date": "2026-10-14"
  },
  "workweeks": [
    { "start_date": "2026-10-01", "end_date": "2026-10-07" },
    { "start_date": "2026-10-08", "end_date": "2026-10-14" }
  ],
  "employee_compensations": [
    {
      "employee_uuid": "85a6fd1c-d691-41b9-a4f0-ce95870fc673",
      "gross_pay": "2500.12",
      "fixed_compensations": [
        {
          "name": "Commission",
          "amount": "500.00",
          "breakdowns": [
            { "start_date": "2026-10-01", "end_date": "2026-10-07", "amount": "300.00" },
            { "start_date": "2026-10-08", "end_date": "2026-10-14", "amount": "200.00" }
          ]
        },
        {
          "name": "Bonus",
          "amount": "100.00",
          "breakdowns": [
            { "start_date": "2026-10-01", "end_date": "2026-10-07", "amount": "60.00" },
            { "start_date": "2026-10-08", "end_date": "2026-10-14", "amount": "40.00" }
          ]
        }
      ],
      "hourly_compensations": [
        {
          "name": "Regular Hours",
          "flsa_status": "Nonexempt",
          "hours": "40.000",
          "breakdowns": [
            { "start_date": "2026-10-01", "end_date": "2026-10-07", "hours": "20.000" },
            { "start_date": "2026-10-08", "end_date": "2026-10-14", "hours": "20.000" }
          ]
        },
        {
          "name": "Overtime",
          "flsa_status": "Nonexempt",
          "hours": "5.000",
          "breakdowns": [
            { "start_date": "2026-10-01", "end_date": "2026-10-07", "hours": "3.000" },
            { "start_date": "2026-10-08", "end_date": "2026-10-14", "hours": "2.000" }
          ]
        }
      ]
    }
  ]
}
```

By contrast, [GET a payroll](https://docs.gusto.com/embedded-payroll/reference/get-v1-companies-company_id-payrolls-payroll_id) on a processed payroll omits the top-level `workweeks` array and instead includes `pay_adjustments` on each employee. Per-workweek breakdowns still appear on compensation entries:

```json
// GET /v1/companies/:company_id/payrolls/:payroll_id
{
  "payroll_uuid": "11bd39d8-af3f-4020-9ea4-067ae62ad8bd",
  "pay_period": {
    "start_date": "2026-10-01",
    "end_date": "2026-10-14"
  },
  "employee_compensations": [
    {
      "employee_uuid": "85a6fd1c-d691-41b9-a4f0-ce95870fc673",
      "gross_pay": "2500.12",
      "pay_adjustments": [
        { "name": "Overtime", "amount": "13.65" }
      ],
      "fixed_compensations": [
        {
          "name": "Commission",
          "amount": "500.00",
          "breakdowns": [
            { "start_date": "2026-10-01", "end_date": "2026-10-07", "amount": "300.00" },
            { "start_date": "2026-10-08", "end_date": "2026-10-14", "amount": "200.00" }
          ]
        },
        {
          "name": "Bonus",
          "amount": "100.00",
          "breakdowns": [
            { "start_date": "2026-10-01", "end_date": "2026-10-07", "amount": "60.00" },
            { "start_date": "2026-10-08", "end_date": "2026-10-14", "amount": "40.00" }
          ]
        }
      ]
    }
  ]
}
```

### Writing workweek breakdowns

When you update a payroll with [PUT payrolls](https://docs.gusto.com/embedded-payroll/reference/put-v1-companies-company_id-payrolls), you can include a `breakdowns` array on each `fixed_compensations` or `hourly_compensations` entry to specify how much of that earning applies to each workweek:

```json
// PUT /v1/companies/:company_id/payrolls/:payroll_id
{
  "employee_compensations": [
    {
      "employee_uuid": "85a6fd1c-d691-41b9-a4f0-ce95870fc673",
      "fixed_compensations": [
        {
          "name": "Commission",
          "amount": "500.00",
          "breakdowns": [
            { "start_date": "2026-10-01", "end_date": "2026-10-07", "amount": "300.00" },
            { "start_date": "2026-10-08", "end_date": "2026-10-14", "amount": "200.00" }
          ]
        }
      ],
      "hourly_compensations": [
        {
          "name": "Regular Hours",
          "flsa_status": "Nonexempt",
          "hours": "40.000",
          "breakdowns": [
            { "start_date": "2026-10-01", "end_date": "2026-10-07", "hours": "20.000" },
            { "start_date": "2026-10-08", "end_date": "2026-10-14", "hours": "20.000" }
          ]
        },
        {
          "name": "Overtime",
          "flsa_status": "Nonexempt",
          "hours": "5.000",
          "breakdowns": [
            { "start_date": "2026-10-01", "end_date": "2026-10-07", "hours": "3.000" },
            { "start_date": "2026-10-08", "end_date": "2026-10-14", "hours": "2.000" }
          ]
        }
      ]
    }
  ]
}
```

For the most accurate overtime calculation, we recommend providing explicit breakdowns wherever you have the underlying data. Breakdowns written on a fixed compensation that is not included in overtime pay (`included_in_overtime_pay: false`) do not affect gross pay—they are recorded for reference only. The exact rules a `breakdowns` array must satisfy are covered in [Validation and error responses](#validation-and-error-responses) below.

## Immutability and reactivation

`category` and `included_in_overtime_pay` are set at creation and cannot be changed on an existing earning type.

* Sending a different `category` on an update is rejected with `"Category is not modifiable"`
* Sending a different `included_in_overtime_pay` on an update is rejected with `"Included in overtime pay is not modifiable"`

### Reactivating a deactivated earning type

Earning types are matched on **name and category**. To reactivate a previously deactivated earning type, submit a create request by calling [POST earning\_types](https://docs.gusto.com/embedded-payroll/reference/post-v1-companies-company_id-earning_types) with the **same name and the same category** it originally had:

* If you reuse a name but pair it with a different category, the request is rejected with `"Name already in use on an earning type with a different category. To reactivate, use the same name and category."`
* For a category `Other` earning type, `included_in_overtime_pay` is immutable, so it must match the original value on reactivation. You can either omit it (Gusto reuses the stored value) or pass the original value. Passing a different value is rejected with `"included_in_overtime_pay does not match the existing earning type. Omit it or use the original value to reactivate."`.

## Validation and error responses

<Accordion title="Company earning types" icon="fa-circle-exclamation">
  | Condition | Message |
  | --- | --- |
  | `category` not one of the allowed values | `Category is not valid` |
  | `included_in_overtime_pay` set with a non-`Other` category | `Category must be 'Other' to set included_in_overtime_pay` |
  | `category` changed on update | `Category is not modifiable` |
  | `included_in_overtime_pay` changed on update | `Included in overtime pay is not modifiable` |
  | Name reused with a different category | `Name already in use on an earning type with a different category. To reactivate, use the same name and category.` |
  | `included_in_overtime_pay` mismatch on reactivation | `included_in_overtime_pay does not match the existing earning type. Omit it or use the original value to reactivate.` |
</Accordion>

<Accordion title="Pay schedule workweek_start_day" icon="fa-circle-exclamation">
  | Condition | Message |
  | --- | --- |
  | Not a valid weekday | `Workweek start day is not a valid day of the week` |
  | Changed more than once per pay period | `Workweek start day can only be changed once per pay period. Please wait until {date} to change it again.` |
</Accordion>

<Accordion title="Compensation breakdowns" icon="fa-circle-exclamation">
  Each `breakdowns` array you submit must satisfy all of the following. Errors are reported against `employee_compensations.hourly_compensations.breakdowns` or `employee_compensations.fixed_compensations.breakdowns`.

  | Rule | Message on failure |
  | --- | --- |
  | Every entry has a `start_date` and `end_date` | `breakdowns must include a start_date and end_date for every entry` |
  | Dates are valid ISO 8601 (YYYY-MM-DD) | `breakdowns must use valid ISO 8601 dates (YYYY-MM-DD) for start_date and end_date` |
  | `start_date` is on or before `end_date` | `breakdowns must have start_date on or before end_date` |
  | Each value (`hours` or `amount`) is present and non-negative | `breakdowns must have a non-negative value` |
  | Entry values sum to the parent total | `breakdowns must sum to the reported total ({parent_total}); got {breakdown_total}` |
  | Entries cover the full pay period with no gaps or overlaps | `breakdowns must cover the payroll's pay period ({period_start} - {period_end}) exactly, with no gaps or overlaps` |
  | All hourly earnings for the same job include breakdowns if any one does | `all hourly_compensations for the same job must include breakdowns when any one does` |

  Two details worth calling out:

  - **Sum tolerance.** The sum check allows a small rounding tolerance: `0.0001` for hourly `hours` and `$0.01` for fixed `amount`
  - **Tiling, not calendar alignment.** The date ranges you submit must *tile* the pay period—chain contiguously from the pay period start to the pay period end with no gaps and no overlaps. They do not have to correspond one-to-one to the calendar workweeks. A single range spanning the entire pay period is valid, as is any contiguous partition of it.
</Accordion>