Skip to content

TypeScript SDK

The SDK provides a one-call Cloud calendar path and low-level resource clients:

  • Backend code idempotently maps an app user and creates short-lived frontend sessions.
  • Browser code gives the calendar an async frontend-token function.
  • The Cloud calendar loads visible-range events and persists changes automatically.
  • Browser code can connect Google Calendar accounts and enable synced provider calendars.
  • The calendar preset wires loaded config into Schedule-X Calendar.

Frontend-token routes support direct browser requests from any origin without cookies. Google OAuth return URLs are separate: register the application’s origin for each environment in the Cloud console before starting authorization.

Server-only integrations can install the SDK and use its UI-free entry point:

Terminal window
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. Set up the Premium registry token shown in the Schedule-X Cloud console first:

Terminal window
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

Create one server client for backend-only work:

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,
})

The SDK defaults to https://cloud.schedule-x.com. You can pass baseUrl to target another deployment:

const serverClient = new ScheduleXServerClient({
apiKey: process.env.SCHEDULE_X_ORG_API_TOKEN,
baseUrl: 'https://calendar-api.example.com',
})

Map the authenticated app user and issue a frontend token in one idempotent call:

import { ScheduleXServerClient } from '@schedule-x-cloud/sdk/server'
export async function createScheduleXFrontendSession(appUser: AppUser) {
return serverClient.auth.createFrontendSession({
externalUserId: appUser.id,
email: appUser.email,
displayName: appUser.name,
})
}

The first call creates a Member; later calls update profile fields without changing the role and return a fresh one-hour token.

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 standard CalendarApp synchronously. Its shared Cloud data source loads the initial and subsequent visible ranges, caches the current token, refreshes it once after a 401, coalesces concurrent refreshes, and wires event CRUD. Use the same app with every Schedule-X framework adapter.

The high-level calendar includes a loading overlay by default. The initial overlay blocks an empty calendar, while range refreshes retain the existing events and use a compact status. Applications can observe the same lifecycle without reading rendered DOM:

const calendarApp = createScheduleXCloudCalendar({
getFrontendToken,
callbacks: {
onLoadStateChange(state) {
reportCalendarState(state.phase)
},
onInitialLoadComplete(state) {
console.log(state.hasLoadedData)
},
},
})
const unsubscribe = calendarApp.scheduleXCloud.subscribe((state) => {
// loading | partial | ready | refreshing | error
console.log(state.phase)
})

The snapshot also contains initialLoadComplete, hasLoadedData, activeRangeLoads, error, and provider synchronization details. Call calendarApp.scheduleXCloud.retry() after a load failure. onInitialLoadComplete fires once after the first range and optional provider import settle, including an error outcome; inspect the supplied state to distinguish success from failure.

Disable only the built-in UI while keeping this lifecycle:

createScheduleXCloudCalendar({ getFrontendToken, loadingUI: false })

Or render custom framework-neutral UI into the SDK-owned container:

createScheduleXCloudCalendar({
getFrontendToken,
loadingUI: {
render({ container, state }) {
container.textContent = state.phase === 'refreshing'
? 'Updating…'
: `Calendar: ${state.phase}`
return () => container.replaceChildren()
},
},
})

Existing applications that already render their own loading state should add loadingUI: false; all other factory options remain source-compatible. The lower-level preset APIs do not add an overlay because their config is already loaded before construction.

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.

const { url } = await client.integrations.googleCalendar.getConnectUrl({
returnUrl: window.location.href,
})
window.location.assign(url)

After Google redirects back, sync all provider calendars for the connected accounts. The SDK waits for the async import jobs to finish before returning fresh Schedule-X config:

const { config, syncStatus, timedOut } =
await client.integrations.googleCalendar.syncAllProviderCalendars()

For the rendered-calendar path, prefer one SDK-owned lifecycle:

const calendarApp = createScheduleXCloudCalendar({
getFrontendToken,
initialProviderSync: true,
})

This opt-in enables all visible provider calendars, displays available config as partial data, and continues polling if the initial wait times out. Provider errors remain visible in lifecycle state but do not block successfully loaded calendars.

For selective sync, use listConnections(), listProviderCalendars(connectionId), and enableCalendarSync(connectionId, providerCalendarId). See Google Calendar Sync for the full browser flow.

const event = await client.events.create({
calendarId: calendar.id,
title: 'Planning',
start: Temporal.ZonedDateTime.from(
'2026-06-10T09:00:00+02:00[Europe/Berlin]'
),
end: Temporal.ZonedDateTime.from(
'2026-06-10T10:00:00+02:00[Europe/Berlin]'
),
})
await client.events.update(event.id, {
calendarId: calendar.id,
title: 'Updated planning',
start: Temporal.ZonedDateTime.from(
'2026-06-10T09:30:00+02:00[Europe/Berlin]'
),
end: Temporal.ZonedDateTime.from(
'2026-06-10T10:30:00+02:00[Europe/Berlin]'
),
})
await client.events.delete(event.id)

Create and update requests require calendarId, start, and end. Both range values must use the same Temporal type, and timed ranges must use the same timezone. The SDK derives timeZone and isAllDay for the HTTP request.

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 customize persistence behavior:

const preset = await loadScheduleXCloudCalendarPreset({
client,
canPersistEvent: (event) => event.calendarId === 'work',
callbacks: {
onCreateError: (error) => console.error(error),
onUpdateError: (error) => console.error(error),
onDeleteError: (error) => console.error(error),
},
})

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)
}
}