@dsptch-work/api-client 0.35.0 → 0.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,335 @@ All notable changes to `@dsptch-work/api-client` are documented here. The format
5
5
  [Semantic Versioning](https://semver.org) — currently `0.x`, so breaking changes may land in a
6
6
  minor bump until `1.0.0`. See [RELEASING.md](./RELEASING.md) for the release and versioning process.
7
7
 
8
+ ## [0.37.0] - 2026-10-14
9
+
10
+ ### Added
11
+
12
+ - `Jobs` adds `listJobDocuments()`, `createJobDocument()`, `getJobDocument()`,
13
+ `updateJobDocument()`, and `deleteJobDocument()`, with corresponding operation types and Zod
14
+ schemas. Use `path: { job_id }` for list/create and `path: { job_id, id }` for the others.
15
+ `JobDocumentParameters` and `JobDocumentUpdateParameters` support an external `url` or an
16
+ uploaded `file`; supply exactly one source on create and retain exactly one after an update.
17
+ Although create's generated fields are optional, the server requires nonblank `type` and `name`.
18
+ Register files through `DirectUploads.createDirectUpload()` with
19
+ `DirectUploadParameters.resource: 'jobs.documents'`, then send its signed ID as `file`.
20
+ `JobDocumentResponseObject` exposes nullable `url` and `file` download metadata;
21
+ `JobDocumentsResponseObject` wraps the list, and `ListJobDocumentsData.query` accepts
22
+ `'filter[type]'`. PWA documents are always `admin_only`; callers without job financial access
23
+ cannot read them. Grant the appropriate `jobs.documents:read` / `:create` / `:update` / `:delete`
24
+ scope. Deletion resolves `204` with no body.
25
+ - `PositionParameters.pay_rates_rule_package_id` accepts a nullable package ID through
26
+ `Jobs.createPosition()` / `updatePosition()`. Choose a selectable package belonging to the path
27
+ job; an inaccessible, hidden, or other-job package returns `404`. Omit it on create to leave the
28
+ assignment unset, omit it on update to retain it, or send null to clear it. A cash-fringe package
29
+ on a non-PWA position returns `422`.
30
+ - `SiteCheckInResponseObject` and `zSiteCheckInResponseObject` add required nullable
31
+ `duration_minutes`, the elapsed whole minutes between check-in and check-out, rounded to the nearest minute. It is null until the
32
+ visitor checks out. Add the field to typed fixtures for `OversiteSiteCheckIns` reads.
33
+ - `TodoInboxTodoResponseObject` and `zTodoInboxTodoResponseObject` add required `priority`
34
+ (`'critical' | 'high' | 'medium' | 'low' | null`) and `category` (the same ten categories used by
35
+ compliance checks). `Todos.listTodoInbox()` now carries them on `kind: 'todo'` entries;
36
+ add both fields to typed fixtures. These are read fields, without new SDK write methods or
37
+ query filters.
38
+
39
+ ### Changed
40
+
41
+ - **Breaking:** `UserParameters`, `UserCompanyCreateParameters`,
42
+ `UserCompanyScheduledChangesParameters`, `UserCompanyScheduledChange`, and `UserResponseObject`
43
+ replace `hourly_rate`, `training_annual_amount`, `employer_combined_health_amount`, and
44
+ `employer_combined_savings` with the corresponding `_cents` fields. Update calls to
45
+ `Users.createUser()`, `createCompany()`, `createUserCompanyScheduledChange()`, and
46
+ `updateScheduledChange()` and consumers of user and scheduled-change responses. Send decimal
47
+ strings in cents: `hourly_rate_cents: '3250'` replaces `hourly_rate: '32.50'`.
48
+ Response values are decimal-string cents such as `'3250.0'`, without a currency symbol;
49
+ obtain the currency from `People.getEmployment()`. Omitted amounts remain unset on create
50
+ or unchanged on scheduled updates, null clears them, and `'0'` sets zero. Old dollar-field
51
+ names return `400 unknown_key`; corresponding Zod schemas now expose only the cents names.
52
+ - **Breaking:** `ProjectParameters` and `ProjectUpdateParameters` replace `budget` with
53
+ `budget_cents` for `Projects.createProject()` / `updateProject()`, including their Zod schemas.
54
+ Send `'123450'` for a budget of $1,234.50, rather than the former dollar string `'1234.50'`.
55
+ Null clears it and omission retains it on update. `budget` now returns `400 unknown_key`.
56
+ A budget, including null, still returns `422` while federal PWA tracking is off.
57
+ `ProjectResponseObject.budget_cents` and `budget_currency` are now optional nullable fields:
58
+ handle their absence when the caller cannot see project financials instead of assuming null.
59
+ - **Breaking:** `ApprenticeshipWageScheduleParameters` / `ApprenticeshipWageScheduleUpdateParameters`
60
+ make `journeyworker_wage_cents`, `journeyworker_fringe_cents`, and `end_wage_cents` decimal
61
+ strings. `ApprenticeshipWageSchedulePeriodParameters` /
62
+ `ApprenticeshipWageSchedulePeriodUpdateParameters`, including nested `periods_attributes`,
63
+ likewise make `wage_cents`, `fringe_cents`, `wage_percent`, and `fringe_percent` strings.
64
+ Update the `ApprenticeshipWageSchedules` and `ApprenticeshipWageSchedulePeriods` write calls
65
+ to send `'2800.5'` cents or `'62.5'` percent, or echo the string from a read. JSON numbers
66
+ now return `422` at the field pointer; nullable fringe fields still accept null.
67
+ The corresponding Zod schemas enforce nonnegative decimal strings.
68
+ - **Breaking:** `AssetsItemParameters.purchase_price_cents` and
69
+ `AssetsItemUpdateParameters.purchase_price_cents` change from `number | null` to
70
+ `string | null` for `AssetsItems.createItem()` / `updateItem()`. Send `'2800'` or `'2800.5'`,
71
+ or null to clear it. JSON numbers now return `422`; the corresponding Zod schemas enforce
72
+ nonnegative decimal strings. Purchase-price storage rounds beyond two decimal places in cents.
73
+ - **Breaking:** `PositionParameters` now requires decimal strings for `cash_fringe_rate_cents`,
74
+ `hourly_rate_cents`, `pwa_wage_pay_rate_cents`, and `wage_adder_rate_cents` in
75
+ `Jobs.createPosition()` / `updatePosition()`. `start_time` / `end_time` no longer accept null;
76
+ supply real `YYYY-MM-DD` dates or omit the keys to retain dates on update or leave a new
77
+ position unscheduled. A supplied `pwa_details_attributes` object requires
78
+ `skill_level: 'journeyman' | 'foreman' | null`; use `{ skill_level: null }` rather than `{}`.
79
+ Send `pwa` as a boolean and nonblank string IDs, using null to clear nullable references.
80
+ Use `zPositionParameters` to validate these forms locally.
81
+ - **Breaking:** `UserParameters` now types `enrolled_in_t_and_a` and `overtime_eligible` as
82
+ booleans, and `worked_annual_minutes`, `pto_annual_minutes`, `holiday_annual_minutes`, and
83
+ `training_annual_minutes` as nullable numbers instead of strings. Send whole-minute integers
84
+ and real booleans through `Users.createUser()`. `roles` no longer accepts null; omit it or
85
+ send `[]` to grant no roles, and send unique nonblank role strings. `company_user_pwa_info`
86
+ must be an object when supplied, without null. `zUserParameters` also checks nonblank names
87
+ and IDs and a date-only nullable `birth_date`. The old contact union is removed from the
88
+ generated type and schema, but the server still requires an email or phone unless
89
+ `skip_invite: true`; missing names return `400`, and invalid values return `422` with pointers.
90
+ Optional nullable profile fields now match accepted nulls. Omitted or null pay amounts now
91
+ remain unset rather than becoming zero. Send explicit '0' to designate zero: an unset
92
+ `training_annual_amount_cents` can fail the PWA designation check, and an unset
93
+ `hourly_rate_cents` can cause aggregate imports to return `HOURLY_RATE_NOT_FOUND` when no
94
+ position rate exists.
95
+ - **Breaking:** `JobCreateParameters` and `JobUpdateParameters` are standalone objects.
96
+ `created_by_user_id` is optional in the create type so template copies can inherit it; plain
97
+ creates still need a creator and requesting company. Job feature-allocation flags,
98
+ `job_work_types_attributes`, `job_address_attributes`, and address `verified` no longer accept
99
+ null; omit them to retain current values. `region` now accepts null.
100
+ `time_card_start_day` is a number, with `zJobCreateParameters` / `zJobUpdateParameters`
101
+ requiring an integer from 0 through 6. `Jobs.createJob()` / `updateJob()` now refuse wrong
102
+ JSON types and malformed nested fields with `422` pointers. Send lowercase PWA mode keys
103
+ (`'all'`, `'pw_only'`, `'ap_only'`, `'none'`), booleans for flags, nonblank IDs, and declared
104
+ nested keys. Null can still clear nullable schedule dates and references.
105
+ - **Breaking:** monetary write Zod schemas now reject malformed strings before submission,
106
+ matching server-side `422 validation_failed` errors with exact field pointers. Use plain
107
+ decimal strings with digits before the decimal point; blanks, whitespace, currency symbols,
108
+ scientific notation, and values such as `'.5'` are refused. This applies to employment pay,
109
+ time-entry and position rates, wage determinations, per diems, payroll amounts, project
110
+ budgets, asset prices, and production scope prices. Most values must be nonnegative;
111
+ `PaystubLineItemParameters.amount_cents` and `PositionParameters.pwa_wage_pay_rate_cents`
112
+ allow a leading minus. `RateRuleEffect.amount_cents` requires nonnegative whole-cent strings
113
+ such as `'300'`, without a decimal part. Handle these refusals through `Problem.errors`.
114
+ - **Breaking:** `PaystubLineItems.createPaystubLineItem()` / `updatePaystubLineItem()` enforce
115
+ the documented string `amount_cents`, nonblank reference IDs, and lowercase
116
+ `contributor: 'employee' | 'employer'`. JSON-number amounts now return `422`, and omitting any
117
+ of create's four required fields returns `400 parameter_missing`. Send decimal-string cents;
118
+ negative and fractional amounts remain supported. `zPaystubLineItemParameters` /
119
+ `zPaystubLineItemUpdateParameters` now validate the ID and money patterns.
120
+ - **Breaking:** `Users.createUser()`, `createCompany()`, `updateCompany()`,
121
+ `People.createEmployment()`, and `updateEmployment()` return `404` for a newly assigned
122
+ `manager_user_id` outside the key's visible people. Choose a visible manager. Employment
123
+ updates can still omit or resend an already held legacy manager; method signatures are unchanged.
124
+ - **Breaking:** `Users.removeUserFromCompany()` now requires
125
+ `headers: { 'If-Match': etag }` in `RemoveUserFromCompanyData`. Read the employment ID from
126
+ `UserResponseObject.employment_id`, then obtain its validator through
127
+ `People.listEmploymentHistory()` or, while a version covers now, `People.getEmployment()`.
128
+ A key without those read scopes may send `'*'` to delete whatever state exists.
129
+ `RemoveUserFromCompanyErrors` adds `412` and `428`: re-read after a stale validator and add
130
+ the header when it is missing. Success remains `200` with the user body.
131
+ - **Breaking at runtime:** `TimeEntries.createTimeEntry()` / `updateTimeEntry()` now interpret
132
+ `start_time` / `end_time` without an offset in the time card's pay schedule zone. If you mean
133
+ UTC, append `Z`; explicit `Z` or `±HH:MM` values retain their prior meaning. A bare date-time
134
+ now represents local wall time, including DST resolution and pay-period edge validation.
135
+ Request types remain strings, so TypeScript cannot catch a missing offset.
136
+ - **Breaking:** `CompetenciesAssessmentCriteria.listAssessmentCriteria()` /
137
+ `getAssessmentCriterion()` replace the assessment key-activity read methods. The new
138
+ `CompetencyAssessmentCriterionResponseObject` uses `competencies_criterion_id`.
139
+ `CompetenciesEvidenceItems.listEvidenceItems()` / `getEvidenceItem()` keep their method names
140
+ but replace `path.key_activity_id` with `path.criterion_id`; evidence responses replace
141
+ `competencies_assessment_key_activity_id` with `competencies_assessment_criterion_id`.
142
+ Grant `competencies.assessments.criteria:read` and
143
+ `competencies.assessments.criteria.evidence_items:read` in place of the retired key-activity
144
+ scopes. These reads remain available to companies with Competencies enabled.
145
+ `CompetencyCriterionParameters` / `CompetencyCriterionResponseObject` replace nullable
146
+ `assessment_method` with nonnullable `assessment_methods`, an array of the same eight method
147
+ values. Use `[]` for no suggested methods; corresponding Zod schemas follow the new shapes.
148
+
149
+ ### Removed
150
+
151
+ - **Breaking:** `JobParameters` and `zJobParameters` are removed. Import
152
+ `JobCreateParameters` / `zJobCreateParameters` or `JobUpdateParameters` /
153
+ `zJobUpdateParameters` for the owning write.
154
+ - **Breaking:** `PositionParameters.per_diem_rate_cents` is removed, including from
155
+ `zPositionParameters`; sending it now returns `400 unknown_key`. Select `per_diem_id`
156
+ instead, since the rate comes from that per diem.
157
+ - **Breaking:** `CompetenciesAssessmentKeyActivities`,
158
+ `CompetencyAssessmentKeyActivityResponseObject`, `ListAssessmentKeyActivities*`,
159
+ `GetAssessmentKeyActivity*`, and their corresponding Zod exports are removed. Migrate to
160
+ `CompetenciesAssessmentCriteria`, `CompetencyAssessmentCriterionResponseObject`,
161
+ `ListAssessmentCriteria*`, and `GetAssessmentCriterion*`.
162
+ - **Breaking:** `ProblemTypeCatalog` and `zProblemTypeCatalog` remove `non_numeric_cents`.
163
+ Delete that case from exhaustive switches and handle malformed money as `validation_failed`
164
+ with field pointers instead.
165
+
166
+ ### Fixed
167
+
168
+ - **Breaking response correction:** `AssetsItems.deleteDocument()` now resolves `204`
169
+ with no body. `DeleteDocumentResponses` replaces its `200: AssetsDocumentResponseObject`
170
+ arm with `204: void`, and `zDeleteDocumentResponse` validates void. Remove code that reads
171
+ the deleted document from the response; read it before deletion if needed.
172
+ - `DirectUploads.createDirectUpload()` now stores `resource: 'assets.items.documents'` uploads
173
+ on protected storage, matching the asset document attachment. Request and response types
174
+ stay unchanged; continue attaching the returned purpose-bound signed ID to an asset document.
175
+
176
+ See the [API changelog](https://dsptch.app/support/docs/developers/api-changelog#2026-10-14) for the
177
+ complete REST contract details and error behavior.
178
+
179
+ ## [0.36.0] - 2026-10-13
180
+
181
+ ### Added
182
+
183
+ - New class `ProjectDocuments`: `listProjectDocuments()`, `createProjectDocument()`,
184
+ `getProjectDocument()`, `updateProjectDocument()`, `deleteProjectDocument()`, and
185
+ `listProjectDocumentVersions()`. `ProjectDocumentParameters` requires `file` and
186
+ `performed_by_user_id`; get the signed file id through `DirectUploads.createDirectUpload()`
187
+ with `DirectUploadParameters.resource: 'projects.documents'`. `ProjectDocumentUpdateParameters`
188
+ accepts an optional replacement file and nullable `filename` / `description`.
189
+ `ProjectDocumentResponseObject.file` is nullable and exposes download metadata and `url`.
190
+ `ProjectDocumentVersionResponseObject` records audit events (`'create' | 'update' | 'destroy'`),
191
+ actor, and timestamp. List methods support cursor pagination; documents also support created/updated
192
+ date filters. Grant the appropriate `projects.documents:read` / `:create` / `:update` / `:delete`
193
+ scopes and `projects.documents.versions:read` for history. Corresponding operation types and Zod
194
+ schemas are exported.
195
+ - `PayPeriods.getPayPeriod()` reads an individual period with `path: { id }` and the existing
196
+ `pay_periods:read` scope. New `PayPeriodResponseObject` and `zPayPeriodResponseObject` are shared
197
+ by show and list responses. `ListPayPeriodsData.query` adds
198
+ `'filter[timekeeping_pay_period_config_id]'` to select a pay schedule family; use the same id each
199
+ period returns as `timekeeping_pay_period_config_id`.
200
+ - `ListEmploymentsData.query` adds `'filter[companies_department_id]'`. It selects the department
201
+ in the employment version at now or the supplied `'as_of[valid]'` time, so historical queries
202
+ follow historical assignments.
203
+
204
+ ### Changed
205
+
206
+ - **Breaking:** `TimeEntryCreateParameters` is now a standalone object requiring
207
+ `timekeeping_time_card_id`, `start_time`, and `end_time` for
208
+ `TimeEntries.createTimeEntry()`. `TimeEntryUpdateParameters` keeps every field optional for
209
+ `updateTimeEntry()`. Both make `feature_ids` a nonnullable array; create's
210
+ `feature_allocation_acknowledged` and update's `confirm_allocation_conflict` accept booleans only.
211
+ Pass `[]` to clear feature allocations and omit the field to retain them on update. The generated
212
+ Zod schemas validate the split objects and required create timestamps; timestamp strings are
213
+ parsed by the server rather than restricted to Zod's ISO date-time format. Missing required
214
+ fields return `400`; wrong JSON types return `422` with field pointers, and unparseable timestamp
215
+ strings return `422 invalid_date`. Correct the values before retrying.
216
+ - **Breaking:** `Users.updateCompany()` and `removeUserFromCompany()` take
217
+ `path: { user_id, id }` rather than `path: { user_id, company_id }`.
218
+ Update `UpdateCompanyData` / `RemoveUserFromCompanyData` call sites and their path-schema inputs;
219
+ `id` still holds the company id, so the actual HTTP URL is unchanged.
220
+ - **Breaking:** `UserCompanyParameters.type` and `UserCompanyCreateParameters.type` are
221
+ `'EMPLOYEE' | 'CONTRACTOR'`, without `null`. Omit the value for the create default or to retain it
222
+ on update. `Users.createCompany()` / `updateCompany()` now reject wrong JSON types before saving:
223
+ send pay and benefit amounts as decimal strings, minute amounts as integers, and enrollment /
224
+ overtime flags as booleans. Creating requires a valid `hire_date`; on an administrative update,
225
+ null or blank `hire_date` still retains the employment start. Custom-field rows require nonblank
226
+ `custom_field_config_id` and string-or-null `value`; send a list of row objects, not an indexed
227
+ object. Malformed values return `422` with a field pointer; missing required fields return `400`.
228
+ - **Breaking:** `UserParameters.group_ids` no longer accepts `null`. `Users.createUser()`,
229
+ `Groups.addUsersToGroup()`, `TimeEntries.createTimeEntry()` / `updateTimeEntry()`,
230
+ `ComplianceChecks.updateCheck()`, and form-assignment writes require unique nonblank IDs in
231
+ their group, feature, and assignee arrays. Null, blank, duplicate, or wrong-typed members now
232
+ return `422` before any write. Omit optional replacement arrays to retain them on update or send
233
+ `[]` to clear them; `UserGroupParameters.user_ids` must contain at least one ID. Corresponding
234
+ Zod schemas validate nonblank members and the group-add minimum; uniqueness remains server-side.
235
+ - **Breaking:** `AssetsTransfers.createTransfer()` validates endpoint IDs and `line_items`
236
+ before moving stock. Supply at most one endpoint per side and at least one side; endpoint IDs
237
+ must be nonblank strings. Supply a nonempty array of rows with `assets_item_id` and integer
238
+ `quantity >= 1`; indexed row objects, fractional quantities, numeric strings, and unknown row
239
+ keys return `422` with pointers. Missing `line_items` or required row fields returns `400`.
240
+ `AssetsTransferParameters.from_assets_sub_location_id` / `to_assets_sub_location_id` now allow
241
+ `null` for unbinned stock, matching their generated Zod schemas.
242
+ - **Breaking:** `ApprenticeshipWageSchedules.createWageSchedule()` / `updateWageSchedule()` and
243
+ `ApprenticeshipWageSchedulePeriods.createPeriod()` / `updatePeriod()` validate JSON types,
244
+ nullable fields, units, and nonnegative period values before saving. Send `periods_attributes`
245
+ as an array of row objects. Missing required fields return `400`; malformed or unknown nested
246
+ fields return `422` with pointers. A period must retain at least one of `min_minutes`,
247
+ `max_minutes`, or `num_competencies`, including after clearing values. `UpdateWageScheduleErrors`
248
+ now declares `422: Problem`; `CreatePeriodErrors` now declares `404: Problem` for a missing or
249
+ inaccessible schedule.
250
+ - **Breaking:** `AssetsAttributes.createAttribute()` / `updateAttribute()`,
251
+ `Certifications.createCertification()` / `updateCertification()`,
252
+ `Projects.createProject()` / `updateProject()`, `ComplianceChecks.updateCheck()`, and
253
+ `Users.updateUser()` reject wrong JSON types and undeclared body fields before saving.
254
+ Supply nonblank required names, booleans for flags, and only declared keys; nested option-row
255
+ failures return `422` with a row pointer instead of `400`. The corresponding generated Zod
256
+ schemas validate nonblank names and IDs. Project date fields require real `YYYY-MM-DD` strings
257
+ or null; timestamps, loose dates, and empty strings return `422 validation_failed` with a pointer.
258
+ Send an IANA zone or null for `tz_name` and an integer `0`–`6` or null for `billing_start_day`.
259
+ `zUserUpdateParameters.birth_date` now validates
260
+ a `YYYY-MM-DD` calendar date or null; timestamps are not dates.
261
+ - **Breaking:** `Timecodes` writes validate documented flags as booleans and reject blank names,
262
+ malformed values, and undeclared fields before saving. The create, correction, scheduled-change,
263
+ and genesis Zod schemas accept temporal strings for server parsing rather than enforcing ISO
264
+ date-time syntax locally. Omit create's `effective_date` to use now; sending null now returns
265
+ `422 validation_failed` instead of defaulting. Unparseable strings return `422 invalid_date`.
266
+ `updateTimecode()`, `scheduleTimecodeChange()`, and `shiftTimecodeGenesis()` validate the body
267
+ before `If-Match`, so malformed requests can return `400` / `422` ahead of `428`. Preserve the
268
+ header for valid writes and correct body errors before retrying.
269
+ - **Breaking:** `UserCertifications.approveUserCertification()` requires a company key to name
270
+ a nonblank `UserCertificationApprovalParameters.approved_by_user_id`; a user key must omit it
271
+ and approves as itself. A company key's omitted approver is `400`; supplied null or malformed
272
+ values are `422` with `#/approved_by_user_id`, while a user key naming an approver is `403`.
273
+ Correct the body for the key type rather than retrying a refused actor.
274
+ - **Breaking:** `People.updateCustomField()` requires a nonempty `custom_fields` array.
275
+ Missing the list or either row field (`custom_field_config_id` / `value`) now returns
276
+ `400 parameter_missing`, and extra row keys return `422 validation_failed` with a row-field
277
+ pointer. Body validation precedes `If-Match`; keep the precondition header for valid batches.
278
+ - **Breaking:** `JobWageDeterminations` and `ProjectWageDeterminations` writes validate
279
+ subtype fields before saving. Send decimal-string cents, nonblank classifications and trade
280
+ IDs, and lowercase `construction_category` values. Required create-field omissions now return
281
+ `400 parameter_missing`; malformed values return `422 validation_failed` with exact pointers.
282
+ Federal create requests must omit `regional_fields`; even `{}` is refused. On edits,
283
+ scheduled changes, and genesis shifts, invalid calendar dates (`effective_from` /
284
+ `effective_date`) now return `validation_failed` instead of `invalid_date`, before `If-Match`
285
+ failures. Send real `YYYY-MM-DD` dates and handle `Problem.errors` before retrying.
286
+ - **Breaking:** manager and safety-manager user keys no longer receive selectable packages from
287
+ `PayRateRulePackages.listPayRateRulePackages()`. `getPayRateRulePackage()` and the corresponding
288
+ `PayRateRules.listPayRateRules()`, `getPayRateRule()`, and `listPayRateRuleHistory()` lookups return
289
+ `404`. Use an administrator user key for reusable recipe details. Administrator user keys,
290
+ company keys, and existing reads of hidden determination packages retain their access.
291
+
292
+ ### Removed
293
+
294
+ - **Breaking:** `TimeEntryParameters` and `zTimeEntryParameters` are removed. Use
295
+ `TimeEntryCreateParameters` / `zTimeEntryCreateParameters` for creates and
296
+ `TimeEntryUpdateParameters` / `zTimeEntryUpdateParameters` for edits.
297
+ - **Breaking:** `RegionalWageDeterminationFields` and `zRegionalWageDeterminationFields` are
298
+ removed. Regional write fields are inline in the owning create, update, or scheduled-change
299
+ type. Derive a reusable type with
300
+ `NonNullable<RegionalJobWageDeterminationParameters['regional_fields']>` or its project
301
+ counterpart. Categorized-fringe fields now allow null in the TypeScript and Zod shape; the
302
+ server still requires nonnull fringe values for regions that require them and rejects fields
303
+ the region does not support.
304
+
305
+ ### Fixed
306
+
307
+ - `TimecodeScheduledChangeParameters.name` is optional. `Timecodes.scheduleTimecodeChange()`
308
+ can change flags or another attribute without resending the name; only `effective_date` is
309
+ required. `zTimecodeScheduledChangeParameters` matches this accepted partial write.
310
+ - `ApprenticeshipWageScheduleParameters.periods_attributes` makes `period_number`, `wage_percent`,
311
+ and `wage_cents` optional in nested rows, including edits or removals of existing periods.
312
+ Standalone `ApprenticeshipWageSchedulePeriods.createPeriod()` still requires all three.
313
+ `ApprenticeshipWageScheduleUpdateParameters.periods_attributes` and
314
+ its Zod schema now use simple row objects, so partial edits need not repeat a progression
315
+ threshold. The server validates the resulting period rather than just the supplied fields.
316
+ - `ProjectParameters.budget` and `ProjectUpdateParameters.budget` allow null, including through
317
+ their generated Zod schemas. Send null to clear a budget, a decimal string to set it, or omit
318
+ it on update to retain it.
319
+ - `FederalJobWageDeterminationParameters` and `FederalProjectWageDeterminationParameters`
320
+ expose optional nullable `overtime_package_id`. `RegionalJobWageDeterminationParameters` and
321
+ `RegionalProjectWageDeterminationParameters` expose optional nullable `class_code` and
322
+ `construction_category`. Corresponding create Zod schemas retain those fields instead of
323
+ stripping them. Regional `class_code` / `construction_category` remain ignored by the server,
324
+ and Federal creates still refuse a non-null overtime package; these are schema corrections.
325
+ Method names and response types are unchanged.
326
+ - `zComplianceCheckParameters.time_due` accepts a string or null instead of requiring ISO
327
+ date-time syntax. The server parses supplied dates and returns a validation problem for
328
+ malformed input; consumers using the schema can submit the server's accepted date forms.
329
+ - `AssetsProducts` writes with an out-of-range `default_minimum_quantity` and
330
+ `ProductionCompletions` writes with an out-of-range `quantity_completed` now return
331
+ `422 validation_failed` instead of `500 internal_error`. These range problems have no field
332
+ `errors` array; correct the number rather than retrying a server failure.
333
+
334
+ See the [API changelog](https://dsptch.app/support/docs/developers/api-changelog#2026-10-13) for the
335
+ complete REST contract details and error behavior.
336
+
8
337
  ## [0.35.0] - 2026-10-12
9
338
 
10
339
  ### Added