Google Calendar Integration Help

Overview

This page manages two types of Google Calendar integration.

Feature Direction Purpose
Write integration UnlockOS → Google Calendar Automatically write UnlockOS native reservations to Google Calendar to manage availability in one place
Read calendars Google Calendar → UnlockOS Read calendars that Spacemarket, Instabase, Spacee, and similar platforms write to, and import their bookings into UnlockOS so keys and check-ins are issued automatically

Both features require a connected Google account. Complete the OAuth connection by clicking "Connect Google Calendar" before configuring read calendars.

Google Workspace verification status: Under review. Until verification completes, only Google accounts registered as test users on the Google OAuth consent screen can use this integration (limit: 100 accounts). Contact support if you would like to be added.


How to access

Connection Settings → External Integrations → click the Google Calendar card

The legacy URL /google-calendar-connection automatically redirects to the new URL /integrations/google-calendar.


Step 1: Connecting your Google account

Setting the target calendar ID (write destination)

Before clicking the connect button, decide which calendar UnlockOS should write reservation events to.

Value Description
primary The Google account's main calendar (default)
Dedicated calendar ID Use only when you want to write to a specific calendar

To find a dedicated calendar ID:

  1. Open Google Calendar on a computer
  2. In the left sidebar, click the three-dot menu ("⋮") next to the target calendar → Settings and sharing
  3. Under "Integrate calendar," copy the Calendar ID (for example: xxxxxxx@group.calendar.google.com)
  1. Enter the calendar ID (usually leave it as primary)
  2. Click "Connect Google Calendar"
  3. You are redirected to Google's OAuth consent screen
  4. Review the requested permissions and click "Continue"
  5. You are automatically returned to the UnlockOS settings page; status changes to "✓ Connected"

Requested permissions

Scope What it allows
https://www.googleapis.com/auth/calendar.events Create, update, and delete Google Calendar events (write destination for UnlockOS reservations)
https://www.googleapis.com/auth/calendar.calendarlist.readonly Read the list of calendars on your Google account (used to populate the calendar picker in the Read Calendars section)

Both scopes are requested in a single OAuth flow. The calendarlist.readonly scope is read-only and is never used to read event content — only to list calendar names and IDs for the dropdown.

Security design (CSRF protection)

When you click the Connect button, a one-time CSRF token is temporarily stored in the browser's sessionStorage. When Google redirects back, the token and facility ID are validated before the connection is finalized.

Private browsing mode disables sessionStorage, so the integration cannot be completed in a private window. Use a regular browser window.


Step 2: READ — importing bookings from other platforms

The Read Calendars section appears below the connection status once your Google account is connected. It lets you bind a Google Calendar (such as the one that Spacemarket or Instabase writes to) to a specific room. UnlockOS then reads that calendar's events and imports them as reservations, issuing keys and check-ins automatically.

Prerequisite: This section is only shown when a Google account is connected.

Adding a new binding

  1. Source calendar — Select the target calendar from the dropdown. All calendars on the connected Google account are listed.
    • If the dropdown is empty, see "The read calendar picker is empty or unavailable" in the Troubleshooting section below.
  2. Room to bind — Select the room that reservations from this calendar should be assigned to.
  3. Click "Add" (追加).

The new binding appears in the list below.

Automatic sync

Once a binding is created, UnlockOS syncs the linked calendar automatically approximately every 30 minutes. New events are imported as reservations.

Manual sync

Click the "Sync" (同期) button on a binding card to read the calendar immediately and import any new events. The last-synced timestamp and event count update after sync completes.

Removing a binding (解除)

Click the "Remove" (解除) button on a binding card and confirm in the dialog.

When a binding is removed:

  • Automatic syncing of that calendar stops immediately.
  • Reservations imported by this binding that have not yet been checked in are cancelled. Already checked-in reservations are unaffected.

Reading the binding list

Each binding is displayed as a card with the following information:

Field Description
Calendar ID The Google Calendar ID being read
Room The room that reservations are assigned to
Last synced Date and time of the most recent successful sync
Status badge Synced / Error / Pending

Step 3: WRITE — UnlockOS reservations in your Google Calendar

When your Google account is connected, UnlockOS native reservations are automatically written to your Google Calendar as blocking events titled [UnlockOS] Reserved. This prevents double-booking on other channels that reference the same calendar.

Note: When a reservation is created or changed in UnlockOS, an immediate sync is attempted — events typically appear in Google Calendar within seconds. If the immediate dispatch fails, a backstop background job (pg_cron, approximately every 5 minutes) retries automatically. Both mechanisms are best-effort; real-time delivery is not guaranteed.

Events written to Google Calendar

Reservation change Google Calendar action
Reservation confirmed or checked in Create event (or update if already exists)
Reservation modified (date, time, room) Update existing event
Cancelled, completed, or pre-empted Delete event

Event titles are written as [UnlockOS] Reserved. The event description includes the reservation confirmation code and a link to the admin panel.

Reservations not synced (write)

  • Reservations from iCal / OTA / PMS: Syncing external reservations back to Google Calendar would create a circular write loop, so they are excluded
  • Past-dated reservations: Reservations in the past are not synced
  • Draft or pending reservations: Only reservations in confirmed or checked_in state are synced

CRITICAL operating rule: 1 room = 1 calendar source

Do NOT connect the same calendar to a room via both an iCal feed AND a Google Calendar read binding.

If you register the same room's availability calendar via both iCal Sync AND as a Google Calendar read binding, UnlockOS will import the same reservations twice — once from each channel. This creates false double-booking conflicts and duplicate reservations in the system.

Rule: for each room, choose exactly one import channel:

Channel Use when
iCal Sync (?tab=ical) Your OTA provides an iCal (.ics) export URL
Google Calendar read binding (this page) Your OTA writes directly to Google Calendar (e.g. Spacemarket, Instabase)

If you are currently using both for the same room, remove one of them — either delete the iCal feed for that room, or remove the Google Calendar binding.


Page states

The page shows one of three states depending on the integration status.

1. Not connected

Shown for facilities that have not yet connected.

  • Target calendar ID input field (default: primary)
  • "Connect Google Calendar" button

2. Connected

Shown for facilities where OAuth is complete and the integration is active. A green-bordered section displays the following information:

Field Description
Google account Email address of the Google account used to authorize
Target calendar Calendar ID where reservation events are written
Connected at Date and time when OAuth was completed
Pending / Failed Count of pending (awaiting sync) and failed (retrying) reservations

This section also shows the "Disconnect" (連携を解除) button.

3. Reauthorization required

Shown when access has been revoked on the Google account side. A red banner at the top of the page displays the number of failed syncs and a "Reauthorize" (再認可する) button.

Common causes of the reauthorization banner:

  • Access to the app was manually revoked in Google Account settings
  • A Google Workspace administrator blocked third-party app access
  • Google Workspace verification has not completed and the test-user limit (100 accounts) was reached

Disconnecting

  1. Click "Disconnect" (連携を解除) in the Connected section
  2. Click "OK" in the confirmation dialog

Upon disconnect:

  • New reservation syncs stop immediately
  • All pending and failed syncs are disabled

All stored refresh tokens (authorization credentials) are permanently deleted from Vault within 30 days of disconnect.

Events already written to Google Calendar remain there. Delete them manually in Google Calendar if needed.


Troubleshooting

The "Reauthorization required" banner appears

Access was revoked on the Google account side.

Steps to resolve:

  1. Click "Reauthorize" (再認可する) to restart the OAuth flow
  2. If the issue persists, check Google Account settings → Security → "Third-party apps with account access" to review UnlockOS access
  3. If you use Google Workspace, ask your Workspace administrator to review third-party app policies

Events do not appear in Google Calendar (write integration)

Check the following in order:

  1. Is the status "✓ Connected"? — Complete the connection first if status shows "Reauthorization required" or "Not connected"
  2. Is it a native reservation? — Reservations from OTA, iCal, or PMS are not synced via the write integration
  3. Is the target calendar ID correct? — Verify it is primary or the correct dedicated calendar ID
  4. Have you waited a few seconds? — Events typically appear within seconds, but sync is best-effort. If the immediate dispatch failed, the backstop job retries within approximately 5 minutes
  5. Is the "Failed" count increasing? — Check the pending/failed counter in the Connected section; contact support if failures persist

Clicking the connect button does nothing

If the browser's sessionStorage is unavailable (for example, in private browsing mode), an error message is shown. Try again in a regular browser window.

A message appears confirming the connection was cancelled. Start again from the "Connect Google Calendar" button.

I want to reconnect with the same account

Click "Disconnect," then click "Connect Google Calendar" again. You can select the same Google account on the consent screen.

The read calendar picker is empty or unavailable

The picker is empty when the calendar.calendarlist.readonly scope was not granted during the original OAuth connection.

Steps to resolve:

  1. Click "Disconnect" (連携を解除) to remove the current connection
  2. Click "Connect Google Calendar" again to reconnect — the new OAuth flow grants both scopes
  3. After reconnecting, the calendar dropdown in the read calendars section will populate

While waiting to reconnect, you can manually enter a calendar ID in the text input to add a binding without the picker.

Syncing a read calendar binding does not import events

Check in this order:

  1. Is the calendar ID correct? — Compare the ID shown on the binding card against the space booking platform's calendar settings
  2. Are the events in the future? — Past-dated events are not imported
  3. Is the Google account status "Connected"? — If the reauthorization banner appears, reauthorize first
  4. Does the binding card show an error? — Read the error message and contact support if it persists

I need to cancel or edit an imported reservation

Reservations imported from a Google Calendar read binding have Google Calendar as their source of truth. To cancel or modify such a reservation, edit or delete the event in Google Calendar — do not attempt to cancel it directly from the UnlockOS admin panel. The next automatic read sync (approximately every 30 minutes) or a manual sync will reflect the change in UnlockOS.

I see duplicate reservations for the same booking

This is the most common symptom of connecting the same room's calendar via both iCal Sync and a Google Calendar read binding simultaneously. See the CRITICAL operating rule section above and remove one of the two conflicting import channels.


How the write integration works (technical reference)

Sync mechanism

State changes to reservations in UnlockOS are automatically detected by a database trigger, which marks each affected reservation as pending (awaiting sync). A second AFTER trigger immediately fires an asynchronous request (pg_net.http_post) to the gcal-event-sync Edge Function the moment a reservation enters pending status — the request is sent after the transaction commits.

Changes typically reflect in Google Calendar within seconds of the reservation being created, modified, or cancelled. If the immediate dispatch fails (for example due to missing Vault secrets or a transient network error), the pg_cron backstop job (every 5 minutes) picks up any remaining pending rows and retries. Both mechanisms are best-effort; real-time delivery is not guaranteed.

Retry and error handling

If a sync fails, the background job retries automatically up to 5 times. Reservations that fail all 5 attempts are recorded in the DLQ (dead-letter queue) view (gcal_event_sync_dlq) for operational review.

Secure credential storage

Google refresh tokens (long-lived credentials that authorize ongoing access) are never sent to the browser. They are stored in Supabase Vault (encrypted internal storage), keyed per facility.


FAQ

Q: What happens to events already written to Google Calendar after I disconnect?

A: They remain in Google Calendar. UnlockOS does not delete them on disconnect. Delete them manually in Google Calendar if needed.

Q: Can I import Google Calendar events into UnlockOS?

A: Yes, using the Read Calendars feature. Add a read calendar binding to associate a Google Calendar (for example one that Spacemarket or Instabase writes to) with a room, and UnlockOS will import those events as reservations. Note that the write integration itself is still one-directional: UnlockOS native reservations are pushed to Google Calendar, but Google Calendar is not polled for changes to those events.

Q: Can each facility use a different calendar?

A: Yes. Each facility has its own independent integration. Facility A can write to primary while Facility B writes to a dedicated calendar ID.

Q: Can I use multiple Google accounts?

A: One facility supports one Google account at a time. To switch accounts, disconnect and reconnect with the new account.

Q: Where is the refresh token (authorization credential) stored?

A: In Supabase Vault (encrypted internal storage). It is never sent to the browser. It is automatically deleted within 30 days after you disconnect.

Q: Who can authorize the integration?

A: Only Facility Owners, Organization Owners, and Platform Admins can perform the OAuth connection. Facility Members do not have access to this setting.

Q: What is the "test user" limit?

A: While UnlockOS's Google Workspace verification is still in progress, Google accounts must be pre-registered as test users before they can connect (limit: 100 accounts). This restriction will be lifted once verification is complete. Contact support to be added as a test user.

Q: Where do I find reservations that were imported from a read calendar binding?

A: They appear in the standard Booking Management Dashboard reservation list. The source is recorded as adapter:gcal, so you can distinguish them from reservations made through other channels.

Q: What happens to imported reservations when I remove a read calendar binding?

A: Reservations imported by that binding that have not yet been checked in are cancelled. Reservations that are already checked in are not affected.

Q: The read calendar picker is empty — how do I fix it?

A: The picker is empty when the calendar listing scope was not granted at connection time. Disconnect and reconnect your Google account (the new OAuth flow grants both scopes). Until then you can manually enter a calendar ID in the text field.

Q: Can I bind the same calendar to more than one room?

A: Yes, but each event will be imported as a separate reservation into each bound room. Unless that is the intended behavior, it is recommended to use a 1-to-1 binding. A warning appears on the binding card if the same calendar is bound to multiple rooms.

Q: Can I use both iCal Sync and a Google Calendar read binding for the same room?

A: No. Do not use both channels for the same room — they will import the same reservations twice and create false double-booking conflicts. Choose one import channel per room. See the CRITICAL operating rule section above.


Keys for synced reservations

  • Each synced event receives the key for the room it is assigned to (the room's own smart lock) — not a key from the check-in configuration's unit. In a multi-room property, every guest gets their own room's key.
  • The key is issued ahead of time and KEYVOX distributes it to the lock from about 72 hours before check-in.
  • Synced reservations are free at the kiosk; selecting a price plan on the assigned check-in configuration does not charge these guests.
  • If a calendar is bound to a room with no smart lock assigned, check-in is refused (no fallback key is issued) so the misconfiguration is visible.