Google Calendar Webhook¶
Route & Auth¶
| Property | Value |
|---|---|
| Method | POST |
| Path | /webhooks/google/calendar |
| Auth type | secret |
| Header | X-Goog-Channel-Token |
| Secret | GOOGLE_WEBHOOK_TOKEN |
| Service account | google-webhook@alan-eu-tools.iam.gserviceaccount.com |
| Response | 204 No Content |
Payload¶
Google Calendar push notifications carry data in headers, not the body:
| Header | Description |
|---|---|
X-Goog-Channel-ID |
Watch channel identifier |
X-Goog-Resource-ID |
Calendar resource identifier |
X-Goog-Resource-State |
Event type: sync, exists, or not_exists |
X-Goog-Resource-URI |
Resource URI |
X-Goog-Message-Number |
Incrementing message number |
Behavior¶
Only exists events trigger processing. The endpoint enqueues _process_refused_events as a background job.
The job:
- Finds the
OncallGroupbycalendar_watch_channel_id - Fetches incremental calendar changes using the stored sync token
- Detects declined attendees on future shifts
- Marks declined shifts (
declined_on = today) - Attempts to find swap candidates via
find_shift_for_swap() - Swaps shifts and notifies via Slack
See the On-Call Groups > Shift declination and swap section for the full sequence diagram.
Integrations¶
- Google Calendar API: incremental sync, event reading
- Slack API: swap notifications
- On-call group DB: shift management
Code reference¶
apps.eu_tools.webhooks.google_calendar.GoogleCalendarHeadersSchema ¶
Bases: Schema
channel_expiraton
class-attribute
instance-attribute
¶
channel_id
class-attribute
instance-attribute
¶
channel_token
class-attribute
instance-attribute
¶
message_number
class-attribute
instance-attribute
¶
resource_id
class-attribute
instance-attribute
¶
resource_state
class-attribute
instance-attribute
¶
resource_state = String(
data_key="X-Goog-Resource-State",
required=True,
validate=OneOf(["sync", "exists", "not_exists"]),
)
resource_uri
class-attribute
instance-attribute
¶
apps.eu_tools.webhooks.google_calendar.GoogleCalendarWebhook ¶
Bases: MethodView
post ¶
Source code in apps/eu_tools/webhooks/google_calendar.py
apps.eu_tools.webhooks.google_calendar.google_blueprint
module-attribute
¶
google_blueprint = CustomBlueprint(
"google_webhook",
"google_webhook",
url_prefix="/webhooks/google",
auth_context_providers=[
WebhookAuthContextProvider(
auth_type=secret,
header_name="X-Goog-Channel-Token",
secret_name_config_key="GOOGLE_WEBHOOK_TOKEN",
auth_principal_type=ServiceAccount,
auth_principal_email="google-webhook@alan-eu-tools.iam.gserviceaccount.com",
)
],
)