Fivexer

People & terms

Roster workers are the same workers used by task routing, with additional planning facts. Keep identity and qualifications on the worker; keep contract, pay, and site-planning facts in roster terms.

Qualifications

Shift eligibility is checked against a worker’s date-valid tags and qualifications. Use hard requirements for licences, clearances, languages, or role qualifications that must never be waived by scoring.

Requirements can apply to:

  • every person on a post or shift (requiredTags);
  • the composition of the whole shift (tagRequirements);
  • a maximum number in one category (tagMaximums).

Candidate explanations return failed requirements explicitly, so “not eligible” never has to be a black box.

Working terms

ts
await fivexer.roster.setTerms('worker_anna', {
  weeklyMinutes: 2_400,
  maxDaysInPeriod: 5,
  rateCents: 2_250,
  overtimeConsent: true,
  homeSiteId: 'site_north',
  siteIds: ['site_north', 'site_south'],
});

Important semantics:

  • weeklyMinutes: null means the contractual week is not stated.
  • maxDaysInPeriod: null means no personal period cap is stated.
  • rateCents: null inherits the workspace default rate when one exists.
  • overtimeConsent is tri-state: true, false, or null for never recorded. When consent is required, null is treated like no consent.
  • homeSiteId is a preference, not permission.
  • siteIds: [] means the person may work at every site. A non-empty list is a hard allow-list.

Pay configuration

Pay settings price a plan; they do not invent legal rules.

ts
await fivexer.roster.setPay({
  defaultRateCents: 2_000,
  bands: [
    { id: 'night', label: 'Night', startTime: '22:00', endTime: '06:00', multiplier: 1.25 },
  ],
  sundayMultiplier: 1.5,
  holidayMultiplier: 2,
  holidays: ['2026-12-25'],
  overtimeMultiplier: 1.5,
  stacking: 'max',
});

stacking: 'max' uses the largest applicable premium for a minute; add combines premiums. Personal rates override the workspace default. If no rate resolves for a worker, their planned time remains visible but no invented cost is returned.

Use roster.plannedHours({ from, to }) to read shift counts, ordinary time, premium-band minutes, overtime, and cost by worker and day. The response says whether it came from a published or draft plan.

Time off

Only approved leave constrains the solver. Pending requests appear in publishing preflight because publishing over one may be a legitimate manager decision, but it should never happen invisibly.

ts
const request = await fivexer.timeOff.create({
  workerId: 'worker_anna',
  startDate: '2026-09-14',
  endDate: '2026-09-18',
  kind: 'vacation',
});

const impact = await fivexer.timeOff.impact(request.id);
await fivexer.timeOff.approve(request.id);

Check impact before deciding: it identifies affected rosters and conflicting shifts. For sickness or a no-show after publication, use the cover workflow instead of rewriting historical leave.

Was this page helpful?