GET /company to establish the timezone and GET /schedule/settings for members, their scheduling capabilities, arrival-window options and calendar display hours.
Read a day or week
GET /schedule?starts_from=2026-09-08T07:00:00Z&starts_before=2026-09-09T07:00:00Z reads September 8 in Los Angeles. Both timestamps require an offset. The start is inclusive and the end exclusive. Visits qualify when their arrival window or an assignment overlaps the period, including work that began earlier.
The data array contains APPOINTMENT visits and INTERNAL_EVENT occurrences. Visits include customer, contact, location, coordinates, job dimensions, arrival window, confirmation/cancellation state and all assignments. A member filter selects visits involving that member; it retains their other technicians. An empty assignment array identifies an unassigned visit. Jobs without any visit remain available through /jobs.
Internal events retain their reason, such as training, on-call duty or time off. Recurring events expand in the company’s timezone, preserving local times through daylight-saving changes and honoring series end dates and exception days. Identify an occurrence with its series id and starts_at. Unsupported stored recurrence returns 409 INVALID_SCHEDULE_EVENT with the event ID instead of hiding the event.
Follow pagination.next_cursor until null. Periods may span at most 31 days; pages contain at most 100 complete items. Reads exceeding 5,000 selected visits, event series or occurrences return 400 SCHEDULE_TOO_LARGE; narrow the period or member filter. Order is earliest start at millisecond precision, ID, then kind. Cursors bind to the company, timezone and filters. They provide traversal of current data, not a snapshot or deletion feed.
The default canceled=false selects uncanceled visits and internal events. canceled=true selects canceled visits only. Business-unit, job-type and job-class filters select visits only; internal events have no such dimensions. Empty calendar space and display hours do not establish availability.
Understand dispatch state
Each assignment exposes its recorded execution status. The derived visitdispatch_status is CANCELED for canceled visits, UNASSIGNED with no assignments, then IN_PROGRESS if any assignment is in progress, EN_ROUTE if any is en route, COMPLETED if all assignments are completed, and ASSIGNED otherwise. This is operational state, not attendance, actual work hours or a lateness promise.
Change a visit
Every command requires an
Idempotency-Key header containing 8–128 letters, numbers, underscores or hyphens. Use a fresh key for each intended change. Retry the same operation with the same key and body after a network failure or retryable server error. Keys are scoped to company and authenticated user and retained without an automatic expiry. A different request with the same key returns 409 IDEMPOTENCY_CONFLICT.
For any edit, first read GET /schedule/appointments/{id} or use a visit returned by /schedule. Pass its opaque revision as expected_revision. A stale revision returns 409 STALE_REVISION without changes. Re-read the visit and reconsider the edit; do not automatically overwrite another dispatcher’s work. A successful command returns the full visit, a new revision and notification outcome. A replay returns the original committed visit snapshot; re-read to obtain subsequent changes.
assignments array preserves every technician. A supplied array replaces the complete set: include each existing assignment’s id to retain it; omit id to add one; omitted existing IDs are removed. Moving the arrival window does not shift assignments implicitly. Include their revised spans in the same request when both should move.
Assignments must have positive durations and distinct, active, eligible company members. Work outside the arrival window requires allow_outside_window=true, or an explicit window change. The API permits scheduling overlaps and does not select or reserve available slots. It rejects moving, reassigning, removing or canceling active/completed work; execution-status transitions remain an office workflow.
Write timestamps require a UTC offset and support up to six fractional second digits, matching database precision. Appointment windows must also have positive durations. UUIDs are case-insensitive; responses use their canonical lowercase spelling.
Request customer notifications explicitly
Omittingcustomer_notification (or sending null) sends no customer message for that operation, regardless of stored company defaults. Each operation may include one request:
notification.status is NOT_REQUESTED, PENDING, SENT (provider call completed), UNKNOWN (delivery may have occurred), or SUPPRESSED (the visit or recipient changed before delivery). An identical retry can resume an unclaimed pending send. Before sending, the API rechecks the visit revision, account contact link, selected destination and SMS subscription; an obsolete request is suppressed. An attempted send is never automatically repeated, including after a timeout or process interruption; UNKNOWN requires checking the communication history. Notification failure or suppression does not undo the visit change.
This slice does not send technician alerts or run job-lifecycle automations. Explicit status transitions, recurring-event editing, automatic booking, and draft preview/apply are separate workflows. Existing reporting reads retain their original filters and representations, including start-time filters on /job-appointments and /job-assignments.