# POST /api/v1/payroll/gusto/reconcile/apply

> Apply the Gusto payroll reconciliation

- **Tag:** payroll
- **Operation ID:** `gusto_reconcile_apply`

## Description

Recomputes the preview's plan from the same inputs and applies it: splits each NET lump one leg per employee (each leg names the employee), creates the per-pay-period Gusto bills for tax and reimbursement debits and pays them with the bank rows (or pays an open Gusto bill of the same amount), renames and categorizes contractor and fee rows, and saves the register as pay runs. Each row is applied on its own; failures are listed. Rows already applied are skipped, so repeating the call is safe. Pass plan_hash from the preview to refuse a plan that changed since.

## Authentication

Bearer token in `Authorization` header.
Required header: `x-business-id: <business uuid>`.

## Request body

Schema: `GustoApplyRequest`

- `reports` (array · GustoReportInput) → `GustoReportInput` — Gusto exports: Payroll Journal (or Payroll Register), Contractor Payments and/or Bank Transactions. Without any, only the bank lines' own descriptors are used (contractor payee, fee).
  - `s3_key` (string) — S3 key from POST /uploads (or generate_upload_url) of a CSV/XLSX exported from Gusto > Reports.
  - `content` (string) — The report pasted as CSV / tab-separated text.
  - `filename` (string) — Original file name (format hint).
- `bank_ledger_id` (string) — Bank account Gusto debits. Omit to consider every bank account of the business.
- `start_date` (string · date · required) — First bank date considered
- `end_date` (string · date · required) — Last bank date considered
- `ledger_overrides` (GustoLedgerOverrides)
- `amount_tolerance_cents` (integer) — Largest difference accepted between a payroll lump and the register total; the difference becomes a rounding leg.
- `create_bills` (boolean) — Book tax and reimbursement debits as an accrual bill per pay period (vendor Gusto) paid by the bank row. False categorizes them directly instead.
- `plan_hash` (string) — plan_hash from the preview. When given, apply refuses if the plan it computes now differs (books changed since the preview).
- `transaction_ids` (array · string) — Apply only these bank rows of the plan (default: all).

## Responses

### 200 — Successful Response

Schema: `SuccessEnvelope_GustoReconcileApplyResponse_`

- `success` (boolean)
- `message` (string)
- `code` (string)
- `data` (GustoReconcileApplyResponse)

### 400 — Bad Request - Invalid input

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

### 401 — Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

### 403 — Forbidden - Insufficient permissions

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

### 422 — Validation Error

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

## Code samples

### cURL

```bash
curl -X POST 'https://api.ondayzero.com/api/v1/payroll/gusto/reconcile/apply' \
  -H 'Authorization: Bearer dz_your_token' \
  -H 'x-business-id: YOUR_BUSINESS_ID' \
  -H 'Content-Type: application/json' \
  -d '{
  "start_date": "2026-01-01",
  "end_date": "2026-01-01"
}'
```

### JavaScript

```javascript
const response = await fetch('https://api.ondayzero.com/api/v1/payroll/gusto/reconcile/apply', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer dz_your_token',
    'x-business-id': 'YOUR_BUSINESS_ID',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
  "start_date": "2026-01-01",
  "end_date": "2026-01-01"
}),
});
const data = await response.json();
```

### Python

```python
import httpx

headers = {
    "Authorization": "Bearer dz_your_token",
    "x-business-id": "YOUR_BUSINESS_ID",
}

payload = {'start_date': '2026-01-01', 'end_date': '2026-01-01'}

response = httpx.post("https://api.ondayzero.com/api/v1/payroll/gusto/reconcile/apply", headers=headers, json=payload)
data = response.json()
```

## See also

- HTML version: https://www.ondayzero.com/docs/reference/payroll/gusto-reconcile-apply
- OpenAPI slice: https://www.ondayzero.com/docs/reference/payroll/gusto-reconcile-apply/openapi.json
- Other endpoints in **payroll**: https://www.ondayzero.com/docs/reference/payroll (markdown bundle: https://www.ondayzero.com/docs/reference/payroll.md, OpenAPI: https://www.ondayzero.com/docs/reference/payroll/openapi.json)
- Endpoint catalog: https://www.ondayzero.com/docs/reference/index.md
