curl --request POST \
--url https://api.example.com/calendar/webhook \
--header 'X-Goog-Channel-Id: <x-goog-channel-id>' \
--header 'X-Goog-Channel-Token: <x-goog-channel-token>' \
--header 'X-Goog-Resource-State: <x-goog-resource-state>'{
"Empty Object": {},
"sync": {},
"exists": {},
"not_exists": {}
}Receive real-time calendar change notifications from Google Calendar
curl --request POST \
--url https://api.example.com/calendar/webhook \
--header 'X-Goog-Channel-Id: <x-goog-channel-id>' \
--header 'X-Goog-Channel-Token: <x-goog-channel-token>' \
--header 'X-Goog-Resource-State: <x-goog-resource-state>'{
"Empty Object": {},
"sync": {},
"exists": {},
"not_exists": {}
}POST /calendar/webhook
sync - Initial verification message (ignored)exists - Resource has been created or updatednot_exists - Resource has been deletedX-Goog-Channel-Id header existsX-Goog-Channel-Token matches stored token (HMAC comparison)sync resource state (verification message){} on successcalendar_sync_state table and be associated with a valid calendar and user.
hmac.compare_digest(actual_token, expected_token)
POST /calendar/webhook HTTP/1.1
Host: api.chronoscalendar.com
X-Goog-Channel-Id: 550e8400-e29b-41d4-a716-446655440000
X-Goog-Channel-Token: a8f5f167f44f4964e6c998dee827110c
X-Goog-Resource-State: exists
X-Goog-Resource-Id: ret08u3rv24htgh004g
X-Goog-Channel-Expiration: Thu, 11 Mar 2026 19:00:00 GMT
Content-Length: 0
{}
X-Goog-Channel-Id header{"detail": "Missing channel ID"}
X-Goog-Channel-Token{"detail": "Invalid token"}
{} to avoid leaking information to Google)WEBHOOK_BASE_URL is configured.
handle_webhook_notification(calendar_id, user_id)
calendar_sync_state table which stores:
google_calendar_id - Calendar identifierwebhook_channel_id - Unique channel ID (UUID)webhook_resource_id - Google’s opaque resource IDwebhook_expires_at - Channel expiration timestampwebhook_channel_token - Secret verification tokenhttps://api.chronoscalendar.comIf not configured, webhook registration is skipped.backend/app/routers/calendar.py:226-253 (webhook endpoint)backend/app/calendar/sync.py:163-217 (webhook registration)backend/app/calendar/webhook.py (notification handler)backend/app/calendar/db.py:31-53 (webhook persistence)