Calendar Sync
Google Calendar Sync Guide
When to Connect Google Calendar
-
When resources need their external Google Calendar events to block availability in OnSched.
-
To automatically create calendar events in Google Calendar when appointments are booked in OnSched.
-
To keep multiple Google calendars (primary plus shared calendars) synchronized with OnSched availability.
-
To enable real-time availability checks that account for external calendar conflicts via the
syncExternalparameter.
Google Calendar sync creates a bidirectional connection: external events become unavailability blocks in OnSched, and OnSched appointments become events in the selected Google Calendar. This keeps both systems in sync without manual entry.
Required Context
-
Authentication: All external calendar requests require a valid API key with access to the requested company.
-
Resource setup: The resource must exist and have an email address. The Google account email will be used as the primary calendar identifier.
-
OAuth flow: Google Calendar sync uses OAuth 2.0. You'll need to handle a redirect flow where users grant permissions to OnSched to access their calendars.
-
Calendar permissions: The sync requires read and write access to Google Calendar. Users must grant these permissions during the OAuth consent screen.
Connecting in the OnSched App
Initial Connection Flow
-
Navigate to Resource Settings: Open the resource you want to connect and go to the Calendar Sync settings.
-
Generate Authorization URL: Click "Connect Google Calendar" to create a new external calendar connection. The app calls
POST /v3/resource/{id}/externalCalendarwithprovider: "google". -
Authorize Access: A new tab opens with the Google OAuth consent screen. The authorization URL is also available as a copyable link in the UI. Users must sign in to their Google account and grant calendar permissions.
-
Complete OAuth Callback: After granting permissions, Google redirects to OnSched's callback endpoint (
/v3/calendar/callback). OnSched exchanges the authorization code for a refresh token and stores the connection. -
Select Calendars: Once connected, users can select which calendars to sync:
- Read calendars: Calendars from which events will be imported as unavailability blocks.
- Write calendar: The calendar where OnSched appointments will be created as events.
-
Start Syncing: After calendar selection, external events are automatically synced as unavailability blocks, and new appointments create events in the write calendar.
Calendar Selection
The primary calendar (the user's email address) is automatically included in the read set. You can add additional calendars (shared calendars, secondary calendars) to the read set. Only one calendar can be designated as the write calendar at a time.
Events created by OnSched are marked with createdBy: 'ONSCHED' in their extended properties, so they're excluded from being re-imported as unavailability blocks.
API Endpoints for Custom Integration
If you're building your own integration, you'll use these endpoints to implement the Google Calendar sync flow:
1. Create External Calendar Connection
Endpoint: POST /v3/resource/{id}/externalCalendar
Description: Creates a pending external calendar connection and returns an authorization URL.
Request Body:
{
"provider": "google",
"calendarId": "primary"
}Response:
{
"success": true,
"data": {
"id": "645afc52-8c92-4ba2-8047-de56f8783f99",
"ResourceId": "fd9a18bb-8e9f-45be-be3d-3aa1b6aa0644",
"provider": "google",
"pending": true,
"authUrl": "https://accounts.google.com/o/oauth2/v2/auth?access_type=offline&scope=...",
"calendarId": null,
"read": false,
"write": false
}
}The authUrl in the response is the Google OAuth consent URL. Direct users to this URL to grant permissions.
2. OAuth Callback
Endpoint: GET /v3/calendar/callback?code={code}&state={state}
Description: Handles the OAuth callback from Google. Exchanges the authorization code for refresh tokens and completes the connection.
Query Parameters:
code: The authorization code from Google (required)state: JSON string containing{ id, provider }(required)
Note: This endpoint is public (no authentication required) and handles the OAuth redirect automatically. After processing, it redirects users to your configured redirect URL or the OnSched calendar selection page.
Response: Redirects to your application with connection details or to the calendar selection interface.
3. List Available Calendars
Endpoint: GET /v3/resource/{id}/externalCalendars/list
Description: Returns all Google calendars accessible to the connected account. Use this after OAuth completion to let users choose which calendars to sync.
Response:
{
"success": true,
"data": [
[
{
"id": "[email protected]",
"summary": "[email protected]",
"primary": true,
"accessRole": "owner"
},
{
"id": "[email protected]",
"summary": "Team Calendar",
"primary": false,
"accessRole": "reader"
}
]
]
}The response is a nested array because multiple Google accounts can be connected. Each inner array represents calendars from a single account.
4. Select Calendars for Sync
Endpoint: POST /v3/resource/{id}/externalCalendars/select
Description: Configures which calendars to read from and which calendar to write appointments to.
Request Body:
{
"readCalendarIds": [
"[email protected]",
"[email protected]"
],
"writeCalendarId": "[email protected]"
}Notes:
- The primary calendar (user's email) is always included in the read set, even if not explicitly listed.
- The write calendar must also be in the read set.
- Only calendars with
accessRoleof"owner"or"writer"can be set as write calendars. - If
externalCalendarIdis provided in the URL path, selections apply to that specific connection; otherwise, they apply to the first non-pending Google calendar for the resource.
Response:
{
"success": true,
"data": [
{
"id": "645afc52-8c92-4ba2-8047-de56f8783f99",
"ResourceId": "fd9a18bb-8e9f-45be-be3d-3aa1b6aa0644",
"provider": "google",
"calendarId": "[email protected]",
"calendarEmail": "[email protected]",
"read": true,
"write": true,
"pending": false
},
{
"id": "789bfc52-8c92-4ba2-8047-de56f8783f00",
"ResourceId": "fd9a18bb-8e9f-45be-be3d-3aa1b6aa0644",
"provider": "google",
"calendarId": "[email protected]",
"calendarEmail": "[email protected]",
"read": true,
"write": false,
"pending": false
}
]
}5. Get Connected Calendars
Endpoint: GET /v3/resource/{id}/externalCalendar
Description: Retrieves all external calendar connections for a resource.
Response:
{
"success": true,
"data": [
{
"id": "645afc52-8c92-4ba2-8047-de56f8783f99",
"ResourceId": "fd9a18bb-8e9f-45be-be3d-3aa1b6aa0644",
"provider": "google",
"calendarId": "[email protected]",
"calendarEmail": "[email protected]",
"read": true,
"write": true,
"pending": false,
"authUrl": null
}
]
}6. Regenerate Authorization URL
Endpoint: PUT /v3/resource/{id}/externalCalendar/{externalCalendarId}/regenerateAuthUrl
Description: Generates a new authorization URL if the previous one expired or if the user needs to reconnect.
Response:
{
"success": true,
"data": {
"id": "645afc52-8c92-4ba2-8047-de56f8783f99",
"authUrl": "https://accounts.google.com/o/oauth2/v2/auth?access_type=offline&scope=...",
"pending": true
}
}7. Sync External Events as Unavailability
Endpoint: POST /v3/resource/{id}/externalCalendar/createUnavailabilityBulk?startDate={startDate}&endDate={endDate}
Description: Manually triggers a sync of external calendar events as unavailability blocks within a date range. External events that don't have createdBy: 'ONSCHED' in their extended properties are imported.
Query Parameters:
startDate: ISO 8601 timestamp for the start of the sync window (required)endDate: ISO 8601 timestamp for the end of the sync window (required)
Response:
OK
This creates Unavailability records with reasonType: 'EXT' for each external event in the date range.
8. Delete Calendar Connection
Endpoint: DELETE /v3/resource/{id}/externalCalendar/{externalCalendarId}
Description: Disconnects a Google Calendar and revokes access. This also deletes all calendar entries created by OnSched in Google Calendar.
Response:
{
"success": true,
"data": {
"id": "645afc52-8c92-4ba2-8047-de56f8783f99"
}
}Complete OAuth Flow
Here's the step-by-step flow for implementing Google Calendar sync in your application:
Step 1: Create Pending Connection
POST /v3/resource/{resourceId}/externalCalendar
Headers:
Authorization: Bearer {token}
X-Company-API-Key: {companyApiKey}
Body:
{
"provider": "google",
"calendarId": "primary"
}Store the returned externalCalendarId and authUrl.
Step 2: Redirect User to Authorization URL
Open the authUrl in a browser or redirect the user. They'll see Google's consent screen requesting:
- View your email address
- See, edit, share, and permanently delete all calendars you can access
- View events on all calendars you can access
Step 3: Handle OAuth Callback
After the user grants permissions, Google redirects to:
GET /v3/calendar/callback?code={authorization_code}&state={"id":"{externalCalendarId}","provider":"google"}
OnSched automatically:
- Exchanges the code for refresh tokens
- Stores the refresh token and calendar email
- Marks the connection as non-pending
- Redirects to your configured return URL or the calendar selection page
Step 4: List Available Calendars
GET /v3/resource/{resourceId}/externalCalendars/list
Headers:
Authorization: Bearer {token}
X-Company-API-Key: {companyApiKey}Present the calendars to the user and let them select which to read from and which to write to.
Step 5: Select Calendars
POST /v3/resource/{resourceId}/externalCalendars/select
Headers:
Authorization: Bearer {token}
X-Company-API-Key: {companyApiKey}
Body:
{
"readCalendarIds": ["[email protected]", "[email protected]"],
"writeCalendarId": "[email protected]"
}Step 6: Sync External Events (Optional)
If you want to manually trigger a sync instead of waiting for automatic background sync:
POST /v3/resource/{resourceId}/externalCalendar/createUnavailabilityBulk?startDate=2025-03-01T00:00:00Z&endDate=2025-03-31T23:59:59Z
Headers:
Authorization: Bearer {token}
X-Company-API-Key: {companyApiKey}How Syncing Works
Reading from Google Calendar
External calendar events are imported as Unavailability records with reasonType: 'EXT'. These blocks prevent availability during those times.
Event Filtering:
- Only events without
extendedProperties.private.createdBy === 'ONSCHED'are imported - This prevents OnSched-created appointments from being re-imported as unavailability
- Events are converted using their
start.dateTimeandend.dateTimevalues
Automatic Sync:
- Background jobs periodically sync external events
- You can trigger manual syncs via the
createUnavailabilityBulkendpoint - Availability requests with
syncExternal=truetrigger an on-demand sync before calculating slots
Writing to Google Calendar
When appointments are created in OnSched, events are automatically created in the write calendar for each resource with write: true.
Event Creation:
- Event summary: Service name
- Event location: Full address from the location
- Event description: Service description
- Start/end times: Match the appointment's unavailability block
- Extended properties: Marked with
createdBy: 'ONSCHED'and theUnavailabilityId
Event Deletion:
- When appointments are deleted in OnSched, corresponding Google Calendar events are also deleted
- The
googleCalendarEventIdstored on the appointment record is used for deletion
Calendar Selection Behavior
- Primary calendar: Always included in the read set (user's email address)
- Multiple calendars: You can select multiple calendars for reading, but only one for writing
- Access roles: Write calendar must have
accessRoleof"owner"or"writer" - Shared calendars: Can be added to the read set if the user has access
Availability Integration
External calendar events affect availability calculations when:
- Automatic background sync: External events are periodically synced and become unavailability blocks
- Manual sync: Calling
createUnavailabilityBulkimports events for a date range - On-demand sync: Setting
syncExternal=truein availability requests triggers an immediate sync before calculating slots
Availability Request Example:
GET /v3/availability?startDate=2025-03-21&endDate=2025-03-21&LocationId={locId}&ServiceId={svcId}&ResourceIds={resourceId}&syncExternal=trueThe syncExternal parameter adds latency but ensures the most up-to-date calendar state is considered.
Response Examples
Successful Connection
{
"success": true,
"data": {
"id": "645afc52-8c92-4ba2-8047-de56f8783f99",
"ResourceId": "fd9a18bb-8e9f-45be-be3d-3aa1b6aa0644",
"provider": "google",
"calendarId": "[email protected]",
"calendarEmail": "[email protected]",
"read": true,
"write": true,
"pending": false,
"createdAt": "2025-02-14T10:00:00Z",
"updatedAt": "2025-02-14T10:05:00Z"
}
}Calendar List
{
"success": true,
"data": [
[
{
"id": "[email protected]",
"summary": "[email protected]",
"primary": true,
"accessRole": "owner"
},
{
"id": "[email protected]",
"summary": "Team Calendar",
"primary": false,
"accessRole": "reader"
},
{
"id": "[email protected]",
"summary": "Personal Calendar",
"primary": false,
"accessRole": "writer"
}
]
]
}Usage Patterns
Basic Connection Flow
# 1. Create connection
curl -X POST "https://api.onsched.com/v3/resource/{resourceId}/externalCalendar" \
-H "Authorization: Bearer {token}" \
-H "X-Company-API-Key: {apiKey}" \
-H "Content-Type: application/json" \
-d '{"provider": "google", "calendarId": "primary"}'
# 2. User authorizes at authUrl (manual step)
# 3. List calendars after OAuth callback
curl -X GET "https://api.onsched.com/v3/resource/{resourceId}/externalCalendars/list" \
-H "Authorization: Bearer {token}" \
-H "X-Company-API-Key: {apiKey}"
# 4. Select calendars
curl -X POST "https://api.onsched.com/v3/resource/{resourceId}/externalCalendars/select" \
-H "Authorization: Bearer {token}" \
-H "X-Company-API-Key: {apiKey}" \
-H "Content-Type: application/json" \
-d '{
"readCalendarIds": ["[email protected]"],
"writeCalendarId": "[email protected]"
}'Manual Sync Trigger
# Sync external events for the next 30 days
curl -X POST "https://api.onsched.com/v3/resource/{resourceId}/externalCalendar/createUnavailabilityBulk?startDate=2025-03-01T00:00:00Z&endDate=2025-03-31T23:59:59Z" \
-H "Authorization: Bearer {token}" \
-H "X-Company-API-Key: {apiKey}"Multi-Calendar Setup
# Select primary calendar for writing, multiple calendars for reading
curl -X POST "https://api.onsched.com/v3/resource/{resourceId}/externalCalendars/select" \
-H "Authorization: Bearer {token}" \
-H "X-Company-API-Key: {apiKey}" \
-H "Content-Type: application/json" \
-d '{
"readCalendarIds": [
"[email protected]",
"[email protected]",
"[email protected]"
],
"writeCalendarId": "[email protected]"
}'Troubleshooting
-
Authorization URL expired: Regenerate it using
PUT /v3/resource/{id}/externalCalendar/{externalCalendarId}/regenerateAuthUrl. Authorization URLs can expire if not used promptly. -
Refresh token expired: If the refresh token becomes invalid (user revoked access, account changes), regenerate the authorization URL and have the user reconnect.
-
Calendar not appearing in list: Ensure the user has access to the calendar in their Google account. Shared calendars require explicit sharing permissions.
-
Write permission denied: Only calendars with
accessRoleof"owner"or"writer"can be set as write calendars. Check theaccessRolefield in the calendar list response. -
Events not syncing: External events are filtered by the
createdBy: 'ONSCHED'marker. Ensure events you want imported don't have this property. Also verify the calendar is selected for reading and the date range covers the events. -
Appointments not creating calendar events: Verify the calendar connection has
write: trueand check that the resource is assigned to the appointment. Only resources with write-enabled calendars receive events. -
OAuth callback errors: The callback endpoint requires both
codeandstateparameters. Ensure thestateparameter contains valid JSON withidandproviderfields. -
Multiple Google accounts: If a resource has multiple Google accounts connected, specify
externalCalendarIdwhen selecting calendars to avoid ambiguity.
With these practices, you can build robust Google Calendar integrations that keep OnSched and Google Calendar synchronized automatically.
Outlook Calendar Sync Guide
When to Connect Outlook Calendar
-
When resources need their external Outlook Calendar events to block availability in OnSched.
-
To automatically create calendar events in Outlook Calendar when appointments are booked in OnSched.
-
To keep Outlook calendars synchronized with OnSched availability for Microsoft 365 and Outlook.com users.
-
To enable real-time availability checks that account for external calendar conflicts via the
syncExternalparameter.
Outlook Calendar sync creates a bidirectional connection: external events become unavailability blocks in OnSched, and OnSched appointments become events in the user's primary Outlook Calendar. Unlike Google Calendar, Outlook syncs only with the primary calendar—multiple calendar selection is not supported.
Required Context
-
Authentication: All external calendar requests require a valid API key with access to the requested company.
-
Resource setup: The resource must exist and have an email address. The Outlook account email will be used as the calendar identifier.
-
OAuth flow: Outlook Calendar sync uses Microsoft Authentication Library (MSAL) and OAuth 2.0. You'll need to handle a redirect flow where users grant permissions to OnSched to access their calendars.
-
Calendar permissions: The sync requires read and write access to Outlook Calendar. Users must grant these permissions during the Microsoft OAuth consent screen.
-
Microsoft account: Users must have a Microsoft account (Microsoft 365, Outlook.com, or work/school account) to connect Outlook calendars.
Connecting in the OnSched App
Initial Connection Flow
-
Navigate to Resource Settings: Open the resource you want to connect and go to the Calendar Sync settings.
-
Generate Authorization URL: Click "Connect Outlook Calendar" to create a new external calendar connection. The app calls
POST /v3/resource/{id}/externalCalendarwithprovider: "outlook". -
Authorize Access: A new tab opens with the Microsoft OAuth consent screen. The authorization URL is also available as a copyable link in the UI. Users must sign in to their Microsoft account and grant calendar permissions.
-
Complete OAuth Callback: After granting permissions, Microsoft redirects to OnSched's callback endpoint (
/v3/calendar/callback). OnSched exchanges the authorization code for refresh tokens and stores the connection. -
Start Syncing: Unlike Google Calendar, Outlook Calendar doesn't require calendar selection. After OAuth completion, the connection is automatically configured with read and write access to the user's primary calendar. External events are automatically synced as unavailability blocks, and new appointments create events in Outlook.
Calendar Selection
Outlook does not support calendar selection. Only the user's primary calendar (their email address) is synced. The connection automatically has both read and write permissions enabled after successful OAuth.
Events created by OnSched are marked with organizer.emailAddress.name === 'ONSCHED' and include an extension property com.onsched.unavailabilityId, so they're excluded from being re-imported as unavailability blocks.
API Endpoints for Custom Integration
If you're building your own integration, you'll use these endpoints to implement the Outlook Calendar sync flow:
1. Create External Calendar Connection
Endpoint: POST /v3/resource/{id}/externalCalendar
Description: Creates a pending external calendar connection and returns an authorization URL.
Request Body:
{
"provider": "outlook"
}Note: Unlike Google Calendar, Outlook doesn't require a calendarId parameter.
Response:
{
"success": true,
"data": {
"id": "789bfc52-8c92-4ba2-8047-de56f8783f00",
"ResourceId": "fd9a18bb-8e9f-45be-be3d-3aa1b6aa0644",
"provider": "outlook",
"pending": true,
"authUrl": "https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=...",
"calendarId": null,
"read": false,
"write": false
}
}The authUrl in the response is the Microsoft OAuth consent URL. Direct users to this URL to grant permissions.
2. OAuth Callback
Endpoint: GET /v3/calendar/callback?code={code}&state={state}
Description: Handles the OAuth callback from Microsoft. Exchanges the authorization code for refresh tokens and completes the connection.
Query Parameters:
code: The authorization code from Microsoft (required)state: JSON string containing{ id, provider }(required)
Note: This endpoint is public (no authentication required) and handles the OAuth redirect automatically. After processing, it redirects users to your configured redirect URL or the OnSched calendar selection page. For Outlook, the connection is automatically configured with read and write access—no additional selection step is needed.
Response: Redirects to your application with connection details.
3. Get Connected Calendars
Endpoint: GET /v3/resource/{id}/externalCalendar
Description: Retrieves all external calendar connections for a resource.
Response:
{
"success": true,
"data": [
{
"id": "789bfc52-8c92-4ba2-8047-de56f8783f00",
"ResourceId": "fd9a18bb-8e9f-45be-be3d-3aa1b6aa0644",
"provider": "outlook",
"calendarId": "homeAccountId-123",
"calendarEmail": "[email protected]",
"read": true,
"write": true,
"pending": false,
"authUrl": null
}
]
}Note: Outlook calendars use homeAccountId as the calendarId, which is Microsoft's account identifier.
4. List Available Calendars
Endpoint: GET /v3/resource/{id}/externalCalendars/list
Description: Not supported for Outlook. This endpoint only works for Google Calendar. Outlook connections automatically sync with the primary calendar only.
Response: Returns an error if called for Outlook calendars.
5. Select Calendars for Sync
Endpoint: POST /v3/resource/{id}/externalCalendars/select
Description: Not supported for Outlook. Calendar selection is only available for Google Calendar. Outlook connections automatically have read and write access to the primary calendar after OAuth completion.
Response: Returns an error if called for Outlook calendars.
6. Regenerate Authorization URL
Endpoint: PUT /v3/resource/{id}/externalCalendar/{externalCalendarId}/regenerateAuthUrl
Description: Generates a new authorization URL if the previous one expired or if the user needs to reconnect.
Response:
{
"success": true,
"data": {
"id": "789bfc52-8c92-4ba2-8047-de56f8783f00",
"authUrl": "https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=...",
"pending": true
}
}7. Sync External Events as Unavailability
Endpoint: POST /v3/resource/{id}/externalCalendar/createUnavailabilityBulk?startDate={startDate}&endDate={endDate}
Description: Manually triggers a sync of external calendar events as unavailability blocks within a date range. External events that don't have organizer.emailAddress.name === 'ONSCHED' are imported.
Query Parameters:
startDate: ISO 8601 timestamp for the start of the sync window (required)endDate: ISO 8601 timestamp for the end of the sync window (required)
Response:
OK
This creates Unavailability records with reasonType: 'EXT' for each external event in the date range.
8. Delete Calendar Connection
Endpoint: DELETE /v3/resource/{id}/externalCalendar/{externalCalendarId}
Description: Disconnects an Outlook Calendar and revokes access. This also deletes all calendar entries created by OnSched in Outlook Calendar.
Response:
{
"success": true,
"data": {
"id": "789bfc52-8c92-4ba2-8047-de56f8783f00"
}
}Complete OAuth Flow
Here's the step-by-step flow for implementing Outlook Calendar sync in your application:
Step 1: Create Pending Connection
POST /v3/resource/{resourceId}/externalCalendar
Headers:
Authorization: Bearer {token}
X-Company-API-Key: {companyApiKey}
Body:
{
"provider": "outlook"
}Store the returned externalCalendarId and authUrl.
Step 2: Redirect User to Authorization URL
Open the authUrl in a browser or redirect the user. They'll see Microsoft's consent screen requesting:
- Sign in and read user profile
- Have full access to all calendars you can access
- Read and write calendars you have access to
Step 3: Handle OAuth Callback
After the user grants permissions, Microsoft redirects to:
GET /v3/calendar/callback?code={authorization_code}&state={"id":"{externalCalendarId}","provider":"outlook"}
OnSched automatically:
- Exchanges the code for refresh tokens
- Stores the refresh token, home account ID, and calendar email
- Marks the connection as non-pending with
read: trueandwrite: true - Redirects to your configured return URL
Note: Unlike Google Calendar, no calendar selection step is required. The connection is ready to use immediately after OAuth completion.
Step 4: Sync External Events (Optional)
If you want to manually trigger a sync instead of waiting for automatic background sync:
POST /v3/resource/{resourceId}/externalCalendar/createUnavailabilityBulk?startDate=2025-03-01T00:00:00Z&endDate=2025-03-31T23:59:59Z
Headers:
Authorization: Bearer {token}
X-Company-API-Key: {companyApiKey}How Syncing Works
Reading from Outlook Calendar
External calendar events are imported as Unavailability records with reasonType: 'EXT'. These blocks prevent availability during those times.
Event Filtering:
- Only events where
organizer.emailAddress.name !== 'ONSCHED'are imported - This prevents OnSched-created appointments from being re-imported as unavailability
- Events are converted using their
start.dateTimeandend.dateTimevalues from Microsoft Graph API - Events are fetched using the
/me/calendarviewendpoint
Automatic Sync:
- Background jobs periodically sync external events
- You can trigger manual syncs via the
createUnavailabilityBulkendpoint - Availability requests with
syncExternal=truetrigger an on-demand sync before calculating slots
Writing to Outlook Calendar
When appointments are created in OnSched, events are automatically created in the user's primary Outlook calendar.
Event Creation:
- Event subject: Service name
- Event location: Structured address object with location name, street, city, state, postal code, and country
- Event body: Service description
- Start/end times: Match the appointment's unavailability block with timezone information
- Organizer: Marked with
emailAddress.name: 'ONSCHED' - Extensions: Includes
com.onsched.unavailabilityIdextension with the Unavailability ID
Event Deletion:
- When appointments are deleted in OnSched, corresponding Outlook Calendar events are also deleted
- The
outlookCalendarEventIdstored on the appointment record is used for deletion
Calendar Selection Behavior
- Primary calendar only: Outlook sync only works with the user's primary calendar (their email address)
- Automatic configuration: Read and write permissions are automatically enabled after OAuth—no selection needed
- No multi-calendar support: Unlike Google Calendar, Outlook doesn't support syncing multiple calendars or selecting specific calendars
Availability Integration
External calendar events affect availability calculations when:
- Automatic background sync: External events are periodically synced and become unavailability blocks
- Manual sync: Calling
createUnavailabilityBulkimports events for a date range - On-demand sync: Setting
syncExternal=truein availability requests triggers an immediate sync before calculating slots
Availability Request Example:
GET /v3/availability?startDate=2025-03-21&endDate=2025-03-21&LocationId={locId}&ServiceId={svcId}&ResourceIds={resourceId}&syncExternal=trueThe syncExternal parameter adds latency but ensures the most up-to-date calendar state is considered.
Response Examples
Successful Connection
{
"success": true,
"data": {
"id": "789bfc52-8c92-4ba2-8047-de56f8783f00",
"ResourceId": "fd9a18bb-8e9f-45be-be3d-3aa1b6aa0644",
"provider": "outlook",
"calendarId": "homeAccountId-abc123",
"calendarEmail": "[email protected]",
"read": true,
"write": true,
"pending": false,
"createdAt": "2025-02-14T10:00:00Z",
"updatedAt": "2025-02-14T10:05:00Z"
}
}Usage Patterns
Basic Connection Flow
# 1. Create connection
curl -X POST "https://api.onsched.com/v3/resource/{resourceId}/externalCalendar" \
-H "Authorization: Bearer {token}" \
-H "X-Company-API-Key: {apiKey}" \
-H "Content-Type: application/json" \
-d '{"provider": "outlook"}'
# 2. User authorizes at authUrl (manual step)
# 3. Connection is ready after OAuth callback - no selection neededManual Sync Trigger
# Sync external events for the next 30 days
curl -X POST "https://api.onsched.com/v3/resource/{resourceId}/externalCalendar/createUnavailabilityBulk?startDate=2025-03-01T00:00:00Z&endDate=2025-03-31T23:59:59Z" \
-H "Authorization: Bearer {token}" \
-H "X-Company-API-Key: {apiKey}"Key Differences from Google Calendar
-
No calendar selection: Outlook only syncs with the primary calendar. The
listCalendarsandselectendpoints are not supported. -
Automatic permissions: Read and write permissions are automatically enabled after OAuth completion—no additional configuration needed.
-
Event identification: Outlook uses
organizer.emailAddress.nameto identify OnSched-created events, while Google usesextendedProperties.private.createdBy. -
Token management: Outlook uses Microsoft's MSAL library with Redis caching for token management, while Google uses direct OAuth2 refresh tokens.
-
API endpoints: Outlook uses Microsoft Graph API (
/me/calendarview,/me/events), while Google uses Google Calendar API. -
Account identifier: Outlook uses
homeAccountIdas the calendar identifier, while Google uses email addresses.
Troubleshooting
-
Authorization URL expired: Regenerate it using
PUT /v3/resource/{id}/externalCalendar/{externalCalendarId}/regenerateAuthUrl. Authorization URLs can expire if not used promptly. -
Refresh token expired: If the refresh token becomes invalid (user revoked access, account changes), regenerate the authorization URL and have the user reconnect.
-
Calendar selection not available: Outlook doesn't support calendar selection. Only the primary calendar is synced. If you need multi-calendar support, use Google Calendar instead.
-
Events not syncing: External events are filtered by the
organizer.emailAddress.name !== 'ONSCHED'check. Ensure events you want imported don't have this organizer name. Also verify the date range covers the events and the connection hasread: true. -
Appointments not creating calendar events: Verify the calendar connection has
write: true(should be automatic) and check that the resource is assigned to the appointment. Only resources with write-enabled calendars receive events. -
OAuth callback errors: The callback endpoint requires both
codeandstateparameters. Ensure thestateparameter contains valid JSON withidandproviderfields set to"outlook". -
Microsoft account issues: Users must have a valid Microsoft account (Microsoft 365, Outlook.com, or work/school account). Personal Microsoft accounts work, but organization admin policies may restrict access.
-
Token cache errors: OnSched uses Redis to cache Microsoft tokens. If you see token cache errors, check Redis connectivity and configuration.
With these practices, you can build robust Outlook Calendar integrations that keep OnSched and Outlook Calendar synchronized automatically.
Updated 1 day ago
