Managing schedules
Create, update, query, and delete JSCalendar-aligned schedules compatible with RFC 5545 (iCalendar).
Navixy GraphQL API is a work in progress. This documentation is published for preview purposes only and doesn't reflect a stable release. Structure, field names, and behaviors are subject to change.
Schedules in Business Data Repository (BDR) define time-based rules for your fleet operations, maintenance windows, work hours, restrictions, and more.
The schedule data structure follows JSCalendar (RFC 8984), a JSON format for calendar data, and converts to RFC 5545 (iCalendar) and back without losing information. If you've worked with iCalendar concepts like RRULE, EXDATE, and VTIMEZONE, the model will be familiar: the field names and JSON structure come from JSCalendar, while the repeat rules behave as in iCalendar. If you haven't, that's fine. This guide explains everything you need.
This guide walks you through creating, configuring, updating, and deleting schedules.
Prerequisites
To work with a schedule, you need your workspace's ID. It comes with your access credentials and is carried in your access token. See Authentication for how tokens work and where the workspace ID comes from.
How schedule data works
A schedule consists of metadata (title and workspace) and calendar data stored in the scheduleData field, which accepts a value of ScheduleData, a structured JSON object validated on every write.
Top-level fields
The JSON structure follows the JSCalendar conventions:
timeZone
IANA timezone identifier (e.g., Europe/Berlin, America/New_York, UTC). Defines how the API interprets all date-time values in timed events.
events
Non-empty array of time slots, each with a start time, end time or duration, and an optional recurrence rule
active
Boolean. When false, the schedule is disabled without deleting it. Defaults to true.
description
Free-text description. The schedule's display name is the entity title, not this field.
How timezone works
All date-time values in events (start, end, excludedDates, additionalDates, and recurrenceRule.until) are local time with no UTC offset or Z suffix. The timeZone field tells the API how to interpret them.
For example, for "timeZone": "Europe/Berlin":
"start": "2025-01-06T06:00:00"means 6:00 AM Berlin time.The API handles daylight saving time (DST) changes automatically, so a recurring event at
06:00:00stays at 6 AM local time year-round.
All-day events (where showWithoutTime: true) use date strings instead of date-times (2025-06-10, not 2025-06-10T00:00:00) and are timezone-independent.
Event fields
Each event in the events array can include:
start
Yes
Start date-time for timed events (2025-01-06T06:00:00) or date for all-day events (2025-01-06). Seconds required. No fractional seconds. No offset or Z.
end
Conditional
End date-time (or date for all-day). Can't be combined with duration. A timed event needs exactly one of end or duration. An all-day event may omit both.
duration
Conditional
Duration in ISO 8601 format (e.g., PT9H, PT30M, P1D). Can't be combined with end. Must be positive. For all-day events, must be whole days (e.g., P1D, P2W) with no time component. Preferred over end for recurring events because it stays stable across DST changes.
showWithoutTime
No
When true, the event is all-day: start and end are dates, and the event ignores timeZone. All-day recurrence rules must not use byHour, byMinute, or bySecond.
recurrenceRule
No
Recurrence rule defining the repeat pattern. Absent means a single occurrence at start.
excludedDates
No
Array of local date-times to exclude from recurrence (iCalendar EXDATE). Values must exactly match generated occurrence date-times, including the time component.
additionalDates
No
Array of local date-times to add as one-off occurrences (iCalendar RDATE).
uid
No
Stable string identifier for the slot. Useful when tracking individual events across updates.
title
No
Display label for this event slot (maps to VEVENT SUMMARY).
Recurrence rule fields
The recurrenceRule property supports these fields:
frequency
String
Required. One of: secondly, minutely, hourly, daily, weekly, monthly, yearly. Lowercase.
interval
Integer
Repeat every N periods. Must be ≥ 1. Defaults to 1.
count
Integer
Stop after N occurrences. Can't be combined with until.
until
String
Stop after this local date-time. Must be ≥ start. Can't be combined with count.
byDay
Object[]
Days of the week. Each entry is { "day": "<mo|tu|we|th|fr|sa|su>", "nthOfPeriod": <integer> }. The optional nthOfPeriod sets an ordinal (e.g., { "day": "mo", "nthOfPeriod": 1 } = first Monday of the period) and is only valid for monthly or yearly frequency.
byMonth
Integer[]
Months: 1–12.
byMonthDay
Integer[]
Days of the month: 1–31, or -31 to -1 from the end (-1 = last day).
byYearDay
Integer[]
Days of the year: 1–366, or -366 to -1 from the end.
byWeekNo
Integer[]
Weeks of the year: 1–53, or -53 to -1. Valid only with yearly frequency.
byHour
Integer[]
Hours: 0–23. Must not be used on all-day events.
byMinute
Integer[]
Minutes: 0–59. Must not be used on all-day events.
bySecond
Integer[]
Seconds: 0–60 (60 is valid for leap seconds). Must not be used on all-day events.
firstDayOfWeek
String
First day of the week for week calculations. One of mo–su. Defaults to mo. (iCalendar WKST.)
Validation
scheduleData is validated on every write against the following rules:
required fields
pairs that can't be combined (
end/duration,count/until)date-time format (local time only, no offset or
Z)recurrence constraints (
byWeekNoonly withyearly, ordinalbyDayonly withmonthly/yearly, nobyHour/byMinute/bySecondon all-day events)field types
If the input breaks any of these rules, the API rejects the whole write with a validation error that names the problem field. The rules apply only to writes. Reading is never validated, so schedules saved before a rule existed can still be read.
Example scenario: Fleet maintenance schedule
TransLog GmbH needs to schedule weekly maintenance for their vehicle fleet. The maintenance provider works every Monday from 6:00 to 10:00 (Europe/Berlin timezone). Over time, requirements will change: holidays need to be excluded, the contract has an end date, and the maintenance window gets split to accommodate a break.
Create the schedule
Start with a weekly recurring event. The scheduleData field requires a timeZone and at least one event with a start and either end or duration.
Run this mutation:
Note the following:
timeZoneisEurope/Berlin. All date-times in this schedule are Berlin local time: noZ, no offset.start: "2025-01-06T06:00:00"is a Monday, which matches thebyDay: [{ day: "mo" }]rule. Always makestartmatch your repeat rule, otherwise the first occurrence may not land where you expect.duration: "PT4H"defines a 4-hour window (06:00–10:00). Usingdurationinstead ofendkeeps the window stable across DST changes.frequency: "weekly"withbyDay: [{ day: "mo" }]means the event repeats every Monday.
The response confirms creation:
Save the id and version. You'll need them for updating the schedule.
Exclude holidays
The maintenance provider doesn't work on public holidays. Several holidays in the year fall on Mondays. Add these as exception dates using excludedDates. This requires updating the schedule with scheduleUpdate.
When updating scheduleData, you must provide the complete value, as the API replaces the entire field. Include all existing configuration alongside your changes.
An entry in excludedDates must exactly match the date and time of the occurrence it removes, not just the date. This event's occurrences start at 06:00:00, so every excluded date ends with the same T06:00:00.
Run this mutation:
The response shows the incremented version:
Set an end date
The maintenance contract runs through December 31, 2025. Add an until date to the recurrence rule so the schedule stops repeating after that date.
until is inclusive: the last occurrence can fall on this date. It must be ≥ start and can't be combined with count. The schedule's version is now 3.
Split the schedule into two windows
The maintenance team requests a break from 8:00 to 8:30. Replace the single 4-hour event with two events: 6:00–8:00 and 8:30–10:00.
Each event needs its own excludedDates array with times matching that event's start. Run this mutation:
The schedule's version is now 4.
Delete the schedule
When the contract ends and you no longer need the schedule, run this mutation to delete it:
Response:
Including version ensures you don't accidentally delete a schedule that someone else has modified. If the version doesn't match, you'll receive a conflict error. See Optimistic locking for details on when to omit it.
Listing schedules
To retrieve all schedules for a workspace:
For details on pagination, see Pagination.
Handling version conflicts
If you include version in your mutation and the entity has been modified since you last fetched it, the API returns a conflict error:
To resolve this:
Query the schedule to get the current version and data
Merge your changes with the current state
Retry the mutation with the correct version
For more details on version conflicts, see Optimistic locking.
Common patterns
The snippets below show the recurrenceRule object in isolation. In practice, each belongs inside an event in the events array alongside start and end or duration.
Single-parameter patterns
Every weekday (standard work hours):
Every other week on Monday (bi-weekly team meetings):
First and fifteenth of each month (payroll processing):
Last day of each month (monthly reports deadline):
First Monday of each month (monthly fleet review):
Multi-parameter patterns
Every hour during weekday business hours (hourly check-ins):
Every Monday in January, April, July, and October (quarterly inspections):
Complete examples
Warehouse work hours
Standard weekday schedule with a lunch break, excluding company holidays:
Refrigerated truck temperature monitoring
Different temperature thresholds for day and night operation:
Equipment rental periods
Non-recurring schedule for specific rental dates:
Attaching schedules to other entities
A schedule on its own is just calendar data. To put it to work, link it to the entity it governs, such as the asset it defines maintenance windows for. The link is a REFERENCE custom field on the asset type, with refEntityTypeCode: "schedule" fixing what the field may point at. The same pattern links entities to tags and catalog items — only the refEntityTypeCode changes.
Define the reference field
Add the field definition to the asset type. See Implementing custom fields for the full definition workflow:
The response returns the type with its incremented version, as in the earlier update examples.
Read the schedule back from the asset
Select the field and use inline fragments, first on the value type, then on Schedule:
Response:
refs is always a list, and a single-value field returns one element. An element is null when the referenced schedule was deleted after being linked, so handle that case when reading.
To detach the schedule, remove the field with unset: ["cf_maintenance_schedule"] in assetUpdate, the same way device fields are unlinked in Working with assets.
See also
Schedules: Complete reference for all schedule operations and types
Implementing custom fields: Define custom fields and store your own data on entities
Working with assets: Create and manage assets such as vehicles and equipment
Last updated
Was this helpful?