User guide
Scheduling and Dispatch
Looking for what it does rather than how to use it? Read the Scheduling and dispatch overview .
What it is
Scheduling and Dispatch is where technician time is planned and assigned: a calendar of appointments, maintenance windows, on-call shifts and time off, and a drag-and-drop board for moving that work between technicians and hours.
Concepts
| Concept | What it is |
|---|---|
| Event | One scheduled block of time. Has a type, a status, an organizer, and optional attendees and reminders. |
| Organizer | The person the event belongs to. Set from your session at creation; it is not a field you can pass. |
| Attendee | Someone invited. Either a person in Solidlio (gets an in-app notification) or an external email address. |
| Reminder | A lead time before the start, delivered in-app or by email. |
| Recurrence | An RFC 5545 RRULE on the parent event; occurrences are expanded on read. |
| Business hours | Your organization’s working week (Settings → SLA & Hours). Drives free/busy and suggested times. |
| Calendar sync | A per-user Microsoft 365 connection, bidirectional, with optional real-time webhooks. |
Event statuses
SCHEDULED → CONFIRMED → IN_PROGRESS → COMPLETED, with CANCELLED and NO_SHOW reachable at any point. Every transition is available from the event page’s status control.
Attendee responses
NEEDS_ACTION (default), ACCEPTED, DECLINED, TENTATIVE.
Roles and permissions
| Portal | Calendar, create/edit, event detail, sync settings | Dispatch board |
|---|---|---|
| MSP | Every role in the portal, technicians included | Same |
| Organization | organization administrator, power user (plus platform administrator, MSP administrator) | organization administrator only (plus platform administrator, MSP administrator) |
Customer (/user) | Not available | Not available |
Creating an event follows the view capability rather than a separate manage capability: the organizer is always the caller, and booking your own appointments is the everyday action a technician needs.
Within the API, visibility is not role-based but ownership-based. A caller may see and edit an event when any of these hold:
- they organize it, or
- they are an attendee of it, or
- it belongs to their account and is not marked private.
Rule 3 is why a colleague can move your team meeting but cannot open your private one-to-one. Marking an event Private removes it from rule 3 entirely.
Cross-tenant ids are rejected on write and return 404 on read — an event belonging to another account is indistinguishable from one that does not exist.
Walkthroughs
Schedule an appointment
- Go to Calendar → + New Event (
/msp/calendar/newor/org/calendar/new). - Give it a title and pick a type. The type sets the colour the event carries on every screen.
- Set start and end. Tick All day to span whole days.
- Optionally set a recurrence — daily, weekly, every weekday, monthly or yearly.
- Under Attendees, tick the staff who should be invited.
- Use the Scheduling assistant below the attendee list:
- Check this time reports which invitees already have something booked, with the conflicting titles and times.
- Suggest times returns up to five ranked slots over the next 14 days that fit everyone, inside your organization’s business hours. Click one to apply it to the form.
- Under Reminders, choose lead times. Each becomes a reminder delivered in-app by default.
- Create event. Every in-system attendee receives a “New calendar invitation” notification.
An event’s colour is not chosen — it comes from its type, and is the same colour that type has on the board, in the month grid and on the event page. That is what makes the legend readable, so there is no per-event colour picker.
Dispatch work to another technician
- Go to Scheduling (
/msp/schedulingor/org/scheduling). The MSP portal opens on the Dispatch board tab. - Rows are technicians, columns are hours from 07:00 to 19:00. Switch between day and week with the toggle. An hour rule marks each hour and a red line marks the current moment.
- Drag an event block onto another technician’s row, or to a different time on the same row. The change is saved on drop. A drop target that would overlap an existing booking is outlined in red and refuses the drop.
- Each technician carries a load ribbon. Its track is the length of that person’s configured working day, so a six-hour Friday is visibly shorter than an eight-hour Tuesday, and a day the organization does not staff is hatched rather than shown as empty. Bands: Open under 50%, Steady 50–79%, At capacity 80–100%, Over capacity above 100%. In day view the figure comes from the availability engine and divides by that day’s actual configured hours; week view is a local estimate over the grid window and is labelled “estimated”.
- If your own calendar contains overlapping events in the visible range, a banner at the top of the board lists them, and the Overlaps tile counts them.
- The type legend below the header doubles as a filter — click a type to show only that kind of work.
Connect a Microsoft 365 calendar
- Go to Settings → Calendar Sync (
/msp/settings/calendaror/org/settings/calendar). - Click Connect Microsoft 365 and complete consent. Solidlio requests
offline_accessandCalendars.ReadWrite. - Choose which O365 calendar to sync against, then set:
- Direction — to O365, from O365, or both
- Frequency — real-time (webhooks), 15/30/60/360 minutes, or manual only
- Include private events and Auto-accept invites
- Turn on Real-time sync to register a Microsoft Graph webhook subscription. Graph caps these at three days; the status card shows the expiry.
- Sync History lists each run with its direction, outcome, and counts of events created, updated and deleted.
- From an event page, Push to M365 sends that single event immediately. The button only appears when a calendar is connected.
Manage attendees and RSVP
- Open the event (
/msp/calendar/{id}or/org/calendar/{id}). - The Attendees card header shows accepted-over-total.
- Add opens a picker: choose a colleague from the dropdown, or type an external email address. People already invited are filtered out.
- Opt toggles an attendee between required and optional. The × removes them.
- If you are on the invite list, Your response appears above the list with Yes / Maybe / No.
Configuration
| Setting | Where | Effect if unset |
|---|---|---|
| Business hours | Settings → SLA & Hours | Availability falls back to 09:00–17:00, weekdays only |
| Holidays | Settings → SLA & Hours | No days are excluded from suggestions |
| Business-hours timezone | Per BusinessHours row | Falls back to UTC — never the server’s local zone |
| Event timezone | Per event | America/Toronto |
| Sync direction | Settings → Calendar Sync | Bidirectional |
| Sync frequency | Settings → Calendar Sync | 15 minutes |
| Include private events | Settings → Calendar Sync | Off — private events are not pushed to O365 |
| Auto-accept invites | Settings → Calendar Sync | Off |
Plan tiers
Every paying tier gets the whole feature; access differences come from portal and role only.
Troubleshooting
| What you see | Cause |
|---|---|
Invalid state on the OAuth callback | The signed state was tampered with, or is older than 30 minutes. Start the connect flow again |
Invalid recurrence rule format | The RRULE string does not parse |
Invalid ticketId: the referenced record does not exist or is not accessible | The linked record belongs to another tenant, or does not exist. The message is identical for both, deliberately |
Attendee already exists for this event (409) | That person or email is already invited |
At least one of personId or email must be provided | An attendee entry identified nobody |
| Event not found (404) on an id you can see elsewhere | It is private and you are neither organizer nor attendee |
| Suggested times come back empty | No slot fits everyone inside business hours in the window — widen the range, or check that the days are configured as working days |
How the calendar reads
Colour carries exactly one meaning across every scheduling surface: what kind of work an event is. Status, attendee response and privacy are carried in text badges instead, so a board where everything is coloured never becomes a board where nothing stands out.
| Type | Reads as |
|---|---|
| Appointment | Cyan — customer meeting or visit |
| Maintenance | Amber — scheduled window |
| Project task | Violet — project work block |
| Internal meeting | Blue |
| On-call | Red — shift cover |
| Time off | Green — PTO or vacation |
| Reminder | Orange |
| Other | Neutral |
These resolve through the platform’s theme tokens, so a tenant that rebrands gets a calendar that follows rather than a fixed palette.
Limits and known behaviour
- SMS reminders are not delivered.
ReminderMethod.SMSexists in the schema but this platform integrates no SMS provider. The reminder job counts these undersmsSkippedand deliberately leaves them unsent rather than marking them delivered. - Reminders fire on a five-minute cadence, so a one-minute lead time is approximate. A reminder whose event started more than 20 minutes ago is retired without delivery rather than arriving late.
- A failed reminder is retried, not dropped. If no recipient could be reached, the row stays unsent and the next run tries again.
- Account colleagues can edit and delete your non-private events. Visibility and mutation share one boundary. Use Private for anything that should not be.
- Recurring occurrences are computed on read. Editing a single occurrence of a series is not supported; edits apply to the parent.
- Business hours are read from one organization per request. For an MSP-portal caller with no organization context, they resolve from the people being scheduled — and only when those people all sit in a single organization. Otherwise the 09:00–17:00 default applies.
- Utilization on the dispatch board is business-hours-accurate in day view only. Week view estimates against the board’s fixed 07:00–19:00 window, because the availability route answers for a single day.
- They are supported API surface, not screens.
- Email reminders use one template,
calendar_event_reminder. Invitations, updates and cancellations are in-app only; there is no email invitation and no.icsattachment. - Per-event colours cannot be chosen. Colour means event type everywhere, so the stored
coloris derived from the type on save. Events created before this change keep their stored value in the database but render by type. - The month grid shows three events per day, then a “+N more” count. Switch to week view to see them all.
- Load ribbons are exact in day view only. Week view estimates against the board’s fixed 07:00–19:00 window, because the availability route answers for a single day; those ribbons are labelled “estimated”.