Skip to main content

Webhooks API

Use webhooks to receive near real-time event change notifications from connected calendar providers.

When a user modifies an event in Google, Microsoft, Apple, or CalDAV, Connect can forward the normalized change payload to your configured project webhook URL after you subscribe the calendar via POST /subscribe-webhook.

This API lets you:

  • Subscribe a calendar to provider notifications
  • Unsubscribe an existing webhook channel
  • Receive normalized webhook payloads at your application webhook URL

Supported providers​

  • Google Calendar (google)
  • Microsoft Outlook (microsoft)
  • Apple Calendar (apple)
  • CalDAV (caldav)

Subscribe webhook​

Creates a webhook subscription for a specific calendar.

Endpoint: POST /subscribe-webhook

Authentication​

Requires Bearer token authentication:

Authorization: Bearer YOUR_ACCESS_TOKEN

Request parameters​

providerstringRequired

Provider name. Supported values: google, microsoft, apple, caldav.

calendarIdstringRequired

Calendar ID to subscribe.

channelIdstring

Optional custom subscription channel ID.

Default: Auto-generated
expirationnumber

Optional Unix timestamp in milliseconds. Provider-specific subscription expiration.

Default: Provider default

Response​

successboolean

true when subscription is created.

providerstring

Provider associated with this subscription.

subscriptionWebhookSubscription

Provider subscription details.

channelIdstring

Unique webhook channel/subscription identifier.

resourceIdstring

Provider resource identifier when available.

expirationstring

ISO 8601 expiration timestamp when available.

webhookUrlstring

Provider callback URL used by the subscription.

serverWebhookUrlstring

Mobiscroll Connect callback endpoint registered with the provider.

channelIdstring

Channel ID used for the subscription.

Error responses​

  • 400 - Missing required parameters, unsupported provider, or project webhook URL not configured
  • 401 - Unauthorized (invalid or missing Bearer token)
  • 500 - Internal server error

Example​

Create subscription
curl -X POST "https://connect.mobiscroll.com/api/subscribe-webhook" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"provider": "google",
"calendarId": "work@company.com",
"channelId": "my-channel-123"
}'
Response
{
"success": true,
"provider": "google",
"subscription": {
"channelId": "my-channel-123",
"resourceId": "resource-abc",
"expiration": "2026-03-19T10:00:00.000Z",
"webhookUrl": "https://your-connect-server/api/webhook-receiver/google"
},
"serverWebhookUrl": "https://your-connect-server/api/webhook-receiver/google",
"channelId": "my-channel-123"
}

Unsubscribe webhook​

Removes an existing webhook subscription channel.

Endpoint: POST /unsubscribe-webhook

Authentication​

Requires Bearer token authentication.

Request parameters​

providerstringRequired

Provider name. Supported values: google, microsoft, apple, caldav.

channelIdstringRequired

Channel/subscription ID to remove.

resourceIdstring

Optional provider resource ID when applicable.

Default: undefined

Response​

successboolean

true when request is accepted and local mapping cleanup is completed.

messagestring

Additional status detail.

Error responses​

  • 400 - Missing parameters or unsupported provider
  • 401 - Unauthorized (invalid or missing Bearer token)
  • 500 - Internal server error

Example​

Unsubscribe channel
curl -X POST "https://connect.mobiscroll.com/api/unsubscribe-webhook" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"provider": "google",
"channelId": "my-channel-123",
"resourceId": "resource-abc"
}'
Response
{
"success": true,
"message": "Webhook unsubscribed successfully"
}

Client webhook payload​

When a provider notification is processed, Mobiscroll Connect forwards a normalized payload to your configured project webhook URL.

providerstring

Notification source provider.

userIdstring

User ID in your system.

calendarIdstring

Calendar ID where changes were detected.

eventsArray<WebhookEvent>

Changed events list.

calendarIdstring

Calendar ID where the event belongs.

idstring

Event ID.

providerstring

Event provider.

titlestring

Event title.

descriptionstring

Event description/notes (optional).

lastModifiedstring

ISO 8601 timestamp of the last provider-side modification (optional).

startDate

Event start date/time.

endDate

Event end date/time.

allDayboolean

Indicates all-day event.

recurringEventIdstring

Recurring series master ID when this event is an instance (optional).

changeTypestring

One of created, updated, deleted.

colorstring

Optional event color.

locationstring

Optional event location.

attendeesArray<EventAttendee>

Optional attendee list.

emailstring

Attendee email.

statusstring

Response status: accepted, declined, tentative, or none.

organizerboolean

Indicates if attendee is organizer. For Google, the organizer appears in this list only when Google lists them as a guest — see attendees in the events reference.

customobject

Optional custom key-value pairs.

conferenceobject

Optional conference metadata.

urlstring

Conference meeting URL.

autoGenerateboolean

If true, provider may auto-generate an online meeting link.

providerstring

Conference provider identifier.

dataobject

Provider-specific conference payload.

availabilitystring

Optional availability: busy or free.

privacystring

Optional privacy: public, private, or confidential.

statusstring

Optional event status: confirmed, tentative, or cancelled.

linkstring

Optional provider event link.

originalobject

Provider-native event object.

changeTypestring

Overall change summary: created, updated, deleted, or mixed.

timestampstring

ISO 8601 processing timestamp.

metadataobject

Additional webhook metadata.

channelIdstring

Subscription channel ID.

eventCountnumber

Number of events in this delivery.

isInitialSyncboolean

true only for a provider initial-sync delivery (when a channel is first established). Ordinary changes are always false, even large ones such as editing many occurrences of a recurring series.

Example delivery​

Delivered to your webhook URL
{
"provider": "google",
"userId": "user-123",
"calendarId": "work@company.com",
"events": [
{
"id": "event-abc",
"provider": "google",
"calendarId": "work@company.com",
"title": "Product review",
"description": "Quarterly review",
"lastModified": "2026-03-10T09:00:00.000Z",
"start": "2026-03-12T09:00:00.000Z",
"end": "2026-03-12T10:00:00.000Z",
"allDay": false,
"recurringEventId": "series-master-id",
"color": "#9fc6e7",
"location": "Office / Meeting room",
"attendees": [
{
"email": "user@example.com",
"status": "accepted",
"organizer": true
}
],
"custom": {
"yourCustomKey": "yourCustomValue"
},
"conference": {
"url": "https://meet.example.com/abc",
"provider": "google-meet"
},
"availability": "busy",
"privacy": "private",
"status": "confirmed",
"link": "https://provider-event-link",
"changeType": "updated",
"original": {}
}
],
"changeType": "updated",
"timestamp": "2026-03-12T09:01:12.000Z",
"metadata": {
"channelId": "sub-123",
"eventCount": 1,
"isInitialSync": false
}
}

Subscription lifecycle​

You do not manage provider subscriptions. Connect subscribes a user's calendars when they connect an account, and renews those subscriptions automatically before the provider's channel expires. Google push channels last about a week and Microsoft subscriptions slightly less, but neither lifetime is something your integration has to track.

POST /subscribe-webhook remains available for subscribing a specific calendar explicitly, and is safe to call repeatedly — it replaces any existing subscription for that calendar.

When a connection breaks​

Renewal cannot fix every failure. If the end user revokes your app in their Google account, an administrator withdraws consent, or the credentials otherwise stop working, no server-side action can restore the connection — providers only issue calendar credentials at consent time.

When that happens, Connect sends a connection event to your webhook URL:

Delivered when a connection needs attention
{
"type": "connection.reauth_required",
"provider": "google",
"account": "user@gmail.com",
"userId": "user-123",
"reason": "invalid_grant",
"calendarIds": ["work@company.com", "personal@gmail.com"],
"timestamp": "2026-09-03T09:14:02.000Z"
}
typestring

connection.reauth_required — the account's calendars have stopped syncing and the user must reconnect.

providerstring

Provider the affected account belongs to.

accountstring

The provider account, usually the user's email address.

userIdstring

User ID in your system.

reasonstring

Machine-readable cause, for example invalid_grant.

calendarIdsArray<string>

Calendars affected. Supporting detail — the subject of the event is the account, not any one calendar.

Branch on type before reading the payload

A connection event has no events array. Calendar change deliveries and connection events arrive at the same URL, so check type first.

To recover, send that user through GET /api/oauth/authorize again. Completing the flow restores the connection and re-subscribes every calendar on the account — there is no follow-up call to make. One event covers the whole account, so one reconnect resolves it.

You can also poll for the same state: every account in GET /api/oauth/connection-status carries syncState, which reads reauth_required for exactly these accounts. Use the event to react immediately and the endpoint to reconcile after your own downtime.


Setup requirements​

  1. Configure Webhook URL in your Connect application settings. See Application setup.
  2. Ensure your webhook endpoint is public, reachable, and returns 2xx quickly.
  3. Keep endpoint handling idempotent and tolerant of out-of-order notifications.

Operational notes​

  • Delivery forwarding to your webhook URL is best-effort and should be handled with idempotent processing on your side.
  • Connect waits for your response before acknowledging the provider, and gives up after 10 seconds. Return 2xx immediately and process asynchronously — a slow endpoint delays our acknowledgement to Google or Microsoft, which over time can cost the subscription.
  • Provider-side notifications may be emitted for changes regardless of where the change originated.
  • A single change can produce more than one provider notification — Microsoft may write the event several times for one user action, and providers deliver at least once — so expect the same event to arrive more than once.
  • Changes you make through the Connect API do not come back to you as deliveries. Every provider notification caused by your own POST /event, PUT /event or DELETE /event call is filtered for 30 seconds after the write (short-lived in-memory dedup window), including notifications that arrive before the API call returns.
  • In distributed or multi-instance setups, add an application-level origin marker in custom (for example custom.source = "my-system") and ignore matching webhook events as an additional loop-prevention safeguard.
  • For Apple, event change detection is based on periodic synchronization (polled every 5 minutes) rather than provider-native push.
  • For CalDAV, event change detection is based on periodic synchronization rather than provider-native push.
  • A single delivery may contain multiple event changes and return changeType: "mixed".
  • When notifications are filtered out, no events may be delivered in that callback cycle.