Offbeat-IoT · Small devices. Big APIs.
Integrations
Spotify Integration Google Health Integration Todoist Integration Google Calendar Integration Alexa Integration Google Home Integration
Built-in
Time Integration Ponder Integration Encouragement Integration API OTA updates
Using the Google Calendar integration

Using the Google Calendar integration

Send provider-neutral calendar commands from your device to a linked Google Calendar account. Every request carries a target naming the linked integration (for example Google Calendar); see the Target resolution section of the canonical protocol reference. The user picks which calendars are watched and queried; when no calendar is selected explicitly, all of the account’s calendars are queried and the primary calendar is used for created events.

Calendars

List calendars (calendar.calendars.list)

Returns the calendars the linked Google account can access, with the current selection state.

Request
{
  "jsonrpc" : "2.0",
  "id" : "cal-1",
  "method" : "calendar.calendars.list",
  "params" : {
    "target" : "Google Calendar"
  }
}
Example response
{
  "jsonrpc" : "2.0",
  "id" : "cal-1",
  "result" : {
    "calendars" : [ {
      "id" : "primary",
      "summary" : "Primary",
      "primary" : true,
      "accessRole" : "owner",
      "selected" : true
    }, {
      "id" : "work@example.com",
      "summary" : "Work",
      "primary" : false,
      "accessRole" : "writer",
      "selected" : false
    } ]
  }
}

Events

List events for one calendar (calendar.events.list)

Lists events for the given calendarId within the time window. Provide from and/or to as RFC-3339 timestamps to bound the window.

start/end are absolute RFC-3339 instants (unchanged). startLocal/endLocal render them in the resolved time zone using the requested format (a preset like iso/time/datetime or a raw pattern such as HH:mm). The zone is resolved from timezone, else country, else the device’s IP address, else UTC; the response echoes the resolved timezone.

Request
{
  "jsonrpc" : "2.0",
  "id" : "cal-2",
  "method" : "calendar.events.list",
  "params" : {
    "target" : "Google Calendar",
    "calendarId" : "primary",
    "timezone" : "Europe/Copenhagen",
    "format" : "HH:mm",
    "from" : "2026-09-08T00:00:00Z",
    "to" : "2026-09-09T00:00:00Z"
  }
}
Example response
{
  "jsonrpc" : "2.0",
  "id" : "cal-2",
  "result" : {
    "events" : [ {
      "id" : "gcal-1",
      "title" : "Daily standup",
      "description" : "Daily engineering sync",
      "start" : "2026-09-08T09:00:00Z",
      "end" : "2026-09-08T09:15:00Z",
      "allDay" : false,
      "startLocal" : "11:00",
      "endLocal" : "11:15"
    }, {
      "id" : "gcal-2",
      "title" : "Team sync",
      "description" : null,
      "start" : "2026-09-08T13:00:00Z",
      "end" : "2026-09-08T13:30:00Z",
      "allDay" : false,
      "startLocal" : "15:00",
      "endLocal" : "15:30"
    } ],
    "timezone" : "Europe/Copenhagen"
  }
}
List events for all calendars (calendar.events.list)

Omitting calendarId lists events across all of the user’s selected calendars (or, with no explicit selection, every readable calendar) in the window. Add a calendarId to this request to scope it to a single calendar.

Request
{
  "jsonrpc" : "2.0",
  "id" : "cal-3",
  "method" : "calendar.events.list",
  "params" : {
    "target" : "Google Calendar",
    "timezone" : "Europe/Copenhagen",
    "format" : "HH:mm",
    "from" : "2026-09-08T00:00:00Z",
    "to" : "2026-09-09T00:00:00Z"
  }
}
Example response
{
  "jsonrpc" : "2.0",
  "id" : "cal-3",
  "result" : {
    "events" : [ {
      "id" : "gcal-1",
      "title" : "Daily standup",
      "description" : "Daily engineering sync",
      "start" : "2026-09-08T09:00:00Z",
      "end" : "2026-09-08T09:15:00Z",
      "allDay" : false,
      "startLocal" : "11:00",
      "endLocal" : "11:15"
    }, {
      "id" : "gcal-2",
      "title" : "Team sync",
      "description" : null,
      "start" : "2026-09-08T13:00:00Z",
      "end" : "2026-09-08T13:30:00Z",
      "allDay" : false,
      "startLocal" : "15:00",
      "endLocal" : "15:30"
    } ],
    "timezone" : "Europe/Copenhagen"
  }
}
Create an event (calendar.event.create)

Creates an event on the primary or an explicitly selected calendar. title, start and end are required; start/end are RFC-3339 timestamps.

Request
{
  "jsonrpc" : "2.0",
  "id" : "cal-4",
  "method" : "calendar.event.create",
  "params" : {
    "target" : "Google Calendar",
    "calendarId" : "primary",
    "title" : "Team sync",
    "start" : "2026-09-09T10:00:00Z",
    "end" : "2026-09-09T10:30:00Z"
  }
}
Example response
{
  "jsonrpc" : "2.0",
  "id" : "cal-4",
  "result" : {
    "event" : {
      "id" : "gcal-3",
      "title" : "Team sync",
      "description" : null,
      "start" : "2026-09-09T10:00:00Z",
      "end" : "2026-09-09T10:30:00Z",
      "allDay" : false,
      "startLocal" : null,
      "endLocal" : null
    }
  }
}
Invalid event error

Returns INVALID_MESSAGE when calendar.event.create has no non-blank title or a missing/invalid start/end.

Example response
{
  "jsonrpc" : "2.0",
  "id" : "cal-5",
  "error" : {
    "code" : -32001,
    "message" : "Canonical request failed",
    "data" : {
      "reason" : "INVALID_MESSAGE",
      "retryable" : false,
      "retryAfterMs" : null
    }
  }
}

Notifications

Calendar changed (calendar.changed)

Sent by the backend when a watched calendar changes (events created, updated or deleted). It is a server-originated canonical event: the device does not request it. It carries no parameters - the device only needs to know that something changed and re-fetches with calendar.calendars.list / calendar.events.list.

Websocket notification
{
  "jsonrpc": "2.0",
  "method": "calendar.changed",
  "params": {}
}