Schedule-X Cloud SDK
TypeScript client and Schedule-X calendar preset for Schedule-X Cloud.
The SDK defaults to the hosted Schedule-X Cloud API at https://cloud.schedule-x.com and stays close to the HTTP API:
- Backend code maps authenticated app users and issues short-lived frontend sessions.
- Browser code supplies one async frontend-token function to a Cloud calendar factory.
- The Cloud calendar loads visible-range events and persists changes automatically.
- The calendar preset wires the loaded config into Schedule-X Calendar with default views, recurrence, and the interactive event modal.
Hosted frontend-token routes support direct cross-origin browser requests without cookies. Before starting Google authorization, register the application's OAuth return origin for the selected environment in the Cloud console.
Install
Server-only integrations can install the SDK and import its UI-free entry point:
npm install @schedule-x-cloud/sdk temporal-polyfill
import { ScheduleXServerClient } from '@schedule-x-cloud/sdk/server'
For the calendar integration, install the Schedule-X peer packages too. Configure
your @sx-premium registry token before running this command:
npm install @schedule-x-cloud/sdk temporal-polyfill @schedule-x/calendar @schedule-x/calendar-controls @schedule-x/event-recurrence @schedule-x/theme-default @schedule-x/translations @sx-premium/interactive-event-modal @sx-premium/sidebar
Auth Flow
Customer integrations use two token types:
- Organization API token: secret owned by one organization, used only on your server.
- Frontend token: short-lived bearer token for one organization user, used by the browser.
The normal implementer flow is:
- Your backend stores the organization API token as a server-side secret.
- Your backend creates or maps a Cloud user for your signed-in app user.
- Your backend exchanges the organization API token and Cloud user id for a frontend token.
- Your frontend uses the frontend token with
ScheduleXBrowserClient.
Never expose an organization API token to browser code.
Server-Side Session Bootstrap
import { ScheduleXServerClient } from '@schedule-x-cloud/sdk/server'
const serverClient = new ScheduleXServerClient({
apiKey: process.env.SCHEDULE_X_ORG_API_TOKEN,
organizationId: process.env.SCHEDULE_X_ORGANIZATION_ID,
})
export async function createScheduleXFrontendSession(appUser) {
return serverClient.auth.createFrontendSession({
externalUserId: appUser.id,
email: appUser.email,
displayName: appUser.name,
})
}
The operation idempotently creates or updates the organization-scoped external-user mapping and returns a fresh one-hour frontend token. Call it only from an authenticated backend route.
Cloud Calendar
import 'temporal-polyfill/global'
import '@schedule-x/theme-default/dist/index.css'
import '@sx-premium/interactive-event-modal/index.css'
import { createScheduleXCloudCalendar } from '@schedule-x-cloud/sdk'
const calendarApp = createScheduleXCloudCalendar({
getFrontendToken: async () => {
const response = await fetch('/api/schedule-x/token', { method: 'POST' })
return (await response.json()).token
},
})
The factory returns a normal CalendarApp synchronously. It shows a loading
overlay until the first visible range is available, retains loaded events during
later range refreshes, wires event CRUD, caches the token, and requests a fresh
token after a 401 before retrying once.
The app exposes its framework-neutral Cloud lifecycle at
calendarApp.scheduleXCloud. Subscribe when your application needs its own UI:
const unsubscribe = calendarApp.scheduleXCloud.subscribe((state) => {
console.log(state.phase, state.providerSync.pendingCalendarCount)
})
await calendarApp.scheduleXCloud.retry()
unsubscribe()
Phases are loading, partial, ready, refreshing, and error.
hasLoadedData distinguishes a blocking initial error from a non-blocking
refresh or provider error. Set loadingUI: false to keep the lifecycle without
the built-in UI, or pass loadingUI.render to render into the SDK-owned status
container. The renderer may return a cleanup function.
The hosted API URL is used automatically. Pass baseUrl only when targeting another deployment:
const serverClient = new ScheduleXServerClient({
apiKey: process.env.SCHEDULE_X_ORG_API_TOKEN,
baseUrl: 'https://calendar-api.example.com',
})
Browser Config
import 'temporal-polyfill/global'
import { ScheduleXBrowserClient } from '@schedule-x-cloud/sdk'
const client = new ScheduleXBrowserClient({
token: frontendToken.token,
})
const config = await client.scheduleX.getCalendarAppConfig({
from: Temporal.ZonedDateTime.from('2026-05-01T00:00:00+00:00[UTC]'),
to: Temporal.ZonedDateTime.from('2026-06-01T00:00:00+00:00[UTC]'),
})
Browser clients do not need an organization id for the default config and event endpoints. The API resolves the organization and user from the frontend token.
Public SDK date-time values use Temporal objects. Timed events use
Temporal.ZonedDateTime, all-day events use Temporal.PlainDate, and absolute
metadata timestamps use Temporal.Instant. The raw HTTP API uses ISO strings;
the SDK handles that transport conversion.
Google Calendar Sync
After a user connects Google Calendar through getConnectUrl, let the Cloud
calendar enable every visible provider calendar and own the initial import:
const calendarApp = createScheduleXCloudCalendar({
getFrontendToken,
initialProviderSync: true,
})
initialProviderSync is opt-in because it enables all visible provider calendars.
The initial config is displayed as partial data while imports run. If the normal
sync wait times out, the lifecycle remains partial and continues polling until
each calendar is synced or failed. One failed provider calendar is reported as a
non-blocking error and does not prevent the loaded calendars from rendering.
listProviderCalendars() returns calendars from all active Google account
connections for the frontend token user. Each item includes connectionId and
providerEmail if you need to show which Google account it came from. For
selective sync, keep using the lower-level APIs.
Calendar Preset
import 'temporal-polyfill/global'
import '@schedule-x/theme-default/dist/index.css'
import '@sx-premium/interactive-event-modal/index.css'
import { createCalendar } from '@schedule-x/calendar'
import {
ScheduleXBrowserClient,
loadScheduleXCloudCalendarPreset,
} from '@schedule-x-cloud/sdk'
const client = new ScheduleXBrowserClient({
token: frontendToken.token,
})
const preset = await loadScheduleXCloudCalendarPreset({
client,
configQuery: {
from: Temporal.ZonedDateTime.from('2026-05-01T00:00:00+00:00[UTC]'),
to: Temporal.ZonedDateTime.from('2026-06-01T00:00:00+00:00[UTC]'),
},
})
const calendarApp = createCalendar(preset.calendarOptions)
The preset creates the default day, week, month grid, and month agenda views. It also wires browser create, update, and delete calls for events. You can override calendar options, modal fields, plugins, persistence checks, and event mapping through createScheduleXCloudCalendarPreset or loadScheduleXCloudCalendarPreset.
Event Persistence
await client.events.create({
calendarId,
end: Temporal.ZonedDateTime.from(
'2026-05-14T11:00:00+02:00[Europe/Berlin]'
),
isPrivate: false,
start: Temporal.ZonedDateTime.from(
'2026-05-14T10:00:00+02:00[Europe/Berlin]'
),
title: 'New event',
})
await client.events.update(eventId, {
calendarId,
end: Temporal.ZonedDateTime.from(
'2026-05-14T12:00:00+02:00[Europe/Berlin]'
),
isPrivate: false,
start: Temporal.ZonedDateTime.from(
'2026-05-14T10:00:00+02:00[Europe/Berlin]'
),
title: 'Updated event',
})
await client.events.delete(eventId)
Both values in an event range must use the same Temporal type. Timed ranges
must also use the same timezone; the SDK derives timeZone and isAllDay for
the HTTP request.
Errors
Failed API responses throw ScheduleXApiError.
import { ScheduleXApiError } from '@schedule-x-cloud/sdk'
try {
await client.events.create(request)
} catch (error) {
if (error instanceof ScheduleXApiError) {
console.error(error.status, error.responseBody)
}
}
Package Status
The beta publish target is npm package @schedule-x-cloud/sdk, with public access and version 0.1.0-beta.0.