When to use this endpoint

Use UserWorkShift_createData for CRM2’s Work Shifts create form. For replacing an entire schedule or restoring the company default, use the related user-level setter.

Authentication and permissions

The request must authenticate with signed API-key fields or a logged-in CRM session, and the tenant’s disableHREnhancements feature must not be enabled.

The handler does not check pageUserWorkShifts_add, Users edit permission, target ownership, or whether the target user is active. UI access controls are not server enforcement.

Parameters

ParameterTypeRequiredDescription
userID / user_idInteger stringYesTarget tenant user. userID takes precedence and must integer-convert above zero.
daysNative array, JSON array text, comma text, or scalarYes in practiceWeekday numbers 0 Sunday through 6 Saturday. Values are integer-converted, de-duplicated, range-filtered, and retain first-seen order. At least one must remain.
start / endHH:MM text or numeric seconds after midnightYesShift bounds. Text accepts one/two-digit hours and two-digit minutes at the start of the value. Numeric input is treated as seconds, not hours. Equal bounds are invalid; end before start represents an overnight shift.
lunchDuration / lunch_durationInteger minutesNoPositive values enable a lunch window and are stored as seconds. Negative values become zero. Camel-case takes precedence.
lunchEarliest / lunch_earliestHH:MM text or numeric secondsWhen lunch duration is positiveEarliest lunch start within the possibly overnight shift. Camel-case takes precedence.
lunchLatest / lunch_latestHH:MM text or numeric secondsWhen lunch duration is positiveLatest lunch start; the wrapped window must fit the duration and remain within the shift.

Example request

$created = FM_api('UserWorkShift_createData', [
	'userID' => '18',
	'days' => ['1', '2', '3', '4', '5'],
	'start' => '08:30',
	'end' => '17:00',
	'lunchDuration' => '30',
	'lunchEarliest' => '12:00',
	'lunchLatest' => '14:00',
]);

Example response

{
  "ok": 1,
  "id": 18002
}

Errors and unusual responses

ResponseCondition
{"error":"not logged in"}No authenticated tenant context is available. Invalid signed credentials can be rejected by the dispatcher before the handler runs.
{"error":"HR enhancements are disabled"}The controlling parent-employer/session feature flag equals 1.
{"error":"missing or invalid parameter: userID"}Neither user alias resolves above zero.
{"error":"user does not exist"}No tenant user has the target ID.
{"error":"invalid shift start/end time"}A bound cannot be parsed or the resulting schedule has an invalid/equal bound.
{"error":"each shift must include at least one day"}No valid weekday remains on the new or existing normalized shift.
{"error":"invalid lunch time"}A positive lunch has an unparseable/out-of-range window bound.
{"error":"lunch window must fit within the shift"}The wrapped lunch window lies outside the shift or is shorter than the requested duration.

Legacy application errors may be returned with HTTP 200. Check the decoded response for error, not only the HTTP status.

Behaviour and edge cases

  • The returned ID is synthetic: userID * 1000 + zeroBasedIndex + 1. It is not a database primary key and can change when earlier rows are deleted.
  • Schedules are saved as {"version":2,"shifts":[...]}. Multiple shifts may cover the same day or overlap; validation does not reject those combinations.
  • When lunch duration is zero, lunch-bound parameters are ignored and no lunch fields are stored. End value 86400 is permitted but renders as 00:00, making a later display round-trip ambiguous.
  • Company fallback derives from work-day-start/work-day-end minute settings and week-days-off. Shift consumers apply the tenant timezone, falling back to UTC for blank/invalid zones.

Side effects

  • Replaces the user’s complete meta.work_hours, preserving other metadata, sets current last_edited, sets edited_uuid="UserWorkShift", and invalidates the users cache.
  • Does not create generic audit history. The metadata read/replace/write is not protected against concurrent changes.

See it in Fieldmotion

CRM1

No direct CRM1 caller was found.

CRM2

Open a user and select Work Shifts → Create. The shared display widget calls this route.

Related endpoints

  • UserWorkShifts_getDataTable lists effective rows and their synthetic IDs.
  • User_setWorkShifts replaces/clears the whole schedule and returns explicit fallback metadata.