Google Apps Platform

Google Calendar API v2 Developer's Guide: Protocol

This API is a subject to the Deprecation Policy and will be deprecated on November 17, 2014. Please use APIv3 instead.

Google Calendar allows client applications to view and update calendar events in the form of Google Data Protocol feeds. Your client application can use the Google Calendar Data API to create new events, edit or delete existing events, and query for events that match particular criteria.

There are many possible uses for the Calendar Data API. For example, you can create a web front end for your group's calendar that uses Google Calendar as a back end. Or you can generate a public calendar for Google Calendar to display, based on your organization's event database. Or you can search relevant calendars to display a list of upcoming events on those calendars.

In addition to providing some background on the capabilities of the Google Calendar Data API, this document provides examples of interacting with the API by sending HTTP messages containing data in Atom (XML) or JSON-C format. If you're using one of our client libraries to interact with the API, you may also be interested in exploring the examples in the developer's guide for that client library.

Contents

Audience

This document is intended for programmers who want to write client applications that can interact with Google Calendar. It provides a series of examples of basic Data API interactions using HTTP and Atom or JSON-C, with explanations. After reading this document, you may wish to learn more about interacting with the API using our client libraries by reading the language-specific examples found on the other tabs at the top of this document.

For Calendar Data API reference information, see the reference guide. This document assumes that you understand the general ideas behind the Google Data protocol. Each example in this document shows how to use the bare protocol to interact with Calendar.

Terms of use

You agree to abide by the Google Calendar Terms of Use when using the Calendar Data API.

Authenticating to the Calendar service

To request, add, or delete data, your client application needs an authentication token. You should use OAuth as your application's authentication method. You can use OAuth directly by sending raw HTTP requests, or you can have Google's client libraries handle the authentication for you. For more information about authentication systems, see Choosing an Auth Mechanism.

OAuth for web applications

OAuth is the preferred method for getting authorized access to a user's Google data. OAuth is an open standard for authorizing the use of data on the web. You can use OAuth for authorization with the Calendar service, other Google services, or with services from other companies that have adopted the standard.

Note: If you have used AuthSub previously, you should transition to OAuth. OAuth is similar to the secure and registered mode of AuthSub, in that all data requests must be digitally signed and you must register your domain.

To use OAuth, your application must obtain an access token by following this sequence of token requests:

  1. Get an unauthorized request token (OAuthGetRequestToken). Use the following scope parameter:
    https://www.google.com/calendar/feeds/
  2. Ask the user to authorize the request token (OAuthAuthorizeToken).
  3. Exchange the authorized request token for an access token (OAuthGetAccessToken).

For more information on this process, see OAuth Authentication for Web Applications documentation. Once you have an OAuth access token, your application can send requests by constructing an appropriate oauth_signature and Authorization header.

Example request

You can use the access token to request calendar data. This example requests a list of calendars owned by the user. You make this request by sending an HTTP GET to https://www.google.com/calendar/feeds/default/owncalendars/full. First, construct the signature base string:

GET&https://www.google.com/calendar/feeds/default/owncalendars/full&oauth_consumer_key=example.com&oauth_nonce=38863f48...28dd9fd2c&oauth_signature_method=RSA-SHA1&oauth_timestamp=1249972977&oauth_token=1%2Fz1...LMzNBrKhElA&oauth_version=1.0

Next, set the oauth_signature to the result of signing the base string with the algorithm you specify in oauth_signature_method. This requires URL-encoding the base string you just constructed, which results in the following:

GET&https%3a%2f%2fwww.google.com%2fcalendar%2ffeeds%2fdefault%2fowncalendars%2ffull&oauth_consumer_key%3Dexample.com%26oauth_nonce%3D38863f48...28dd9fd2c%26oauth_signature_method%3DRSA-SHA1%26oauth_timestamp%3D1249972977%26oauth_token%3D1%252Fz1...LMzNBrKhElA%26oauth_version%3D1.0

The complete example request looks like this:

GET /feeds/default/owncalendars/full HTTP/1.1
Host: www.google.com
Accept: */*
Authorization: OAuth oauth_version="1.0", oauth_nonce="38863f48...28dd9fd2c", oauth_timestamp="1249972977", oauth_consumer_key="example.com", oauth_token="1%2Fz1...LMzNBrKhElA", oauth_signature_method="RSA-SHA1", oauth_signature="kH%2BjQd%2Ba8...odMeUnsU%2FxANOw%3D"

Note: Depending on the method you use for sending the HTTP GET, you might have to URL-encode this request.

This example assumes example.com has already been registered with Google.

For more information on constructing the OAuth base string and Authorization header, see the reference links at the end of this authentication section.

OAuth for installed applications

OAuth is the preferred method for getting authorized access to a user's Google data. OAuth is an open standard for authorizing the use of data on the web. You can use OAuth for authorization with the Calendar service, other Google services, or with services from other companies that have adopted the standard.

Note: If you have used AuthSub previously, you should transition to OAuth. OAuth is similar to the secure and registered mode of AuthSub, in that all data requests must be digitally signed and you must register your domain.

To use OAuth, your application must obtain an access token by following this sequence of token requests:

  1. Get an unauthorized request token (OAuthGetRequestToken). Use the following scope parameter:
    https://www.google.com/calendar/feeds/
  2. Ask the user to authorize the request token (OAuthAuthorizeToken).
  3. Exchange the authorized request token for an access token (OAuthGetAccessToken).

For more information on this process, see OAuth Authentication for Web Applications documentation. Once you have an OAuth access token, your application can send requests by constructing an appropriate oauth_signature and Authorization header.

Example request

You can use the access token to request calendar data. This example requests a list of calendars owned by the user. You make this request by sending an HTTP GET to https://www.google.com/calendar/feeds/default/owncalendars/full. First, construct the signature base string:

GET&https://www.google.com/calendar/feeds/default/owncalendars/full&oauth_consumer_key=anonymous&oauth_nonce=38863f48...28dd9fd2c&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1249972977&oauth_token=1%2Fz1...LMzNBrKhElA&oauth_version=1.0

Note that when using OAuth with an installed application, you use anonymous as the value for &oauth_consumer_key.

Next, set the oauth_signature to the result of signing the base string with the algorithm you specify in oauth_signature_method. This requires URL-encoding the base string you just constructed, which results in the following:

GET&https%3a%2f%2fwww.google.com%2fcalendar%2ffeeds%2fdefault%2fowncalendars%2ffull&oauth_consumer_key%3Danonymous%26oauth_nonce%3D38863f48...28dd9fd2c%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1249972977%26oauth_token%3D1%252Fz1...LMzNBrKhElA%26oauth_version%3D1.0

The complete example request looks like this:

GET /feeds/default/owncalendars/full HTTP/1.1
Host: www.google.com
Accept: */*
Authorization: OAuth oauth_version="1.0", oauth_nonce="38863f48...28dd9fd2c", oauth_timestamp="1249972977", oauth_consumer_key="anonymous", oauth_token="1%2Fz1...LMzNBrKhElA", oauth_signature_method="HMAC-SHA1", oauth_signature="kH%2BjQd%2Ba8...odMeUnsU%2FxANOw%3D"

Note: Depending on the method you use for sending the HTTP GET, you might have to URL-encode this request.

For more information on constructing the OAuth base string and Authorization header, see the reference links at the end of this authentication section.

AuthSub for web applications

You should use OAuth for authentication in your web applications and installed applications. If you're developing a web application and you're unable to use OAuth, you can use AuthSub authentication until you're able to transition to OAuth. With AuthSub, your application acquires and uses a token for authorized access to the user's data.

To acquire an AuthSub token for a given Calendar user, your application must redirect users to the AuthSubRequest URL at Google, which prompts them to log into a Google account.

After the user logs in, the AuthSub system redirects them to the URL you specified in the next query parameter of the AuthSubRequest URL. The AuthSub system appends an authentication token to the next URL as the value of the token query parameter. Your application then uses that authentication token in subsequent interactions with the Calendar API.

The following example shows a request to authorize www.example.com:

https://www.google.com/accounts/AuthSubRequest?scope=https%3A%2F%2Fwww.google.com%2Fcalendar%2Ffeeds%2F&session=1&secure=0&next=http%3A%2F%2Fwww.example.com%2Fwelcome.html

For the Calendar API, use the following scope parameter:

https://www.google.com/calendar/feeds/

For a list of valid scopes for other Google Data APIs, see the FAQ.

Upgrading to a session token

By default, the AuthSub token can only be used for one request. To use a token for multiple requests, it must be upgraded by making an HTTP GET request containing the single use token as an Authorization header. A token can be upgraded only if the initial AuthSub request included session=1 as a URL parameter.

GET /accounts/AuthSubSessionToken HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Authorization: AuthSub token="yourSingleUseToken"
Host: https://www.google.com
Connection: keep-alive

If the token was upgraded successfully, the server's response contains the new token information in the HTTP headers. Here's an example response:

Token=DQAA...7DCTN

Use the authentication token to create an Authorization header for each request:

Authorization: AuthSub token="yourSessionToken"

Note that the token value in the Authorization header should be enclosed in quotation marks.

ClientLogin for installed applications

You should use OAuth for authentication in your web applications and installed applications. If you're developing an installed application and you're unable to use OAuth, you can use ClientLogin authentication until you're able to transition to OAuth. With ClientLogin, your application prompts the user for username and password on first run. After that, your application uses a token for authorized access to the user's data.

To authenticate the user, send a POST request to the following URL:

https://www.google.com/accounts/ClientLogin

Include the relevant parameters in the body of the POST request, as described in the ClientLogin documentation. The service name for Calendar is cl.

If the request succeeds, then the response contains an alphanumeric string labeled Auth.

After a successful authentication request, use the Auth value to create an Authorization header for each request:

Authorization: GoogleLogin auth=yourAuthValue

Magic cookie authentication

The simplest feed URL to use is that of the calendar's read-only, "magic cookie" private feed, because that URL doesn't require authentication. The usual procedure for determining that URL involves using a JavaScript-enabled GUI browser to get the URL manually. If you can't or don't want to use such a browser, then you can instead interact with Calendar using one of the other feed URLs, which require authentication, but which you can construct without using a browser.

To find your calendar's "magic cookie" feed URL:

  1. In the list of calendars on the left side of the page, find the calendar you want to interact with. You can create a new calendar for this purpose if you want to.
  2. Click the arrow button to the right of the calendar. Select "Calendar settings" from the drop-down menu. The Calendar Details page appears.
  3. Scroll down to the Private Address section and select the XML button. The feed URL appears.
  4. Copy the URL. This is the URL of your calendar's read-only "magic cookie" private feed; it includes a special coded string that lets you read the private feed without having to do authentication. This is the URL you'll use to request a feed from Calendar, so you won't have to do authentication just to view the feed.

The feed URL has the following form:

https://www.google.com/calendar/feeds/userID/private-magicCookie/basic

You can modify this URL in the following ways:

  • If you want a private feed that requires authentication, convert the "private-{magic-cookie}" part of this path to just "private".
  • If you want the "full" calendar project, change the last component from "basic" to "full".

The "basic" form of the feed holds event information that is formatted for reading, more suited to human consumption of the feed. The "full" form of the feed holds structured events that are represented as "Kinds", so they are more suited to computer processing.

If you're looking at settings for the user's main calendar, then userID is the user's email address. If you're looking at settings for another calendar, then userID is a longer and more complicated email address. In either case, magicCookie is a special code that lets you read the private feed without having to do authentication. Here's an example of a feed URL:

https://www.google.com/calendar/feeds/jo@gmail.com/private-08ce2fac8efa42f2a0d04eceb7d68cc9/full

Under some circumstances, you may want to generate a new "magic cookie" URL. (Note that if someone else gets access to that URL, they can view your calendar without authentication.) To do that, click the "Reset Private URLs" link in the Calendar Details page.

Need more information on authorization?

More details on working with the different authentication methods, including information on registering your web application with Google and other topics, see:

Specifying a version

Every request that you send using the Calendar Data API should specify version 2 of the API.

To specify a version number, use the GData-Version HTTP header:

GData-Version: 2

Alternatively, if you can't set HTTP headers, you can specify v=2 as a query parameter in the URL. But the HTTP header is preferred where possible.

Note: The client libraries supply appropriate version headers automatically, so don't use the v=2 query parameter when you're using a client library.

Retrieving settings (Experimental)

The Calendar Data API provides access to a read-only view of a user's current settings as set within the Google Calendar HTML interface. This can be retrieved by sending an authenticated GET request to the settings feed URL:

https://www.google.com/calendar/feeds/userId/settings

(To request JSON-C format, append the alt=jsonc query parameter.)

The result is a feed that includes all of the user's settings as key/value pairs:

Atom

<feed xmlns="http://www.w3.org/2005/Atom"
    xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/"
    xmlns:gCal="http://schemas.google.com/gCal/2005"
    xmlns:gd="http://schemas.google.com/g/2005"
    gd:etag="W/&quot;Ck8FQ3Y4cCp7I2A9WxVVEkU.&quot;">
  <id>http://www.google.com/calendar/feeds/default/settings</id>
  <updated>2009-03-05T10:46:25.244Z</updated>
  <title type="text">Coach's's personal settings</title>
  <link rel="alternate" type="text/html" href="https://www.google.com/calendar/feeds/render"/>
  <link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="https://www.google.com/calendar/feeds/default/settings"/>
  <link rel="self" type="application/atom+xml" href="https://www.google.com/calendar/feeds/default/settings"/>
  <author>
    <name>Coach</name>
    <email>user@gmail.com</email>
  </author>
  <generator version="1.0" uri="http://www.google.com/calendar">Google Calendar</generator>
  <openSearch:startIndex>1</openSearch:startIndex>
  <entry>
    <id>http://www.google.com/calendar/feeds/default/settings/alternateCalendar</id>
    <updated>2009-03-05T10:46:25.245Z</updated>
    <link rel="self" type="application/atom+xml" href="https://www.google.com/calendar/feeds/default/settings/alternateCalendar"/>
    <gCal:settingsProperty name="alternateCalendar" value="0"/>
  </entry>
  <entry>
    <id>http://www.google.com/calendar/feeds/default/settings/country</id>
    <updated>2009-03-05T10:46:25.245Z</updated>
    <link rel="self" type="application/atom+xml" href="https://www.google.com/calendar/feeds/default/settings/country"/>
    <gCal:settingsProperty name="country" value="EH"/>
  </entry>
  <entry>
    <id>http://www.google.com/calendar/feeds/default/settings/customCalMode</id>
    <updated>2009-03-05T10:46:25.245Z</updated>
    <link rel="self" type="application/atom+xml" href="https://www.google.com/calendar/feeds/default/settings/customCalMode"/>
    <gCal:settingsProperty name="customCalMode" value="custom,14"/>
  </entry>
  <entry>
    <id>http://www.google.com/calendar/feeds/default/settings/dateFieldOrder</id>
    <updated>2009-03-05T10:46:25.245Z</updated>
    <link rel="self" type="application/atom+xml" href="https://www.google.com/calendar/feeds/default/settings/dateFieldOrder"/>
    <gCal:settingsProperty name="dateFieldOrder" value="MDY"/>
  </entry>
  <entry>
    <id>http://www.google.com/calendar/feeds/default/settings/defaultCalMode</id>
    <updated>2009-03-05T10:46:25.245Z</updated>
    <link rel="self" type="application/atom+xml" href="https://www.google.com/calendar/feeds/default/settings/defaultCalMode"/>
    <gCal:settingsProperty name="defaultCalMode" value="custom"/>
  </entry>
  <entry>
    <id>http://www.google.com/calendar/feeds/default/settings/displayAllTimezones</id>
    <updated>2009-03-05T10:46:25.245Z</updated>
    <link rel="self" type="application/atom+xml" href="https://www.google.com/calendar/feeds/default/settings/displayAllTimezones"/>
    <gCal:settingsProperty name="displayAllTimezones" value="false"/>
  </entry>
  <entry>
    <id>http://www.google.com/calendar/feeds/default/settings/format24HourTime</id>
    <updated>2009-03-05T10:46:25.245Z</updated>
    <link rel="self" type="application/atom+xml" href="https://www.google.com/calendar/feeds/default/settings/format24HourTime"/>
    <gCal:settingsProperty name="format24HourTime" value="false"/>
  </entry>
  <entry>
    <id>http://www.google.com/calendar/feeds/default/settings/hideInvitations</id>
    <updated>2009-03-05T10:46:25.245Z</updated>
    <link rel="self" type="application/atom+xml" href="https://www.google.com/calendar/feeds/default/settings/hideInvitations"/>
    <gCal:settingsProperty name="hideInvitations" value="false"/>
  </entry>
  <entry>
    <id>http://www.google.com/calendar/feeds/default/settings/hideWeekends</id>
    <updated>2009-03-05T10:46:25.245Z</updated>
    <link rel="self" type="application/atom+xml" href="https://www.google.com/calendar/feeds/default/settings/hideWeekends"/>
    <gCal:settingsProperty name="hideWeekends" value="false"/>
  </entry>
  <entry>
    <id>http://www.google.com/calendar/feeds/default/settings/locale</id>
    <updated>2009-03-05T10:46:25.245Z</updated>
    <link rel="self" type="application/atom+xml" href="https://www.google.com/calendar/feeds/default/settings/locale"/>
    <gCal:settingsProperty name="locale" value="en"/>
  </entry>
  <entry>
    <id>http://www.google.com/calendar/feeds/default/settings/showDeclinedEvents</id>
    <updated>2009-03-05T10:46:25.245Z</updated>
    <link rel="self" type="application/atom+xml" href="https://www.google.com/calendar/feeds/default/settings/showDeclinedEvents"/>
    <gCal:settingsProperty name="showDeclinedEvents" value="true"/>
  </entry>
  <entry>
    <id>http://www.google.com/calendar/feeds/default/settings/timezone</id>
    <updated>2009-03-05T10:46:25.245Z</updated>
    <link rel="self" type="application/atom+xml" href="https://www.google.com/calendar/feeds/default/settings/timezone"/>
    <gCal:settingsProperty name="timezone" value="America/Los_Angeles"/>
  </entry>
  <entry>
    <id>http://www.google.com/calendar/feeds/default/settings/timezoneLabel</id>
    <updated>2009-03-05T10:46:25.245Z</updated>
    <link rel="self" type="application/atom+xml" href="https://www.google.com/calendar/feeds/default/settings/timezoneLabel"/>
    <gCal:settingsProperty name="timezoneLabel" value=""/>
  </entry>
  <entry>
    <id>http://www.google.com/calendar/feeds/default/settings/userLocation</id>
    <updated>2009-03-05T10:46:25.245Z</updated>
    <link rel="self" type="application/atom+xml" href="https://www.google.com/calendar/feeds/default/settings/userLocation"/>
    <gCal:settingsProperty name="userLocation" value="94043"/>
  </entry>
  <entry>
    <id>http://www.google.com/calendar/feeds/default/settings/weather</id>
    <updated>2009-03-05T10:46:25.245Z</updated>
    <link rel="self" type="application/atom+xml" href="https://www.google.com/calendar/feeds/default/settings/weather"/>
    <gCal:settingsProperty name="weather" value=""/>
  </entry>
  <entry>
    <id>http://www.google.com/calendar/feeds/default/settings/weekStart</id>
    <updated>2009-03-05T10:46:25.245Z</updated>
    <link rel="self" type="application/atom+xml" href="https://www.google.com/calendar/feeds/default/settings/weekStart"/>
    <gCal:settingsProperty name="weekStart" value="0"/>
  </entry>
</feed>

JSON-C

{
  "apiVersion": "2.3",
  "data": {
    "kind": "calendar#settingFeed",
    "id": "http://www.google.com/calendar/feeds/default/settings",
    "author": {
      "displayName": "Coach",
      "email": "user@gmail.com"
    },
    "selfLink": "https://www.google.com/calendar/feeds/default/settings?alt\u003djsonc",
    "items": [
      {
        "kind": "calendar#settings",
        "id": "alternateCalendar",
        "selfLink": "https://www.google.com/calendar/feeds/default/settings/alternateCalendar",
        "value": "0"
      },
      {
        "kind": "calendar#settings",
        "id": "country",
        "selfLink": "https://www.google.com/calendar/feeds/default/settings/country",
        "value": "CH"
      },
      {
        "kind": "calendar#settings",
        "id": "customCalMode",
        "selfLink": "https://www.google.com/calendar/feeds/default/settings/customCalMode",
        "value": "custom,4"
      },
      {
        "kind": "calendar#settings",
        "id": "dateFieldOrder",
        "selfLink": "https://www.google.com/calendar/feeds/default/settings/dateFieldOrder",
        "value": "MDY"
      },
      {
        "kind": "calendar#settings",
        "id": "defaultCalMode",
        "selfLink": "https://www.google.com/calendar/feeds/default/settings/defaultCalMode",
        "value": "week"
      },
      {
        "kind": "calendar#settings",
        "id": "displayAllTimezones",
        "selfLink": "https://www.google.com/calendar/feeds/default/settings/displayAllTimezones",
        "value": "false"
      },
      {
        "kind": "calendar#settings",
        "id": "format24HourTime",
        "selfLink": "https://www.google.com/calendar/feeds/default/settings/format24HourTime",
        "value": "false"
      },
      {
        "kind": "calendar#settings",
        "id": "hideInvitations",
        "selfLink": "https://www.google.com/calendar/feeds/default/settings/hideInvitations",
        "value": "false"
      },
      {
        "kind": "calendar#settings",
        "id": "hideWeekends",
        "selfLink": "https://www.google.com/calendar/feeds/default/settings/hideWeekends",
        "value": "false"
      },
      {
        "kind": "calendar#settings",
        "id": "locale",
        "selfLink": "https://www.google.com/calendar/feeds/default/settings/locale",
        "value": "en"
      },
      {
        "kind": "calendar#settings",
        "id": "showDeclinedEvents",
        "selfLink": "https://www.google.com/calendar/feeds/default/settings/showDeclinedEvents",
        "value": "true"
      },
      {
        "kind": "calendar#settings",
        "id": "timezone",
        "selfLink": "https://www.google.com/calendar/feeds/default/settings/timezone",
        "value": "Europe/Zurich"
      },
      {
        "kind": "calendar#settings",
        "id": "timezoneLabel",
        "selfLink": "https://www.google.com/calendar/feeds/default/settings/timezoneLabel",
        "value": ""
      },
      {
        "kind": "calendar#settings",
        "id": "userLocation",
        "selfLink": "https://www.google.com/calendar/feeds/default/settings/userLocation",
        "value": ""
      },
      {
        "kind": "calendar#settings",
        "id": "weather",
        "selfLink": "https://www.google.com/calendar/feeds/default/settings/weather",
        "value": ""
      },
      {
        "kind": "calendar#settings",
        "id": "weekStart",
        "selfLink": "https://www.google.com/calendar/feeds/default/settings/weekStart",
        "value": "0"
      }
    ]
  }
}

A list of settings and their values can be found in the reference guide under gCal:settingsProperty.

Retrieving calendar lists

The Calendar Data API provides several ways to access the list of calendars that appear in the Google Calendar web application. There are three types of calendars in this list: primary, secondary, and imported calendars. A primary calendar is created for a user when they sign up for a Google Calendar account. All other calendars created by that user are called secondary calendars. Imported calendars are calendars that a user subscribes to that someone else has created.

Retrieving all calendars

You can get a list of a user's calendars by sending an authenticated GET request to the allcalendars feed URL:

https://www.google.com/calendar/feeds/default/allcalendars/full

(To request JSON-C format, append the alt=jsonc query parameter.)

The result is a feed that includes all primary, secondary, and imported calendars:

Atom

<?xml version='1.0' encoding='utf-8'?>
<feed xmlns='http://www.w3.org/2005/Atom'
    xmlns:openSearch='http://a9.com/-/spec/opensearch/1.1/'
    xmlns:gCal='http://schemas.google.com/gCal/2005'
    xmlns:gd='http://schemas.google.com/g/2005'
    gd:etag='W/"CkYFSHg-fyp7ImA9WxRVGUo."'>
  <id>http://www.google.com/calendar/feeds/default/allcalendars/full</id>
  <updated>2008-11-18T01:01:59.657Z</updated>
  <title>Coach's Calendar List</title>
  <link rel='alternate' type='text/html'
    href='https://www.google.com/calendar/render' />
  <link rel='http://schemas.google.com/g/2005#feed'
    type='application/atom+xml'
    href='https://www.google.com/calendar/feeds/default/allcalendars/full' />
  <link rel='http://schemas.google.com/g/2005#post'
    type='application/atom+xml'
    href='https://www.google.com/calendar/feeds/default/allcalendars/full' />
  <link rel='self' type='application/atom+xml'
    href='https://www.google.com/calendar/feeds/default/allcalendars/full' />
  <author>
    <name>Coach</name>
    <email>user@gmail.com</email>
  </author>
  <generator version='1.0' uri='http://www.google.com/calendar'>Google Calendar</generator>
  <openSearch:startIndex>1</openSearch:startIndex>
  <entry gd:etag='W/"DU4ERH47eCp7ImA9WxRVEkQ."'>
    <id>http://www.google.com/calendar/feeds/default/allcalendars/full/user%40gmail.com</id>
    <published>2007-07-11T22:10:30.257Z</published>
    <updated>2007-07-11T21:46:35.000Z</updated>
    <title>My Primary Calendar</title>
    <summary type='text'>A primary calendar is created by default for each Google Calendar user.</summary>
    <link rel='alternate' type='application/atom+xml' href='https://www.google.com/calendar/feeds/user%40gmail.com/private/full' />
    <link rel='http://schemas.google.com/gCal/2005#eventFeed' type='application/atom+xml' href='https://www.google.com/calendar/feeds/user%40gmail.com/private/full' />
    <link rel='http://schemas.google.com/acl/2007#accessControlList' type='application/atom+xml' href='https://www.google.com/calendar/feeds/user%40gmail.com/acl/full' />
    <link rel='self' type='application/atom+xml' href='https://www.google.com/calendar/feeds/default/allcalendars/full/user%40gmail.com' />
    <link rel='edit' type='application/atom+xml' href='https://www.google.com/calendar/feeds/default/allcalendars/full/user%40gmail.com' />
    <author>
      <name>Coach</name>
      <email>user@gmail.com</email>
    </author>
    <gCal:timezone value='America/Los_Angeles' />
    <gCal:hidden value='false' />
    <gCal:color value='#2952A3' />
    <gCal:selected value='true' />
    <gCal:accesslevel value='owner' />
    <gd:where valueString='Mountain View' />
  </entry>
  <entry gd:etag='W/"Ck4GRH4-eSp7ImA9WxRVGUo."'>
    <id>http://www.google.com/calendar/feeds/default/allcalendars/full/rf1c66uld6dgk2t5lh43svev6g%40group.calendar.google.com</id>
    <published>2007-07-11T22:10:30.258Z</published>
    <updated>2007-07-11T21:50:15.000Z</updated>
    <title>Little Giants</title>
    <summary type='text'>This calendar contains practice times and this season's Little League game schedule. Go Little Giants!</summary>
    <link rel='alternate' type='application/atom+xml' href='https://www.google.com/calendar/feeds/rf1c66uld6dgk2t5lh43svev6g%40group.calendar.google.com/private/full'/>
    <link rel='http://schemas.google.com/gCal/2005#eventFeed' type='application/atom+xml' href='https://www.google.com/calendar/feeds/rf1c66uld6dgk2t5lh43svev6g%40group.calendar.google.com/private/full'/>
    <link rel='http://schemas.google.com/acl/2007#accessControlList' type='application/atom+xml' href='https://www.google.com/calendar/feeds/rf1c66uld6dgk2t5lh43svev6g%40group.calendar.google.com/acl/full'/>
    <link rel='self' type='application/atom+xml' href='https://www.google.com/calendar/feeds/default/allcalendars/full/rf1c66uld6dgk2t5lh43svev6g%40group.calendar.google.com'/>
    <link rel='edit' type='application/atom+xml' href='https://www.google.com/calendar/feeds/default/allcalendars/full/rf1c66uld6dgk2t5lh43svev6g%40group.calendar.google.com'/>
    <author>
      <name>Little Giants</name>
    </author>
    <gCal:timezone value='America/Los_Angeles' />
    <gCal:hidden value='false' />
    <gCal:color value='#5A6986' />
    <gCal:selected value='false' />
    <gCal:accesslevel value='owner' />
    <gd:where valueString='San Francisco' />
  </entry>
  <entry gd:etag='W/"C0cEQnkyeip7ImA9WxRVGUo."'>
    <id>http://www.google.com/calendar/feeds/default/allcalendars/full/c4o4i7m2lbamc4k26sc2vokh5g%40group.calendar.google.com</id>
    <published>2007-07-11T22:10:30.297Z</published>
    <updated>2007-06-05T09:38:50.000Z</updated>
    <title>Google Doodles</title>
    <summary type='text'/>
    <link rel='alternate' type='application/atom+xml' href='https://www.google.com/calendar/feeds/c4o4i7m2lbamc4k26sc2vokh5g%40group.calendar.google.com/private/full'/>
    <link rel='http://schemas.google.com/gCal/2005#eventFeed' type='application/atom+xml' href='https://www.google.com/calendar/feeds/c4o4i7m2lbamc4k26sc2vokh5g%40group.calendar.google.com/private/full'/>
    <link rel='self' type='application/atom+xml' href='https://www.google.com/calendar/feeds/default/allcalendars/full/c4o4i7m2lbamc4k26sc2vokh5g%40group.calendar.google.com'/>
    <link rel='edit' type='application/atom+xml' href='https://www.google.com/calendar/feeds/default/allcalendars/full/c4o4i7m2lbamc4k26sc2vokh5g%40group.calendar.google.com'/>
    <author>
      <name>Google Doodles</name>
    </author>
    <gCal:timezone value='Etc/GMT' />
    <gCal:hidden value='false' />
    <gCal:color value='#5229A3' />
    <gCal:selected value='false' />
    <gCal:accesslevel value='read' />
    <gd:where valueString='' />
  </entry>
</feed>

JSON-C

{
  "apiVersion": "2.3",
  "data": {
    "kind": "calendar#calendarFeed",
    "etag": "W/\"AkQBSH8-fSp7IWA9WxBaGEs.\"",
    "id": "http://www.google.com/calendar/feeds/default/allcalendars/full",
    "updated": "2010-03-29T13:12:39.155Z",
    "author": {
      "displayName": "Coach",
      "email": "user@gmail.com"
    },
    "feedLink": "https://www.google.com/calendar/feeds/default/allcalendars/full",
    "selfLink": "https://www.google.com/calendar/feeds/default/allcalendars/full?alt\u003djsonc",
    "canPost": true,
    "items": [
      {
        "kind": "calendar#calendar",
        "etag": "W/\"Ck4FQX47eCp7IWA9WxBaFEk.\"",
        "id": "http://www.google.com/calendar/feeds/default/calendars/full/user%40google.com",
        "created": "2010-03-29T13:12:38.877Z",
        "updated": "2010-03-24T14:28:30.000Z",
        "title": "My Primary Calendar",
        "eventFeedLink": "https://www.google.com/calendar/feeds/user%40gmail.com/private/full",
        "accessControlListLink": "https://www.google.com/calendar/feeds/user%40gmail.com/acl/full",
        "selfLink": "https://www.google.com/calendar/feeds/default/allcalendars/full/user%40gmail.com",
        "canEdit": true,
        "author": {
         "displayName": "Coach",
         "email": "user@gmail.com"
        },
        "accessLevel": "owner",
        "color": "#A32929",
        "hidden": false,
        "selected": true,
        "timeZone": "America/Los_Angeles",
        "location": "Moutani View",
        "timesCleaned": 0
      },
      {
        "kind": "calendar#calendar",
        "etag": "W/\"CUMCQX47eCp7IWA9WxBaGEk.\"",
        "id": "http://www.google.com/calendar/feeds/default/calendars/p%23moonphase%40group.v.calendar.google.com",
        "created": "2010-03-29T13:12:38.861Z",
        "updated": "2010-03-29T06:17:40.000Z",
        "title": "Phases of the Moon",
        "details": "Shows the primary phases of the Moon",
        "eventFeedLink": "https://www.google.com/calendar/feeds/p%23moonphase%40group.v.calendar.google.com/private/full",
        "selfLink": "https://www.google.com/calendar/feeds/default/allcalendars/full/p%23moonphase%40group.v.calendar.google.com",
        "canEdit": true,
        "author": {
         "displayName": "Phases of the Moon"
        },
        "accessLevel": "read",
        "color": "#AB8B00",
        "hidden": false,
        "selected": false,
        "timeZone": "Europe/Zurich",
        "timesCleaned": 0
      }
    ]
  }
}

For information about accessLevel, color, hidden, selected, and timeZone, see GCal namespace element reference.

Note: This feed is accessible only using an authentication token, so you cannot use a magic cookie URL to access the feed. For information on authentication, see the earlier Authenticating to the Calendar service section.

Retrieving only calendars that a user owns

There is also an owncalendars feed that you can query to retrieve the list of calendars that the authenticated user has owner access to. The owncalendars feed is located at:

https://www.google.com/calendar/feeds/default/owncalendars/full

(To request JSON-C format, append the alt=jsonc query parameter.)

Querying this feed will return a list of calendars that includes the user's primary and secondary calendars, as well as any imported calendars for which the user has been granted ownership. The feed will resemble the feed in the previous example, but it will contain only calendars where the <gCal:accesslevel> (or the accessLevel, in JSON-C) has a value of owner.

Managing Calendars

The owncalendars feed can also be used to create, update, and delete calendars. Calendars created through the owncalendars feed will be secondary calendars.

Creating new calendars

To create a new calendar, first create the Atom or JSON-C code for a calendar <entry> element or data object like the ones in the previous example. For example, you might create the following code to represent a calendar to keep track of your Little League team:

Atom

<entry xmlns='http://www.w3.org/2005/Atom'
       xmlns:gd='http://schemas.google.com/g/2005'
       xmlns:gCal='http://schemas.google.com/gCal/2005'>
  <title type='text'>Little League Schedule</title>
  <summary type='text'>This calendar contains the practice schedule and game times.</summary>
  <gCal:timezone value='America/Los_Angeles'></gCal:timezone>
  <gCal:hidden value='false'></gCal:hidden>
  <gCal:color value='#2952A3'></gCal:color>
  <gd:where rel='' label='' valueString='Oakland'></gd:where>
</entry>

JSON-C

{
  "data": {
    "title": "Little League Schedule",
    "details": "This calendar contains the practice schedule and game times.",
    "timeZone": "America/Los_Angeles",
    "hidden": false,
    "color": "#2952A3",
    "location": "Oakland"
  }
}

To insert this calendar, send an HTTP POST message with the above code in the message body, using the application/atom+xml or application/json content type (as appropriate), to the owncalendars feed URL:

POST https://www.google.com/calendar/feeds/default/owncalendars/full

Upon success, the server will respond with an HTTP 201 Created message that contains the calendar data you submitted, but with some additional elements and properties (shown in bold) that are set by the server, such as id, updated, and multiple link elements and properties:

Atom

<entry xmlns='http://www.w3.org/2005/Atom'
       xmlns:gCal='http://schemas.google.com/gCal/2005'
       xmlns:gd='http://schemas.google.com/g/2005'
       gd:etag='W/"C0UARno6fSp7ImA9WxRVGUo."'>
  <id>http://www.google.com/calendar/feeds/default/owncalendars/full/ppgcfga9qo8jmdwan231w7s8h4%40group.calendar.google.com</id>
  <published>2007-07-12T16:46:11.815Z</published>
  <updated>2007-07-12T16:46:11.000Z</updated>
  <title type='text'>Little League Schedule</title>
  <summary type='text'>This calendar contains the practice schedule and game times.</summary>
  <link rel='alternate' type='application/atom+xml' href='https://www.google.com/calendar/feeds/calendarID/private/full'/>
  <link rel='http://schemas.google.com/gCal/2005#eventFeed' type='application/atom+xml' href='https://www.google.com/calendar/feeds/calendarID/private/full'/>
  <link rel='http://schemas.google.com/acl/2007#accessControlList' type='application/atom+xml' href='https://www.google.com/calendar/feeds/calendarID/acl/full'/>
  <link rel='self' type='application/atom+xml' href='https://www.google.com/calendar/feeds/default/owncalendars/full/calendarID'/>
  <link rel='edit' type='application/atom+xml' href='https://www.google.com/calendar/feeds/default/owncalendars/full/calendarID'/>
  <author>
    <name>Little League Schedule</name>
  </author>
  <gCal:timezone value='America/Los_Angeles'/>
  <gCal:hidden value='false'/>
  <gCal:color value='#2952A3'/>
  <gCal:selected value='false'/>
  <gCal:accesslevel value='owner'/>
  <gd:where valueString='Oakland'/>
</entry>

JSON-C

{
  "apiVersion": "2.3",
  "data": {
    "kind": "calendar#calendar",
    "etag": "W/\"D0cGQn47eCp7IWA9WxBaGEo.\"",
    "id": "http://www.google.com/calendar/feeds/default/calendars/calendarID",
    "created": "2010-03-29T15:03:55.789Z",
    "updated": "2010-03-29T15:03:43.000Z",
    "title": "Little League Schedule",
    "details": "This calendar contains the practice schedule and game times.",
    "eventFeedLink": "https://www.google.com/calendar/feeds/calendarID/private/full",
    "accessControlListLink": "https://www.google.com/calendar/feeds/calendarID/acl/full",
    "selfLink": "https://www.google.com/calendar/feeds/default/owncalendars/full/calendarID",
    "canEdit": true,
    "author": {
      "displayName": "Little League Schedule"
    },
    "accessLevel": "owner",
    "color": "#2952A3",
    "hidden": false,
    "location": "Oakland",
    "selected": false,
    "timeZone": "America/Los_Angeles",
    "timesCleaned": 0
  }
}

Note: If making multiple creations/updates/deletions at the same time, please consider using Batch Request as it increases performance.

Updating existing calendars

You can update most information about a user's calendar via the owncalendars feed. You can determine the edit URL by examining the calendar entry's <link rel='edit'> element or (in JSON-C) the selfLink URL:

Atom

<link rel='edit' type='application/atom+xml' href='https://www.google.com/calendar/feeds/default/owncalendars/full/calendarID'></link>

JSON-C

"selfLink": "https://www.google.com/calendar/feeds/default/owncalendars/full/calendarID",
"canEdit": true,

In JSON-C, the canEdit field in the feed describes whether you have enough access rights to modify this calendar entry.

To update the calendar, send an HTTP PUT, using the appropriate content type, to the edit URL with the updated calendar <entry> element or data object in the message body.

The following example updates the calendar's title and color, and marks it as selected:

PUT https://www.google.com/calendar/feeds/default/owncalendars/full/calendarID

Atom

<entry xmlns='http://www.w3.org/2005/Atom'
       xmlns:gCal='http://schemas.google.com/gCal/2005'
       xmlns:gd='http://schemas.google.com/g/2005'>
  <id>http://www.google.com/calendar/feeds/default/owncalendars/full/ppgcfga9qo8jmdwan231w7s8h4%40group.calendar.google.com</id>
  <published>2007-07-12T16:46:11.815Z</published>
  <updated>2007-07-12T16:46:11.000Z</updated>
  <title type='text'>New Title</title>
  <summary type='text'>This calendar contains the practice schedule and game times.</summary>
  <link rel='alternate' type='application/atom+xml' href='https://www.google.com/calendar/feeds/calendarID/private/full'/>
  <link rel='http://schemas.google.com/gCal/2005#eventFeed' type='application/atom+xml' href='https://www.google.com/calendar/feeds/calendarID/private/full'/>
  <link rel='http://schemas.google.com/acl/2007#accessControlList' type='application/atom+xml' href='https://www.google.com/calendar/feeds/calendarID/acl/full'/>
  <link rel='self' type='application/atom+xml' href='https://www.google.com/calendar/feeds/default/owncalendars/full/calendarID'/>
  <link rel='edit' type='application/atom+xml' href='https://www.google.com/calendar/feeds/default/owncalendars/full/calendarID'/>
  <author>
    <name>Little League Schedule</name>
  </author>
  <gCal:timezone value='America/Los_Angeles'/>
  <gCal:hidden value='false'/>
  <gCal:color value='#0D7813'/>
  <gCal:selected value='true'/>
  <gCal:accesslevel value='owner'/>
  <gd:where valueString='Oakland'/>
</entry>

JSON-C

{
  "apiVersion": "2.3",
  "data": {
    "kind": "calendar#calendar",
    "etag": "W/\"D0cGQn47eCp7IWA9WxBaGEo.\"",
    "id": "http://www.google.com/calendar/feeds/default/calendars/calendarID",
    "created": "2010-03-29T15:03:55.789Z",
    "updated": "2010-03-29T15:03:43.000Z",
    "title": "New Title",
    "details": "This calendar contains the practice schedule and game times.",
    "eventFeedLink": "https://www.google.com/calendar/feeds/calendarID/private/full",
    "accessControlListLink": "https://www.google.com/calendar/feeds/calendarID/acl/full",
    "selfLink": "https://www.google.com/calendar/feeds/default/owncalendars/full/calendarID",
    "canEdit": true,
    "author": {
      "displayName": "Little League Schedule"
    },
    "accessLevel": "owner",
    "color": "#0D7813",
    "hidden": false,
    "location": "Oakland",
    "selected": true,
    "timeZone": "America/Los_Angeles",
    "timesCleaned": 0
  }
}

Note: If making multiple creations/updates/deletions at the same time, please consider using Batch Request as it increases performance.

Deleting calendars

Calendars are deleted by sending a DELETE request to the calendar's edit URL. This is the same URL used to update the calendar. For example, to delete the above calendar send the following HTTP request:

DELETE /calendar/feeds/default/owncalendars/full/calendarID

Note: You can't delete a user's primary calendar, i.e. the calendar with the user's email address in the ID. If you try to delete a primary calendar you will get an HTTP 400 Bad Request error.

Note: If making multiple creations/updates/deletions at the same time, please consider using Batch Request as it increases performance.

Managing subscriptions to calendars

The allcalendars feed can be used to modify the list of imported calendars that a user has subscribed to. Calendars inserted via the allcalendars feed will be added as imported calendars.

Adding new subscriptions

To subscribe to an existing calendar, you first need to find the calendar's ID. The calendar ID is available on the calendar settings page, next to the Calendar Address buttons. If you're subscribing to a user's primary calendar, the id will just be the user's email address.

Once you have the calendar ID, create a calendar <entry> element or data object that contains the ID of the calendar you wish to subscribe to. For example, to subscribe to the Week Numbers calendar, you could start with the following code:

Atom

<entry xmlns='http://www.w3.org/2005/Atom'>
  <id>e_2_en%23weeknum%40group.v.calendar.google.com</id>
</entry>

JSON-C

{
  "data": {
    "id": "e_2_en%23weeknum%40group.v.calendar.google.com"
  }
}

To then subscribe to the Week Numbers calendar, send an HTTP POST message to the allcalendars feed URL with the above calendar entry in the message body (using the application/atom+xml or application/json content type, as appropriate):

POST https://www.google.com/calendar/feeds/default/allcalendars/full

Upon success, the server responds with an HTTP 201 Created message that contains the calendar entry that corresponds to the calendar you subscribed to. This calendar entry is populated with data specific to the Week Numbers calendar such as the title and details, as well as elements and properties that are specific to this subscription, such as color, hidden, and selected. Here's an example of the Atom and JSON-C returned by the server, with personalization settings shown in bold:

Atom

<entry xmlns='http://www.w3.org/2005/Atom'
    xmlns:app='http://www.w3.org/2007/app'
    xmlns:gCal='http://schemas.google.com/gCal/2005'
    xmlns:gd='http://schemas.google.com/g/2005'
    gd:etag='W/"Ak4HRX47eCp7IWA9Wx5REU0."'
    gd:kind='calendar#calendar'>
  <id>http://www.google.com/calendar/feeds/default/calendars/e_2_en%23weeknum%40group.v.calendar.google.com</id>
  <published>2010-08-18T13:54:09.534Z</published>
  <updated>2010-08-18T05:22:14.000Z</updated>
  <app:edited>2010-08-18T05:22:14.000Z</app:edited>
  <category scheme='http://schemas.google.com/g/2005#kind'
    term='http://schemas.google.com/gCal/2005#calendarmeta'/>
  <title>Week Numbers</title>
  <summary>Week numbers displayed weekly</summary>
  <content type='application/atom+xml;type=feed'
    src='https://www.google.com/calendar/feeds/e_2_en%23weeknum%40group.v.calendar.google.com/private/full'/>
  <link rel='alternate' type='application/atom+xml'
    href='https://www.google.com/calendar/feeds/e_2_en%23weeknum%40group.v.calendar.google.com/private/full'/>
  <link rel='http://schemas.google.com/gCal/2005#eventFeed'
    type='application/atom+xml'
    href='https://www.google.com/calendar/feeds/e_2_en%23weeknum%40group.v.calendar.google.com/private/full'/>
  <link rel='self' type='application/atom+xml'
    href='https://www.google.com/calendar/feeds/default/allcalendars/full/e_2_en%23weeknum%40group.v.calendar.google.com'/>
  <link rel='edit' type='application/atom+xml'
    href='https://www.google.com/calendar/feeds/default/allcalendars/full/e_2_en%23weeknum%40group.v.calendar.google.com'/>
  <author>
    <name>Week Numbers</name>
  </author>
  <gCal:accesslevel value='read'/>
  <gCal:color value='#2952A3'/>
  <gCal:hidden value='false'/>
  <gCal:selected value='false'/>
  <gCal:timezone value='Europe/Zurich'/>
  <gCal:timesCleaned value='0'/>
</entry>

JSON-C

{
  "apiVersion": "2.3",
  "data": {
    "kind": "calendar#calendar",
    "etag": "W/\"Ak4MRn47eCp7IWA9WxFTEEw.\"",
    "id": "http://www.google.com/calendar/feeds/default/calendars/e_2_en%23weeknum%40group.v.calendar.google.com",
    "created": "2010-03-31T12:03:30.041Z",
    "updated": "2010-03-31T07:03:07.000Z",
    "title": "Week Numbers",
    "details": "Week numbers displayed weekly",
    "eventFeedLink": "https://www.google.com/calendar/feeds/e_2_en%23weeknum%40group.v.calendar.google.com/private/full",
    "selfLink": "https://www.google.com/calendar/feeds/default/allcalendars/full/e_2_en%23weeknum%40group.v.calendar.google.com",
    "canEdit": true,
    "author": {
      "displayName": "Week Numbers"
    },
    "accessLevel": "read",
    "color": "#2952A3",
    "hidden": false,
    "selected": false,
    "timeZone": "Europe/Zurich",
    "timesCleaned": 0
  }
}

Updating calendar subscriptions

You can update the following personalization settings of a calendar using the allcalendars feed:

color
The color of the calendar in the UI.
hidden
Indicates whether or not the calendar is shown in the UI.
selected
Indicates whether or not the calendar is selected in the UI.

The personalization settings can be modified with the allcalendars feed even if the user doesn't own the calendar. However, the title and summary of the calendar can only be updated by an owner of the calendar using the owncalendars feed.

To update a subscription, you'll need to use the calendar entry's edit URL. You can determine the edit URL by examining the calendar entry's <link rel='edit'> element or (in JSON-C) the selfLink URL:

Atom

<link rel='edit' type='application/atom+xml' href='https://www.google.com/calendar/feeds/default/allcalendars/full/calendarID'></link>

JSON-C

"selfLink": "https://www.google.com/calendar/feeds/default/allcalendars/full/e_2_en%23weeknum%40group.v.calendar.google.com",

Send an HTTP PUT to the edit URL with the updated calendar entry in the message body (using the appropriate content type). The following entry will update the color and select the calendar:

PUT https://www.google.com/calendar/feeds/default/allcalendars/full/e_2_en%23weeknum%40group.v.calendar.google.com

Atom

<entry xmlns='http://www.w3.org/2005/Atom'
       xmlns:gCal='http://schemas.google.com/gCal/2005'
       xmlns:gd='http://schemas.google.com/g/2005'>
  <id>http://www.google.com/calendar/feeds/default/allcalendars/full/c4o4i7m2lbamc4k26sc2vokh5g%40group.calendar.google.com</id>
  <published>2007-07-12T17:09:08.033Z</published>
  <updated>2007-06-05T09:38:50.000Z</updated>
  <title type='text'>Google Doodles</title>
  <summary type='text'></summary>
  <link rel='alternate' type='application/atom+xml' href='https://www.google.com/calendar/feeds/c4o4i7m2lbamc4k26sc2vokh5g%40group.calendar.google.com/private/full'/>
  <link rel='http://schemas.google.com/gCal/2005#eventFeed' type='application/atom+xml' href='https://www.google.com/calendar/feeds/c4o4i7m2lbamc4k26sc2vokh5g%40group.calendar.google.com/private/full'/>
  <link rel='self' type='application/atom+xml' href='https://www.google.com/calendar/feeds/default/allcalendars/full/c4o4i7m2lbamc4k26sc2vokh5g%40group.calendar.google.com'/>
  <link rel='edit' type='application/atom+xml' href='https://www.google.com/calendar/feeds/default/allcalendars/full/c4o4i7m2lbamc4k26sc2vokh5g%40group.calendar.google.com'/>
  <author>
    <name>Google Doodles</name>
  </author>
  <gCal:timezone value='Etc/GMT'/>
  <gCal:hidden value='false'/>
  <gCal:color value='#A32929'/>
  <gCal:selected value='false'/>
  <gCal:accesslevel value='read'/>
  <gd:where valueString=''/>
</entry>

JSON-C

{
  "apiVersion": "2.3",
  "data": {
    "kind": "calendar#calendar",
    "etag": "W/\"Ak4MRn47eCp7IWA9WxFTEEw.\"",
    "id": "http://www.google.com/calendar/feeds/default/calendars/e_2_en%23weeknum%40group.v.calendar.google.com",
    "created": "2010-03-31T12:03:30.041Z",
    "updated": "2010-03-31T07:03:07.000Z",
    "title": "Week Numbers",
    "details": "Week numbers displayed weekly",
    "eventFeedLink": "https://www.google.com/calendar/feeds/e_2_en%23weeknum%40group.v.calendar.google.com/private/full",
    "selfLink": "https://www.google.com/calendar/feeds/default/allcalendars/full/e_2_en%23weeknum%40group.v.calendar.google.com",
    "canEdit": true,
    "author": {
      "displayName": "Week Numbers"
    },
    "accessLevel": "read",
    "color": "#A32929",
    "hidden": false,
    "selected": true,
    "timeZone": "Europe/Zurich",
    "timesCleaned": 0
  }
}

Deleting subscriptions

Subscriptions are deleted by sending a DELETE request to the calendar's edit URL. This is the same URL used to update the subscription. For example, to delete the subscription to the Week Number calendar, send the following HTTP request:

DELETE /calendar/feeds/default/allcalendars/full/e_2_en%23weeknum%40group.v.calendar.google.com

Retrieving events

Retrieving events without query parameters

The general idea of how to request a Calendar feed is that you determine the URL of the feed type you want (see Calendar feed types), and then you send an HTTP GET request for that URL. Calendar then returns a Data API feed containing calendar events, each of which is an Event kind. For more information about kinds, see the Kinds document.

Google provides client libraries for interacting with many Google APIs in a variety of programming languages. You can use the client libraries to send the HTTP request and handle the returned feed; see the other tabs of this document for information on how to do this in various languages. But whether or not you use the client library, the following is what's going on at the protocol level. If you're using a UNIX system and you want to try this out without writing any code, you may find the UNIX command-line utilities curl or wget useful; for more information, see the manual pages for those utilities.

To get a feed, you send the following HTTP request to Calendar, using the URL you found in the previous section of this document:

GET https://www.google.com/calendar/feeds/userID/private-magicCookie/full

(With the appropriate values in place of userID and magicCookie, of course.)

(To request JSON-C format, append the alt=jsonc query parameter.)

When you send that GET request, Calendar may return an HTTP 302 redirect; the redirect URL has a new query parameter, gsessionid, appended to it. (Note that some methods of sending the GET request may not show you the response headers by default; if you receive a blank response, check your HTTP utility's documentation to find out how to view response headers.) That gsessionid parameter is the way that Calendar keeps track of your session, to improve speed of response.

(Some methods of sending the GET request may automatically follow redirects, and in some cases Calendar may not send a redirect at all; in such cases, you don't need to send the second request described below.)

So after you've sent the GET request, you have to read the HTTP headers of the response to find the URL with the session ID appended; then you need to send another GET request with that new URL. (Note that if you're using the UNIX command line to send requests, you may have to precede the question mark in the new URL with a backslash to keep your shell from interpreting it.)

In response to the second GET request, Calendar returns an HTTP 200 OK status code and a feed containing all the events in your calendar. If there's only one event in your calendar, then Calendar returns something similar to the following feed. We've edited the following example a little to make it a little more readable by humans; in particular, a real Calendar feed contains actual magic-cookie values and entry IDs.

Atom

<feed xmlns='http://www.w3.org/2005/Atom'
    xmlns:gd='http://schemas.google.com/g/2005'
    gd:etag='W/"DU4ERH47eCp7ImA9WxRVEkQ."'>
  <id>http://www.google.com/calendar/feeds/jo@gmail.com/private-magicCookie/full</id>
  <updated>2006-03-29T07:35:59.000Z</updated>
  <title type='text'>Jo March</title>
  <subtitle type='text'>This is my main calendar.</subtitle>
  <link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml'
    href='https://www.google.com/calendar/feeds/jo@gmail.com/private-magicCookie/full'></link>
  <link rel='self' type='application/atom+xml'
    href='https://www.google.com/calendar/feeds/jo@gmail.com/private-magicCookie/full'></link>
  <author>
    <name>Jo March</name>
    <email>jo@gmail.com</email>
  </author>
  <generator version='1.0' uri='http://www.google.com/calendar/'>CL2</generator>
  <gd:where valueString='California'></gd:where>
  <entry gd:etag='"EE4NTgBGfCp7ImA6WhVV"'>
    <id>http://www.google.com/calendar/feeds/jo@gmail.com/private-magicCookie/full/entryID</id>
    <published>2006-03-30T22:00:00.000Z</published>
    <updated>2006-03-28T05:47:31.000Z</updated>
    <category scheme='http://schemas.google.com/g/2005#kind'
      term='http://schemas.google.com/g/2005#event'></category>
    <title type='text'>Lunch with Darcy</title>
    <content type='text'>Lunch to discuss future plans.</content>
    <link rel='alternate' type='text/html'
      href='https://www.google.com/calendar/event?eid=aTJxcnNqbW9tcTJnaTE5cnMybmEwaW04bXMgbWFyY2guam9AZ21haWwuY29t'
      title='alternate'></link>
    <link rel='self' type='application/atom+xml'
      href='https://www.google.com/calendar/feeds/jo@gmail.com/private-magicCookie/full/entryID'></link>
    <link rel='edit' type='application/atom+xml'
      href='https://www.google.com/calendar/feeds/jo@gmail.com/private-magicCookie/full/entryID'></link>
    <author>
      <name>Jo March</name>
      <email>jo@gmail.com</email>
    </author>
    <gd:transparency
      value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency>
    <gd:eventStatus
      value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus>
    <gd:comments>
      <gd:feedLink
        href='https://www.google.com/calendar/feeds/jo@gmail.com/private-magicCookie/full/entryID/comments/'></gd:feedLink>
    </gd:comments>
    <gd:when startTime='2006-03-30T22:00:00.000Z'
      endTime='2006-03-30T23:00:00.000Z'></gd:when>
    <gd:where></gd:where>
  </entry>
</feed>

JSON-C

{
  "apiVersion": "2.3",
  "data": {
    "kind": "calendar#eventFeed",
    "id": "http://www.google.com/calendar/feeds/default/private/full",
    "author": {
      "displayName": "Jo March",
      "email": "jo@gmail.com"
    },
    "title": "Jo March",
    "details": "This is my main calendar.",
    "updated": "2010-03-31T12:41:32.000Z",
    "totalResults": 3,
    "startIndex": 1,
    "itemsPerPage": 25,
    "feedLink": "https://www.google.com/calendar/feeds/default/private/full",
    "selfLink": "https://www.google.com/calendar/feeds/default/private/full?alt\u003djsonc&max-results\u003d25",
    "canPost": true,
    "timeZone": "Europe/Zurich",
    "timesCleaned": 0,
    "items": [
      {
        "kind": "calendar#event",
        "etag": "\"FUoIRQBIfCp7IWA6WhJT\"",
        "id": "52f4theojvb86bg16ek0muvnag",
        "selfLink": "https://www.google.com/calendar/feeds/default/private/full/52f4theojvb86bg16ek0muvnag",
        "alternateLink": "https://www.google.com/calendar/event?eid\u003dNTJmNHRoZW9qdmI4NmJnMTZlazBtdXZuYWcgcmF2ZW1hbitjYWxlbmRhcjVAZ29vZ2xlLmNvbQ",
        "canEdit": true,
        "title": "Lunch with Darcy",
        "created": "0001-12-31T00:00:00.000Z",
        "updated": "2010-03-31T12:41:32.000Z",
        "details": "Lunch to discuss future plans.",
        "status": "confirmed",
        "creator": {
          "displayName": "Jo March",
          "email": "jo@gmail.com"
        },
        "anyoneCanAddSelf": false,
        "guestsCanInviteOthers": true,
        "guestsCanModify": false,
        "guestsCanSeeGuests": true,
        "sequence": 0,
        "transparency": "opaque",
        "visibility": "default",
        "location": "California",
        "attendees": [
          {
            "rel": "organizer",
            "displayName": "Jo March",
            "email": "jo@gmail.com"
          }
        ],
        "when": [
          {
            "start": "2010-04-01T10:00:00.000+02:00",
            "end": "2010-04-01T11:00:00.000+02:00"
          }
        ]
      }
  }
}

For information about what each of those elements and properties means, see the Google Data Protocol Reference document and the Calendar elements reference. (Those documents don't explicitly cover JSON-C, but the JSON-C property names are usually the same as Atom element names.)

If your request fails for some reason, Calendar may return a different status code; for information about the status codes, see the Google Data Protocol Reference document.

Note: By default, the events in a feed are ordered by their updated values, with the most recently updated event appearing first in the feed. For information on changing the ordering, see Calendar query parameters reference.

Retrieving an event again

If you want to retrieve an event that you've retrieved before, you can improve efficiency by telling Calendar to send the event only if it has changed since the last time you retrieved it.

To do this sort of conditional retrieval, send an HTTP GET request that includes an HTTP If-None-Match header. In the header, specify the entry's ETag, which you can find in the <entry> element's gd:etag attribute, or (in JSON-C) in the etag property.

For example:

If-None-Match: "EE4NTgBGfCp7ImA6WhVV"

When Calendar receives this request, it checks to see whether the event that you requested has the same ETag as the ETag you specified. If the ETags match, then the event hasn't changed, and Calendar returns either an HTTP 304 Not Modified status code or an HTTP 412 Precondition Failed status code. Both of those status codes indicate that the event you've already retrieved is up-to-date.

If the ETags don't match, then the event has been modified since the last time you requested it, and Calendar returns the event.

For more information about ETags, see the Google Data Protocol reference guide.

Retrieving events for a specified date range

The Calendar Data API lets you request a set of entries that match specified criteria. In addition to the standard Data API query parameters, Calendar provides two additional query parameters, start-min and start-max, to let you request all events that fall within or overlap a range of dates. For more information, see Calendar query parameters reference.

It's a good idea to limit your queries to a range of dates if you're not limiting them in any other way, just to avoid retrieving all entries ever posted to the calendar.

Here's how to create and send a date-range query at the protocol level:

First, authenticate the user, if you haven't already done so. See the previous example for information on how to do that.

Then send an HTTP request like the following to Calendar, using the special "default" URL:

GET https://www.google.com/calendar/feeds/default/private/full?start-min=2006-03-16T00:00:00&start-max=2006-03-24T23:59:59

(To request JSON-C format, append the alt=jsonc query parameter.)

Be sure to include the Authorization header in the request, as described in the previous example.

When you send that GET request, Calendar may return an HTTP 302 redirect with a gsessionid appended to it, just like in the earlier examples. In that case, read the HTTP headers of the response to find the URL with the session ID appended; then send another GET request with that new URL. (This second GET request also needs to have the Authorization header set.)

In response to the second GET request (or the first one if there was no redirect), Calendar returns an HTTP 200 OK status code and a feed containing any event that overlaps the minimum and maximum start times you specified.

Retrieving events matching a full text query

Google Calendar supports full-text queries that search the title and content of an event. To perform a full-text query send an HTTP request using the 'q' parameter in the URL.

GET https://www.google.com/calendar/feeds/default/private/full?q=Tennis

(To request JSON-C format, append the alt=jsonc query parameter.)

To query using standard Data API query parameters, just change the URL to use other parameters.

Note: Google Calendar doesn't support Data API category queries.

Creating events

The Calendar Data API allows you to create two types of events: single-occurrence events and recurring events, which are set up to repeat on a predetermined schedule.

Creating single-occurrence events

Adding an event to a calendar is a little bit more complicated than getting a feed, because you need to create the Atom or JSON-C code representing the event, and you need to use authentication.

First, create an entry of the Event kind. (For more information about kinds, see the Kinds document.) For example, you might create the following entry:

Atom

<entry xmlns='http://www.w3.org/2005/Atom'
    xmlns:gd='http://schemas.google.com/g/2005'>
  <category scheme='http://schemas.google.com/g/2005#kind'
    term='http://schemas.google.com/g/2005#event'></category>
  <title type='text'>Tennis with Beth</title>
  <content type='text'>Meet for a quick lesson.</content>
  <gd:transparency
    value='http://schemas.google.com/g/2005#event.opaque'>
  </gd:transparency>
  <gd:eventStatus
    value='http://schemas.google.com/g/2005#event.confirmed'>
  </gd:eventStatus>
  <gd:where valueString='Rolling Lawn Courts'></gd:where>
  <gd:when startTime='2006-04-17T15:00:00.000Z'
    endTime='2006-04-17T17:00:00.000Z'></gd:when>
</entry>

JSON-C

{
  "data": {
    "title": "Tennis with Beth",
    "details": "Meet for a quick lesson.",
    "transparency": "opaque",
    "status": "confirmed",
    "location": "Rolling Lawn Courts",
    "when": [
      {
        "start": "2010-04-17T15:00:00.000Z",
        "end": "2010-04-17T17:00:00.000Z"
      }
    ]
  }
}

Note that this entry does not contain the standard author element or property. The server will insert author information based on the user that submits the request (i.e. the user whose authentication token accompanies the request).

To post an entry, send the following HTTP request to Calendar, using a special "default" URL (and an Authorization header; see the section on authentication above). Calendar automatically redirects the default URL to the URL of the read/write private feed of the calendar belonging to the authenticated user. (Note that you don't have to use the default URL to send a POST request to Calendar; you can specify the user ID instead of "default" if you prefer. For more information, see the Calendar feed types reference.)

POST https://www.google.com/calendar/feeds/default/private/full

The content that you send with the POST request should be the entry you created above, using the appropriate content type.

Just like in the previous example, Calendar may return an HTTP 302 redirect; if so, then the redirect URL has a new parameter, gsessionid, appended to it. If you received the redirect, then send the same POST request again, with the same Authorization header and the same content, but with the gsessionid parameter appended. The response may also include a S cookie, which you should store and send this cookie with future requests as appropriate. For more information on handling sessions with the Calendar Data API, see the knowledge base. Please note: if a session ID indicated in a cookie header conflicts with the session ID passed as a gsessionid URL parameter, you will get caught in a redirect loop.

When you send that second POST request (or the first one in cases where there's no redirect), Calendar creates a calendar event, then returns an HTTP 201 CREATED status code, along with a copy of the new event in the form of an <entry> element or (in JSON-C) data object. The returned entry is similar to the one you sent, but the returned one contains data added by Calendar, such as an id element or property.

If your request fails for some reason, Calendar may return a different status code; for information about the status codes, see the Google Data Protocol Reference document.

Note that if you use the Data API to add an event to your calendar that involves multiple participants, the event appears on the other people's calendars just as it would if you added it by hand using the Calendar GUI.

Note: If making multiple creations/updates/deletions at the same time, please consider using Batch Request as it increases performance.

Creating quick add events

To create an event using Google Calendar's quick add feature, set the event entry's content to the quick add string you'd like to use. Then add a quickAdd element or property with its value set to true. For example, the following event entry will create an event on April 11 from 3pm-3:30pm with a title of 'Tennis with John':

Atom

<entry xmlns='http://www.w3.org/2005/Atom' xmlns:gCal='http://schemas.google.com/gCal/2005'>
  <content type="html">Tennis with John April 11 3pm-3:30pm</content>
  <gCal:quickadd value="true"/>
</entry>

JSON-C

{
  "data": {
    "details": "Tennis with John April 11 3pm-3:30pm",
    "quickAdd": true
  }
}

The response from the server will contain an event entry with the appropriate fields populated by the server. Note that some elements and properties are now empty or absent:

Atom

<entry xmlns="http://www.w3.org/2005/Atom" xmlns:gd="http://schemas.google.com/g/2005">
  ...
  <title type="text">Tennis with John</title>
  <content type="text" />
  <gd:when endTime="2007-04-11T15:30:00.000-07:00" startTime="2007-04-11T15:00:00.000-07:00" />
  ...
</entry>

JSON-C

{
  "apiVersion": "2.3",
  "data": {
    ...
    "title": "Tennis with John",
    "details": "",
    "when": [
      {
        "start": "2010-04-11T15:00:00.000+02:00",
        "end": "2010-04-11T15:30:00.000+02:00"
      }
    ]
    ...
  }
}

Note: If making multiple creations/updates/deletions at the same time, please consider using Batch Request as it increases performance.

Creating Calendar Event Gadgets

You can also create Gadgets as events in Google Calendar. Calendar Event Gadgets, formerly called web content, can contain images, HTML pages, or gadgets.

To create a simple Calendar Event Gadget that displays an image, first create a calendar event entry that contains a webContent element or object. (In Atom, that element appears inside a <link rel='http://schemas.google.com/gCal/2005/webContent'> element.)

For example, the following entry would create a Calendar Event Gadget that displays the World Cup doodle (dimensions 276x120, and located at https://www.google.com/logos/worldcup06.gif). The icon at https://www.google.com/calendar/images/google-holiday.gif will be used to display the Calendar Event Gadget in the Calendar user interface before it is clicked.

Atom

<entry xmlns="http://www.w3.org/2005/Atom" xmlns:gCal="http://schemas.google.com/gCal/2005" >
  <link rel="http://schemas.google.com/gCal/2005/webContent"
        href="https://www.google.com/calendar/images/google-holiday.gif"
        title="World Cup"
        type="image/gif">
    <gCal:webContent url="https://www.google.com/logos/worldcup06.gif" width="276" height="120" />
  </link>
</entry>

JSON-C

{
  "data": {
    "webContent": {
        "icon": "https://www.google.com/calendar/images/google-holiday.gif",
        "title": "World Cup",
        "type": "image/gif",
        "url": "https://www.google.com/logos/worldcup06.gif",
        "width": 276,
        "height": 120
    }
  }
}

To create a Calendar Event Gadget that displays a gadget, create an event entry with a web content link again, but this time the type should be application/x-google-gadgets+xml. You'll also need to get the gadget's URL from the iGoogle Directory. This example configures a Calendar Event Gadget to display the DateTime gadget and specifies the appropriate user preferences.

Atom

<entry xmlns="http://www.w3.org/2005/Atom" xmlns:gCal="http://schemas.google.com/gCal/2005" >
  <link rel="http://schemas.google.com/gCal/2005/webContent"
        href="https://www.google.com/favicon.ico"
        title="DateTime Gadget (a classic!)"
        type="application/x-google-gadgets+xml">
    <gCal:webContent url="https://www.google.com/ig/modules/datetime.xml" width="300" height="136">
      <gCal:webContentGadgetPref name="color" value="green" />
    </gCal:webContent>
  </link>
</entry>

JSON-C

{
  "data": {
    "webContent": {
        "icon": "https://www.google.com/favicon.ico",
        "title": "DateTime Gadget (a classic!)",
        "type": "application/x-google-gadgets+xml",
        "url": "https://www.google.com/ig/modules/datetime/xml",
        "width": 300,
        "height": 136
    }
  }
}

Once you've created the Gadget's event, insert it just like a normal event by sending an HTTP POST to the event feed URL with the event in the message body (using the appropriate content type).

POST https://www.google.com/calendar/feeds/default/private/full

For more information on Calendar Event Gadgets, see the Calendar Event Gadgets Reference Guide.

Note: If making multiple creations/updates/deletions at the same time, please consider using Batch Request as it increases performance.

Creating recurring events

Creating recurring events is very similar to creating a single-occurrence event. The event is created as an Atom element or JSON-C object of the Event kind, but includes a recurrence instead of a when element or property. A recurrence contains syntax for recurring events based upon the iCalendar standard (RFC 2445).

Here's an example of an all-day recurring event that occurs weekly on Tuesdays from May 5th, 2010 through September 4th, 2010:

Atom

<entry xmlns='http://www.w3.org/2005/Atom'
    xmlns:gd='http://schemas.google.com/g/2005'>
  <category scheme='http://schemas.google.com/g/2005#kind'
    term='http://schemas.google.com/g/2005#event'></category>
  <title type='text'>Tuesday Tennis Lessons with Jane</title>
  <content type='text'>Meet on Tuesdays for a quick lesson.</content>
  <gd:transparency
    value='http://schemas.google.com/g/2005#event.opaque'>
  </gd:transparency>
  <gd:eventStatus
    value='http://schemas.google.com/g/2005#event.confirmed'>
  </gd:eventStatus>
  <gd:where valueString='Rolling Lawn Courts'></gd:where>
  <gd:recurrence>DTSTART;VALUE=DATE:20100505
DTEND;VALUE=DATE:20100506
RRULE:FREQ=WEEKLY;BYDAY=Tu;UNTIL=20100904
</gd:recurrence>
</entry>

JSON-C

{
  "data": {
    "title": "Tuesday Tennis Lessons with Jane",
    "details": "Meet on Tuesdays for a quick lesson.",
    "transparency": "opaque",
    "status": "confirmed",
    "location": "Rolling Lawn Courts",
    "recurrence": "DTSTART;VALUE=DATE:20100505\r\nDTEND;VALUE=DATE:20100506\r\nRRULE:FREQ=WEEKLY;BYDAY=Tu;UNTIL=20100904\r\n"
  }
}

As per RFC 2445, each line of the recurrence syntax ends in a carriage return and a line feed (CRLF). As the event is an all-day event, it does not include a reference to a timezone. If you do include a recurring event which references a timezone, you don't need to include the VTIMEZONE definition if the timezone used is a standard Java timezone definition.

This entry can then be sent via a POST to the Calendar servers using the method described in the Creating single-occurrence events section.

Retrieving recurring events using the Calendar Data API can be done via several methods, using the query parameters defined in the Reference Guide. Here's a basic overview:

  • No query parameters: a recurring event is returned as a single element or object, with a recurrence child element or property. No when elements or properties are included in the recurring event.
  • start-min and/or start-max specified: a recurring event is represented as a single element or object, with multiple when elements or objects for each occurrence in the range specified. A recurrence is also included.
  • singleevents=true: recurring events are represented in the same format as single events, with a single element or object per occurrence of the event. Each event includes a single when element or object, but does not include the recurrence syntax. It does, however, include an originalEvent element or property.

Note: If making multiple creations/updates/deletions at the same time, please consider using Batch Request as it increases performance.

Updating events

To update an existing event, first you retrieve the event you want to update, then you modify it as desired, and then you send a PUT request, with the updated event in the message body, to the event's edit URL.

To make sure that your update doesn't overwrite another client's changes, include an HTTP If-Match header that contains the original event's ETag value. You can determine the original event's ETag value by examining the <entry> element's or data object's etag attribute.

If you want to update the event regardless of whether someone else has updated it since you retrieved it, then use If-Match: * and don't include the ETag.

For more information about ETags, see the Google Data Protocol reference guide.

Be sure that the id value in the entry you PUT exactly matches the id of the existing entry. The edit URL is highlighted in the following event entry:

Atom

<entry xmlns='http://www.w3.org/2005/Atom'
       xmlns:gd='http://schemas.google.com/g/2005'
       xmlns:gCal='http://schemas.google.com/gCal/2005'
       gd:etag='FkkOQgZGeip7ImA6WhVR'>
  <id>http://www.google.com/calendar/feeds/jo@gmail.com/private/full/entryID</id>
  <published>2006-03-30T22:00:00.000Z</published>
  <updated>2006-03-28T05:47:31.000Z</updated>
  <category scheme='http://schemas.google.com/g/2005#kind'
    term='http://schemas.google.com/g/2005#event'></category>
  <title type='text'>Lunch with Darcy</title>
  <content type='text'>Change of plans - Let's discuss the new proposal.</content>
  <link rel='alternate' type='text/html'
    href='https://www.google.com/calendar/event?eid=aTJxcnNqbW9tcTJnaTE5cnMybmEwaW04bXMgbWFyY2guam9AZ21haWwuY29t'
    title='alternate'></link>
  <link rel='self' type='application/atom+xml'
    href='https://www.google.com/calendar/feeds/jo@gmail.com/private/full/entryID' />
  <link rel='edit' type='application/atom+xml'
    href='https://www.google.com/calendar/feeds/jo@gmail.com/private/full/entryID' />
  ...
</entry>

JSON-C

{
  "apiVersion": "2.3",
  "data": {
    "kind": "calendar#event",
    "etag": "\"FkkOQgZGeip7ImA6WhVR\"",
    "id": "entryID",
    "selfLink": "https://www.google.com/calendar/feeds/default/private/full/entryID",
    "alternateLink": "https://www.google.com/calendar/event?eid=aTJxcnNqbW9tcTJnaTE5cnMybmEwaW04bXMgbWFyY2guam9AZ21haWwuY29t",
    "canEdit": true,
    "title": "Lunch with Darcy",
    "created": "2010-03-31T12:41:32.000Z",
    "updated": "2010-03-31T12:41:32.000Z",
    "details": "Change of plans - Let's discuss the new proposal.",
    ...
  }
}

IMPORTANT: To ensure forward compatibility, be sure that when you PUT an updated entry you preserve all the Atom or JSON-C that was present when you retrieved the entry from Google Calendar. Otherwise, when we implement new stuff and include new-awesome-feature elements or properties in the feed, your client won't return them and your users will miss out. The Google Data Protocol client libraries all handle this correctly, so if you're using one of the libraries you're all set.

Note: If making multiple creations/updates/deletions at the same time, please consider using Batch Request as it increases performance.

Deleting events

To delete an event, first you retrieve the event you want to delete, then you send a DELETE request to the event's edit URL. This is the same URL used to update the event.

If you want to make sure that you don't delete an event that has been changed by another client since you retrieved it, include an HTTP If-Match header that contains the original event's ETag value. You can determine the original event's ETag value by examining the event's etag.

If you want to delete the event regardless of whether someone else has updated it since you retrieved it, then use If-Match: * and don't include the ETag. (In this case, you don't need to retrieve the event before deleting it.)

For more information about ETags, see the Google Data Protocol reference guide.

Note: If making multiple creations/updates/deletions at the same time, please consider using Batch Request as it increases performance.

Sharing calendars

This section describes how to retrieve and modify Google Calendar access control lists (ACLs) using the raw protocol. An access control list identifies the set of users with whom a given calendar is shared, and the level of access for each user (such as read-only access, full access, and so on).

Specifically, an ACL is a list of access rules. Each access rule specifies a "scope" (a person or set of people) and then associates a "role" (an access level) with that scope. Those terms are defined as follows:

  • The scope of a rule directly or indirectly identifies a set of individuals to whom the rule applies. A scope has two parts: a type (such as user) and a value (such as an email address).
  • A role defines an access level, which determines what rights people identified by the given scope have. In Google Calendar, the defined roles include none, freebusy, read, and owner. (Note that in Atom, most role names must be preceded by a specific namespace URI; see the examples and reference document for details.) A given scope can have only one role.

For information about the other defined scopes and roles, see the GAcl namespace element reference in the Calendar reference document.

Note: For a given scope, having a role of none is equivalent to having no role defined.

The ACL for each calendar is available as a Data API feed. Each entry in the feed defines a single access rule.

Google Calendar does not support query parameters on requests for ACL feeds.

Retrieving access control lists

To retrieve a calendar's ACL feed, you send an authenticated GET to the feed's URI. Only someone with owner access to a calendar can view that calendar's ACL feed.

You can determine the URI of a calendar's ACL feed by looking at the calendar's entry in one of the calendar feeds (see Retrieving Calendars). The ACL feed URI is given in the <link rel="http://schemas.google.com/acl/2007#accessControlList"> element, or (in JSON-C) the accessControlListLink property.

For example, the following partial entry from a metafeed includes the URI of the ACL feed for a particular calendar.

Atom

<entry gd:etag='W/"C0ABSH4-eip7ImA9WxRVGUo."'>
  <id>http://www.google.com/calendar/feeds/liz%40gmail.com/liz%40gmail.com</id>
  <published>2007-04-24T01:40:29.752Z</published>
  <updated>2007-04-21T00:52:04.000Z</updated>
  <title type='text'>My Calendar</title>
  ...
  <link rel='http://schemas.google.com/acl/2007#accessControlList'
    type='application/atom+xml'
    href='https://www.google.com/calendar/feeds/liz%40gmail.com/acl/full'>
  </link>
  ...
</entry>

JSON-C

{
  "kind": "calendar#calendar",
  ...
  "title": "My Primary Calendar",
  ...
  "accessControlListLink": "https://www.google.com/calendar/feeds/user%40gmail.com/acl/full",
  ...
}

If you send a GET to that ACL feed URI, you might receive a feed like the following.

Atom

<feed xmlns='http://www.w3.org/2005/Atom'
    xmlns:openSearch='http://a9.com/-/spec/opensearch/1.1/'
    xmlns:gAcl='http://schemas.google.com/acl/2007'
    xmlns:gd='http://schemas.google.com/g/2005'
    gd:etag='W/"DU4ERH47eCp7ImA9WxRVEkQ."'>
  <id>http://www.google.com/calendar/feeds/liz%40gmail.com/acl/full</id>
  <updated>2007-04-21T00:52:04.000Z</updated>
  <title type='text'>Elizabeth Bennet's access control list</title>
  <link rel='https://schemas.google.com/acl/2007#controlledObject'
    type='application/atom+xml'
    href='https://www.google.com/calendar/feeds/liz%40gmail.com/private/full'>
  </link>
  <link rel='http://schemas.google.com/g/2005#feed'
    type='application/atom+xml'
    href='https://www.google.com/calendar/feeds/liz%40gmail.com/acl/full'>
  </link>
  <link rel='http://schemas.google.com/g/2005#post'
    type='application/atom+xml'
    href='https://www.google.com/calendar/feeds/liz%40gmail.com/acl/full'>
  </link>
  <link rel='self' type='application/atom+xml'
    href='https://www.google.com/calendar/feeds/liz%40gmail.com/acl/full'>
  </link>
  <generator version='1.0'
    uri='http://www.google.com/calendar'>Google Calendar</generator>
  <openSearch:totalResults>2</openSearch:totalResults>
  <openSearch:startIndex>1</openSearch:startIndex>
  <entry gd:etag='W/"DU4ERH47eCp7ImA9WxRVEkQ."'>
    <id>http://www.google.com/calendar/feeds/liz%40gmail.com/acl/full/user%3Aliz%40gmail.com</id>
    <updated>2007-04-21T00:52:04.000Z</updated>
    <category scheme='http://schemas.google.com/g/2005#kind'
      term='http://schemas.google.com/acl/2007#accessRule'>
</category> <title type='text'>owner</title> <content type='text'></content> <link rel='self' type='application/atom+xml' href='https://www.google.com/calendar/feeds/liz%40gmail.com/acl/full/user%3Aliz%40gmail.com'> </link> <link rel='edit' type='application/atom+xml' href='https://www.google.com/calendar/feeds/liz%40gmail.com/acl/full/user%3Aliz%40gmail.com'> </link> <author>
<name>Elizabeth Bennet</name>
<email>liz@gmail.com</email>
</author> <gAcl:scope type='user' value='liz@gmail.com'></gAcl:scope> <gAcl:role value='http://schemas.google.com/gCal/2005#owner'> </gAcl:role> </entry> <entry gd:etag='W/"DU4ERH47eCp7ImA9WxRVEkQ."'> <id>http://www.google.com/calendar/feeds/liz%40gmail.com/acl/full/default</id> <updated>2007-04-21T00:52:04.000Z</updated> <category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/acl/2007#accessRule'> </category> <title type='text'>read</title> <content type='text'></content> <link rel='self' type='application/atom+xml' href='https://www.google.com/calendar/feeds/liz%40gmail.com/acl/full/default'> </link> <link rel='edit' type='application/atom+xml' href='https://www.google.com/calendar/feeds/liz%40gmail.com/acl/full/default'> </link> <author>
<name>Elizabeth Bennet</name>
<email>liz@gmail.com</email>
</author> <gAcl:scope type='default'></gAcl:scope> <gAcl:role value='http://schemas.google.com/gCal/2005#read'> </gAcl:role> </entry> </feed>

JSON-C

{
  "apiVersion": "2.3",
  "data": {
    "kind": "calendar#aclFeed",
    "etag": "W/\"Ak8CRn47eCp7IWA9WxFTEEk.\"",
    "id": "http://www.google.com/calendar/feeds/liz%40gmail.com/acl/full",
    "controlledObjectLink": "https://www.google.com/calendar/feeds/liz%40gmail.com/private/full",
    "feedLink": "https://www.google.com/calendar/feeds/default/acl/full",
    "selfLink": "https://www.google.com/calendar/feeds/default/acl/full?alt\u003djsonc",
    "canPost": true,
    "items": [
      {
        "kind": "calendar#acl",
        "etag": "W/\"Ak8CRn47eCp7IWA9WxFTEEk.\"",
        "id": "http://www.google.com/calendar/feeds/liz%40gmail.com/acl/full/user%3Aliz%40gmail.com",
        "selfLink": "https://www.google.com/calendar/feeds/liz%40gmail.com/acl/full/user%3Aliz%40gmail.com",
        "canEdit": true,
        "role": "owner",
        "scopeType": "user",
        "scope": "liz@gmail.com"
      },
      {
        "kind": "calendar#acl",
        "etag": "W/\"Ak8CRn47eCp7IWA9WxFTEEk.\"",
        "id": "http://www.google.com/calendar/feeds/liz%40gmail.com/acl/full/default",
        "selfLink": "https://www.google.com/calendar/feeds/liz%40gmail.com/acl/full/default",
        "canEdit": true,
        "role": "read",
        "scopeType": "default",
        "scope": ""
      }
    ]
  }
}

A few comments on that feed:

  • The <link rel='http://schemas.google.com/acl/2007#controlledObject'> element, or (in JSON-C) the controlledObjectLink property, contains the URI of the calendar feed for the calendar that this ACL belongs to.
  • In Atom, each rule/entry contains a <category scheme='http://schemas.google.com/g/2005#kind'> element, with term='http://schemas.google.com/acl/2007#accessRule'.
  • In Atom, the ACL-specific elements use the namespace alias gAcl.
  • The first entry defines a role (owner) for a specific user (liz@gmail.com).
  • The second entry defines a role (read) for all other users (default).

Retrieving a rule

To retrieve a single ACL rule rather than the entire feed, you can construct the URI for a single rule using the scope type (such as user) and the scope value (such as the user's email address).

To construct the URI for a particular rule, start with the ACL feed URI; then add the scope type and value (URL-encoded as needed), separated by a colon, as an additional path element. For example, the following is the URI for the ACL rule (for the example calendar we've been using) for user darcy@gmail.com:

https://www.google.com/calendar/feeds/liz%40gmail.com/acl/full/user%3Adarcy%40gmail.com

(To request JSON-C format, append the alt=jsonc query parameter.)

If you request a rule that hasn't been defined, then the service returns an HTTP 404 NOT FOUND status code.

Adding a user to an access control list

A requester with permission to modify the access control list can add a new ACL rule by posting a new entry to the ACL feed's POST URI. The entry should contain the following elements or properties:

Atom

  • <category>
  • <gAcl:scope>
  • <gAcl:role>

JSON-C

  • scope
  • scopeType
  • role

Any other elements or properties that appear in the entry you send are ignored by the server.

Note: Another way to add a rule is to use PUT. For more information, see Updating a user's role in an ACL.

For example, you could send a POST request to the following URI, after authenticating as user liz@gmail.com:

POST /calendar/feeds/liz@gmail.com/acl/full

With the following entry in the body of the POST (using the appropriate content type):

Atom

<entry xmlns='http://www.w3.org/2005/Atom' xmlns:gAcl='http://schemas.google.com/acl/2007'>
  <category scheme='http://schemas.google.com/g/2005#kind'
    term='http://schemas.google.com/acl/2007#accessRule'/>
  <gAcl:scope type='user' value='darcy@gmail.com'></gAcl:scope>
  <gAcl:role
    value='http://schemas.google.com/gCal/2005#editor'>
  </gAcl:role>
</entry>

JSON-C

{
  "data": {
    "scope": "darcy@gmail.com",
    "scopeType": "user",
    "role": "editor"
  }
}

If the specified scope does not already have a role defined (or, equivalently, if the role for that scope is currently none), then Calendar creates a new ACL rule, and returns the corresponding ACL entry in the response. The returned entry includes several new elements or properties provided by the server.

If there is already a rule in the access control list with a scope whose type and value match that in the request, and whose role is anything other than none, then the POST operation fails with error code 409 Conflict.

The above POST might receive the following successful result:

Atom

201 Created

<entry xmlns='http://www.w3.org/2005/Atom' xmlns:gAcl='http://schemas.google.com/acl/2007'
    xmlns:gd='http://schemas.google.com/g/2005'
    gd:etag='W/"DU4ERH47eCp7ImA9WxRVEkQ."'>
  <id>http://www.google.com/calendar/feeds/liz%40gmail.com/acl/full/user%3Adarcy%40gmail.com</id>
  <updated>2007-04-15T22:03:57.000Z</updated>
  <category scheme='http://schemas.google.com/g/2005#kind'
    term='http://schemas.google.com/acl/2007#accessRule'>
  </category>
  <title type='text'>editor</title>
  <content type='text'></content>
  <link rel='self' type='application/atom+xml'
    href='https://www.google.com/calendar/feeds/liz%40gmail.com/acl/full/user%3Adarcy%40gmail.com'>
  </link>
  <link rel='edit' type='application/atom+xml'
    href='https://www.google.com/calendar/feeds/liz%40gmail.com/acl/full/user%3Adarcy%40gmail.com'>
  </link>
  <author>
    <name>Elizabeth Bennet</name>
    <email>liz@gmail.com</email>
  </author>
  <gAcl:scope type='user' value='darcy@gmail.com'></gAcl:scope>
  <gAcl:role value='http://schemas.google.com/gCal/2005#editor'>
  </gAcl:role>
</entry>

JSON-C

201 Created

{
  "apiVersion": "2.3",
  "data": {
    "kind": "calendar#acl",
    "etag": "W/\"CE8FSXc9cCp7IWA9WxFTEEg.\"",
    "id": "http://www.google.com/calendar/feeds/liz%40gmail.com/acl/full/user%3Adarcy%40gmail.com",
    "selfLink": "https://www.google.com/calendar/feeds/liz%40gmail.com/acl/full/user%3Adarcy%40gmail.com",
    "canEdit": true,
    "role": "editor",
    "scopeType": "user",
    "scope": "darcy@gmail.com"
  }
}

Updating a user's role in an ACL

To change an ACL rule, you can send a PUT request to the edit URI of the entry you want to modify. (You can also use this approach as an alternate method of creating new rules.)

You can construct the edit URI for a Google Calendar ACL rule entry using the entry's scope type and scope value, without having to retrieve the entry first.

For example, to change the ACL rule for user darcy@gmail.com, you could send the following PUT request (using the appropriate content type):

PUT /calendar/feeds/liz@gmail.com/acl/full/user%3Adarcy%40gmail.com

With the following entry in the request body:

Atom

<entry xmlns='http://www.w3.org/2005/Atom' xmlns:gAcl='http://schemas.google.com/acl/2007'
    xmlns:gd='http://schemas.google.com/g/2005'
    gd:etag='W/"DU4ERH47eCp7ImA9WxRVEkQ."'>
  <category scheme='http://schemas.google.com/g/2005#kind'
    term='http://schemas.google.com/acl/2007#accessRule'/>
  <gAcl:scope type='user' value='darcy@gmail.com'></gAcl:scope>
  <gAcl:role value='http://schemas.google.com/gCal/2005#read'></gAcl:role>
</entry>

JSON-C

{
  "data": {
    "etag": "W/\"CE8FSXc9cCp7IWA9WxFTEEg.\"",
    "role": "read",
    "scopeType": "user",
    "scope": "darcy@gmail.com"
  }
}

The URI fragment following /full/ in the PUT URI must indicate the same scope type and value as the elements or properties in the entry you're sending.

The server silently overwrites any previous access level set for the indicated scope. If there is no existing rule for that scope, it will create a new one.

Note: Because a given rule is associated with a particular scope, it is not possible to modify the scope of a rule when updating it; only the role can be modified. An attempt to modify the scope will result in a 403 Forbidden error.

Removing a user from an access control list

To remove a specific access rule for a calendar, you may do either of the following:

  • Send an HTTP DELETE request to the appropriate ACL entry's edit URI.
  • Update the entry (with PUT) and set role to none.

Doing either of those things causes the user (or group of users) specified in the scope to lose access to the calendar.

Querying busy times (Experimental)

If the only needed information is the freebusy time for one or more calendars, the API provides the functionality to get that without the overhead of requesting all calendar data. Using batch requests, this can be done for several users in one single HTTP request.

For Google Apps for Business domains, freebusy information for group members can also be retrieved more efficiently than querying each Calendar separately.

The freebusy feeds are read-only and contain entries with a list of blocks of busy-times, a busy-time being a time taken by a non-transparent event that has not been declined in the user's calendar.

Retrieving a user's busy times

To get a user's busy times feed, you send the following HTTP request to Calendar:

GET https://www.google.com/calendar/feeds/default/freebusy/busy-times/userID

(With the appropriate value in place of userID of course.)

The result is a read-only feed containing the user's blocks of busy-times

Atom

<entry xmlns="http://www.w3.org/2005/Atom" xmlns:gCal="http://schemas.google.com/gCal/2005"
 xmlns:gd="http://schemas.google.com/g/2005"
 gd:kind='calendar#freebusy' >
  <id>http://www.google.com/calendar/feeds/default/freebusy/busy-times/liz%40example.com</id>
  <updated>2010-03-13T00:00:00.000Z</udpated>
  <link rel='self'
  href='https://www.google.com/calendar/feeds/default/freebusy/busy-times/liz%40example.com' />
  <author>
    <name>liz@example.com</name>
    <email>liz@example.com</email>
  </author>
  <gCal:timeRange>
    <gd:when startTime='2010-03-13T00:00:00Z' endTime='2010-03-14T00:00:00Z'/>
  <gCal:timeRange>
  <gCal:busy>
    <gd:when startTime='2010-03-13T14:00Z' endTime='2010-03-13T14:30Z'/>
  </gCal:busy>
  <gCal:busy>
    <gd:when startTime='2010-03-13T16:00Z' endTime='2010-03-13T16:30Z'/>
  </gCal:busy>
</entry>

JSON-C

Freebusy requests aren't available in JSON-C format.

Note: The default time range is 24 hours from the time of the request. For information on specifying a date range, see Retrieving events for a specified date range.

This previous request is equivalent to sending a GET request to this URL:

https://www.google.com/calendar/feeds/default/freebusy/busy-times/userID?start-min=2010-03-13T00:00:00Z&start-max=2010-03-14T00:00:00Z

Retrieving group members' busy information

Note: This API is only available for Google Apps for Business domains.

You can also retrieve the busy information for the members of a group by sending the following HTTP request to Calendar:

GET https://www.google.com/calendar/feeds/default/freebusy/group/groupID/busy-times

(With the appropriate value in place of groupID of course.)

This request will return a feed containing an entry per group member's busy block of times. You can use the max-results query parameter to limit the number of entries returned by the API and use the next link to paginate throught the result.

Note: The default value for max-results is 25.

Atom

<feed xmlns="http://www.w3.org/2005/Atom"
  xmlns:gCal="http://schemas.google.com/gCal/2005"
  xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/"
  xmlns:gd="http://schemas.google.com/g/2005"
  gd:kind="calendar#groupFreebusyFeed">
  <id>http://www.google.com/calendar/feeds/default/freebusy/group/group%40example.com/busy-times</id>
  <updated>2010-03-13T00:00:00.000Z</updated>
  <category scheme="http://schemas.google.com/g/2005#kind"
    term="http://schemas.google.com/gCal/2005#freebusy"/>
  <link rel="http://schemas.google.com/g/2005#feed"
    type="application/atom+xml"
    href="https://www.google.com/calendar/feeds/default/freebusy/group/group%40example.com/busy-times"/>
  <link rel="self" type="application/atom+xml"
    href="https://www.google.com/calendar/feeds/default/freebusy/group/group%40example.com/busy-times?max-results=25"/>
  <link rel="next" type="application/atom+xml"
    href="https://www.google.com/calendar/feeds/default/freebusy/group/group%40example.com/busy-times?start-token=c2VtYmFAZ29vZ2xlLmNvbQ&max-results=25"/>
  <generator version="1.0" uri="http://www.google.com/calendar">Google Calendar</generator>
  <openSearch:totalResults>33</openSearch:totalResults>
  <entry gd:kind="calendar#groupFreebusy">
    <id>http://www.google.com/calendar/feeds/default/freebusy/busy-times/liz%40example.com</id>
    <updated>2010-03-13T00:00:00.000Z</updated>
    <category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/gCal/2005#freebusy"/>
    <link rel="self" type="application/atom+xml"
      href="https://www.google.com/calendar/feeds/default/freebusy/group/group%40example.com/busy-times/liz%40example.com"/>
    <author>
      <name>Elizabeth Bennet</name>
      <email>liz@example.com</email>
    </author>
    <gCal:timeRange>
      <gd:when startTime='2010-03-13T00:00:00Z' endTime='2010-03-14T00:00:00Z'/>
    <gCal:timeRange>
    <gCal:busy>
      <gd:when startTime='2010-03-13T14:00Z' endTime='2010-03-13T14:30Z'/>
    </gCal:busy>
    <gCal:busy>
      <gd:when startTime='2010-03-13T16:00Z' endTime='2010-03-13T16:30Z'/>
    </gCal:busy>
  </entry>
  <entry gd:kind="calendar#groupFreebusy">
    <id>http://www.google.com/calendar/feeds/default/freebusy/busy-times/john%40example.com</id>
    <updated>2010-03-13T00:00:00.000Z</updated>
    <category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/gCal/2005#freebusy"/>
    <link rel="self" type="application/atom+xml"
    href="https://www.google.com/calendar/feeds/default/freebusy/group/group%40example.com/busy-times/john%40example.com"/>
    <author>
      <name>John Doe</name>
      <email>john@example.com</email>
    </author>
    <gCal:timeRange>
      <gd:when startTime='2010-03-13T00:00:00Z' endTime='2010-03-14T00:00:00Z'/>
    <gCal:timeRange>
    <gCal:busy>
      <gd:when startTime='2010-03-13T09:00Z' endTime='2010-03-13T11:30Z'/>
    </gCal:busy>
    <gCal:busy>
      <gd:when startTime='2010-03-13T13:00Z' endTime='2010-03-13T13:30Z'/>
    </gCal:busy>
    <gCal:busy>
      <gd:when startTime='2010-03-13T15:00Z' endTime='2010-03-13T16:15Z'/>
    </gCal:busy>
  </entry>
  ...
</feed>

JSON-C

Freebusy requests aren't available in JSON-C format.

Note: A single group with more than 100 members cannot be queried for freebusy.

Note: Only 50 freebusy entries can be returned per request, please use max-results query parameter to limit the number of returned entries.

Retrieving multiple user's busy times using a batch request.

Busy times queries can be optimized by doing requests for multiple users at the same time by using batch requests

To do so, first create an XML representation of the busy times requests you want to send, which might look like that:

Atom

<feed xmlns="http://www.w3.org/2005/Atom"
  xmlns:gd="http://schemas.google.com/g/2005"
  xmlns:batch='http://schemas.google.com/gdata/batch'>
  <batch:operation type='query'/>
  <entry>
    <batch:id>lizFreeBusy</batch:id>
    <id>https://www.google.com/calendar/feeds/default/freebusy/busy-times/liz%40example.com</id>
  </entry>
  <entry>
    <batch:id>johnFreeBusy</batch:id>
    <id>https://www.google.com/calendar/feeds/default/freebusy/busy-times/john%40example.com</id>
  </entry>
  <entry>
    <batch:id>aliceFreeBusy</batch:id>
    <id>https://www.google.com/calendar/feeds/default/freebusy/busy-times/alice%40example.com</id>
  </entry>
</feed>

JSON-C

Freebusy requests aren't available in JSON-C format.

Then send a POST request to the freebusy batch URL:

https://www.google.com/calendar/feeds/default/freebusy/busy-times/batch

After submitting the batch request, the server will respond with a feed that contains the status of each request. You can parse this response to see if each operation was successful or not.

This is an example of what the server might return:

Atom

<feed xmlns="http://www.w3.org/2005/Atom"
      xmlns:gd="http://schemas.google.com/g/2005"
      gd:kind="calendar#freebusyFeed">
  <id>https://www.google.com/calendar/feeds/default/freebusy/batch/ID</id>
  <updated>2010-03-13T00:00:00.000Z</updated>
  <category scheme="http://schemas.google.com/g/2005#kind"
      term="http://schemas.google.com/gCal/2005#freebusy"/>
  <title>Batch Feed</title>
  <entry xmlns:batch="http://schemas.google.com/gdata/batch"
         xmlns:gCal="http://schemas.google.com/gCal/2005"
         gd:kind="calendar#freebusy">
    <id>http://www.google.com/calendar/feeds/default/freebusy/liz%40example.com</id>
    <updated>2010-03-13T00:00:00.000Z</updated>
    <category scheme="http://schemas.google.com/g/2005#kind"
      term="http://schemas.google.com/gCal/2005#freebusy"/>
    <link rel="self" type="application/atom+xml"
      href="https://www.google.com/calendar/feeds/default/freebusy/busy-times/liz%40example.com"/>
    <author>
      <name>liz@example.com</name>
      <email>liz@example.com</email>
    </author>
    <batch:id>lizFreeBusy</batch:id>
    <batch:operation type="query"/>
    <batch:status code="200" reason="Success"/>
    <gCal:timeRange>
      <gd:when startTime='2010-03-13T00:00:00Z'
      endTime='2010-03-14T00:00:00Z'/>
    <gCal:timeRange>
    <gCal:busy>
      <gd:when startTime='2010-03-13T14:00Z'
      endTime='2010-03-13T14:30Z'/>
    </gCal:busy>
    <gCal:busy>
      <gd:when startTime='2010-03-13T16:00Z'
      endTime='2010-03-13T16:30Z'/>
    </gCal:busy>
  </entry>
  <entry xmlns:batch="http://schemas.google.com/gdata/batch"
         xmlns:gCal="http://schemas.google.com/gCal/2005"
         gd:kind="calendar#freebusy">
    <id>http://www.google.com/calendar/feeds/default/freebusy/john%40example.com</id>
    <updated>2010-03-13T00:00:00.000Z</updated>
    <category scheme="http://schemas.google.com/g/2005#kind"
      term="http://schemas.google.com/gCal/2005#freebusy"/>
    <link rel="self" type="application/atom+xml"
      href="https://www.google.com/calendar/feeds/default/freebusy/busy-times/john%40example.com"/>
    <author>
      <name>john@example.com</name>
      <email>john@example.com</email>
    </author>
    <batch:id>johnFreeBusy</batch:id>
    <batch:operation type="query"/>
    <batch:status code="200" reason="Success"/>
    <gCal:timeRange>
      <gd:when startTime='2010-03-13T00:00:00Z'
      endTime='2010-03-14T00:00:00Z'/>
    <gCal:timeRange>
    <gCal:busy>
      <gd:when startTime='2010-03-13T09:00Z'
      endTime='2010-03-13T11:30Z'/>
    </gCal:busy>
    <gCal:busy>
      <gd:when startTime='2010-03-13T13:00Z'
      endTime='2010-03-13T13:30Z'/>
    </gCal:busy>
    <gCal:busy>
      <gd:when startTime='2010-03-13T15:00Z'
      endTime='2010-03-13T16:15Z'/>
    </gCal:busy>
  </entry>
  <entry xmlns:batch="http://schemas.google.com/gdata/batch"
         xmlns:gCal="http://schemas.google.com/gCal/2005"
         gd:kind="calendar#freebusy">
    <id>http://www.google.com/calendar/feeds/default/freebusy/alice%40example.com</id>
    <updated>2010-03-13T00:00:00.000Z</updated>
    <category scheme="http://schemas.google.com/g/2005#kind"
      term="http://schemas.google.com/gCal/2005#freebusy"/>
    <link rel="self" type="application/atom+xml"
      href="https://www.google.com/calendar/feeds/default/freebusy/busy-times/alice%40example.com"/>
    <author>
      <name>alice@example.com</name>
      <email>alice@example.com</email>
    </author>
    <batch:id>aliceFreeBusy</batch:id>
    <batch:operation type="query"/>
    <batch:status code="200" reason="Success"/>
    <gCal:timeRange>
      <gd:when startTime='2010-03-13T00:00:00Z'
      endTime='2010-03-14T00:00:00Z'/>
    <gCal:timeRange>
    <gCal:busy>
      <gd:when startTime='2010-03-13T09:00Z'
      endTime='2010-03-13T10:00Z'/>
    </gCal:busy>
    <gCal:busy>
      <gd:when startTime='2010-03-13T11:00Z'
      endTime='2010-03-13T11:30Z'/>
    </gCal:busy>
    <gCal:busy>
      <gd:when startTime='2010-03-13T12:00Z'
      endTime='2010-03-13T14:00Z'/>
    </gCal:busy>
    <gCal:busy>
      <gd:when startTime='2010-03-13T15:00Z'
      endTime='2010-03-13T15:15Z'/>
    </gCal:busy>
    <gCal:busy>
      <gd:when startTime='2010-03-13T16:00Z'
      endTime='2010-03-13T16:30Z'/>
    </gCal:busy>
  </entry>
</feed>

JSON-C

Freebusy requests aren't available in JSON-C format.

Note: The default time range is 24 hours from the time of the request. For information on specifying a date range, see Retrieving events for a specified date range.

This previous request is equivalent to sending a POST request to this URL:

https://www.google.com/calendar/feeds/default/freebusy/busy-times/batch?start-min=2010-03-13T00:00:00Z&start-max=2010-03-14T00:00:00Z

Note: See Batch request for more information.

Note: Google Apps for Business domains can add group members' busy-times query to a batch request:

Atom

<feed xmlns="http://www.w3.org/2005/Atom"
  xmlns:gd="http://schemas.google.com/g/2005"
  xmlns:batch='http://schemas.google.com/gdata/batch'>
  <batch:operation type='query'/>
  <entry>
    <batch:id>groupFreeBusy</batch:id>
    <id>https://www.google.com/calendar/feeds/default/freebusy/busy-times/group%40example.com</id>
  </entry>
  ...
</feed>

JSON-C

Freebusy requests aren't available in JSON-C format.

Such a request will return an embedded feed for this batch ID such as the result of a single group members' busy-times query.

Additional operations

Extended properties

You can add extended properties (arbitrary name-value pairs) to Calendar events. These can be used to store application-specific IDs or other small amounts of information your application needs when interacting with a Google Calendar. The name of a property can contain up to 47 characters, and the value can contain up to 1024 characters. Extended properties are only accessible through the API – they do not appear in the Calendar user interface.

To include extended properties in your events, add the <extendedProperty> element or (in JSON-C) the extendedProperties property, like this:

Atom

<entry xmlns="http://www.w3.org/2005/Atom" xmlns:gd="http://schemas.google.com/g/2005"
  gd:etag='W/"DU4ERH47eCp7ImA9WxRVEkQ."' >
  <id>http://www.google.com/calendar/feeds/jo@gmail.com/events/entryID</id>
  <published>2006-03-30T22:00:00.000Z</published>
  <updated>2006-03-28T05:47:31.000Z</updated>
  <category scheme='http://schemas.google.com/g/2005#kind'
    term='http://schemas.google.com/g/2005#event'></category>
  <title type='text'>Lunch with Darcy</title>
  <content type='text'>Lunch to discuss future plans.</content>
  <link rel='alternate' type='text/html'
    href='https://www.google.com/calendar/event?eid=aTJxcnNqbW9tcTJnaTE5cnMybmEwaW04bXMgbWFyY2guam9AZ21haWwuY29t'
    title='alternate'></link>
  <link rel='self' type='application/atom+xml'
    href='https://www.google.com/calendar/feeds/jo@gmail.com/private/full/entryID'></link>
  <link rel='edit' type='application/atom+xml'
    href='https://www.google.com/calendar/feeds/jo@gmail.com/private/full/entryID' />
  <gd:extendedProperty name="propname" value="propvalue" />
  ...
</entry>

JSON-C

{
  "apiVersion": "2.3",
  "data": {
    "kind": "calendar#event",
    "etag": "\"FUoJTgVHdyp7IWA6WhJT\"",
    "id": "8jsb0f2e9lpo6am4cf2plo9brg",
    "selfLink": "https://www.google.com/calendar/feeds/default/private/full/8jsb0f2e9lpo6am4cf2plo9brg",
    "alternateLink": "https://www.google.com/calendar/event?eid\u003dOGpzYjBmMmU5bHBvNmFtNGNmMnBsbzlicmcgcmF2ZW1hbitjYWxlbmRhcjVAZ29vZ2xlLmNvbQ",
    "canEdit": true,
    "title": "Tennis with Beth",
    ...
  "extendedProperties": [
      {
        "name": "name1",
        "value": "value1"
      },
      {
        "name": "name2",
        "value": "value2"
      }
    ]
  }
}

Note: Extended properties are not indexed so you can't query based on their keys or values.

Reminders and notifications

To include reminders in your events, add the reminders element or property as a child of the when element, like this:

Atom

<entry xmlns="http://www.w3.org/2005/Atom" xmlns:gd="http://schemas.google.com/g/2005"
  gd:etag='W/"DU4ERH47eCp7ImA9WxRVEkQ."' >
  <id>http://www.google.com/calendar/feeds/jo@gmail.com/events/entryID</id>
  <published>2006-03-30T22:00:00.000Z</published>
  <updated>2006-03-28T05:47:31.000Z</updated>
  <category scheme='http://schemas.google.com/g/2005#kind'
    term='http://schemas.google.com/g/2005#event'></category>
  <title type='text'>Lunch with Darcy</title>
  <content type='text'>Lunch to discuss future plans.</content>
  <link rel='alternate' type='text/html'
    href='https://www.google.com/calendar/event?eid=aTJxcnNqbW9tcTJnaTE5cnMybmEwaW04bXMgbWFyY2guam9AZ21haWwuY29t'
    title='alternate'></link>
  <link rel='self' type='application/atom+xml'
    href='https://www.google.com/calendar/feeds/jo@gmail.com/private/full/entryID'></link>
  <link rel='edit' type='application/atom+xml'
    href='https://www.google.com/calendar/feeds/jo@gmail.com/private/full/entryID' />
  <gd:when startTime='2006-03-30T22:00:00.000Z' endTime='2006-03-30T23:00:00.000Z'>
    <gd:reminder minutes='30' method='email' />
    <gd:reminder minutes='10' method='alert' />
  </gd:when>  ...
</entry>

JSON-C

{
  "apiVersion": "2.3",
  "data": {
    "kind": "calendar#event",
    "etag": "\"FUoORgREdip7IWA6WhJT\"",
    "id": "52f4theojvb86bg16ek0muvnag",
    "selfLink": "https://www.google.com/calendar/feeds/default/private/full/52f4theojvb86bg16ek0muvnag",
    "alternateLink": "https://www.google.com/calendar/event?eid\u003dNTJmNHRoZW9qdmI4NmJnMTZlazBtdXZuYWcgcmF2ZW1hbitjYWxlbmRhcjVAZ29vZ2xlLmNvbQ",
    "canEdit": true,
    "title": "Lunch with Darcy",
    "created": "0001-12-31T00:00:00.000Z",
    "updated": "2010-03-31T17:50:58.000Z",
    "details": "Lunch to discuss future plans. 2",
    ...
    "when": [
      {
        "start": "2010-04-01T10:00:00.000+02:00",
        "end": "2010-04-01T11:00:00.000+02:00",
    "reminders": [
          {
            "minutes": 10,
            "method": "alert"
          },
          {
            "minutes": 30,
            "method": "email"
          }
        ]
      }
    ]
  }
}

You can include up to five reminders per event. The available methods are email, alert (a popup in the browser), sms (a text message), or none.

By default every event created through the Google Calendar interface is associated with a SMS reminder, even if SMS notifications are not enabled in your Google Calendar account setting.

In Atom, for an event to inherit the default reminder setting of your Google Calendar account, you can either add an empty reminder element with no method value (<gd:reminder />) or add a <gd:reminder method='all' /> element.

In Atom, if you want to ensure that no reminders are sent, add a <gd:reminder method='none' /> element.

Note: The value of minutes can be any arbitrary number of minutes from 5 minutes to 4 weeks.

Comments

An attendee of an event used to be able to add a note, also known as a comment, to their reply.

However, the comment feature has been removed from the Google Calendar GUI, and the Data API comment feeds are now deprecated. Calendar still supplies a comment feed when requested, for backward compatibility, but that feed no longer provides useful information.

Because comments are deprecated and no longer useful, this developer's guide no longer provides information on how to request a comment feed.

GeoRSS data (Deprecated)

Important: This feature has been deprecated. While the server might still geocode the location, client applications should no longer rely on this feature.

If an event has any location information (see the gd:where element), the Calendar server geocodes the event's location as a latitude and longitude and includes this information into the event entry as a georss:where element (Atom) or geoLocation property (JSON-C):

Atom

<entry xmlns='http://www.w3.org/2005/Atom'
    xmlns:gml='http://www.opengis.net/gml'
    xmlns:georss='http://www.georss.org/georss'
    xmlns:gd='http://schemas.google.com/g/2005'
    gd:etag='W/"DU4ERH47eCp7ImA9WxRVEkQ."' >
  <id>http://www.google.com/calendar/feeds/jo@gmail.com/events/entryID</id>
  <published>2006-03-30T22:00:00.000Z</published>
  <updated>2006-03-28T05:47:31.000Z</updated>
  <category scheme='http://schemas.google.com/g/2005#kind'
    term='http://schemas.google.com/g/2005#event'></category>
  <title type='text'>Lunch with Darcy</title>
  <content type='text'>Lunch to discuss future plans.</content>
  <link rel='alternate' type='text/html'
    href='https://www.google.com/calendar/event?eid=aTJxcnNqbW9tcTJnaTE5cnMybmEwaW04bXMgbWFyY2guam9AZ21haWwuY29t'
    title='alternate'></link>
  <link rel='self' type='application/atom+xml'
    href='https://www.google.com/calendar/feeds/jo@gmail.com/private/full/entryID'></link>
  <link rel='edit' type='application/atom+xml'
    href='https://www.google.com/calendar/feeds/jo@gmail.com/private/full/entryID' />
  <gd:where valueString='Saint Petersburg' />
  <georss:where>
    <gml:Point>
      <gml:pos>59.939039 30.315785</gml:pos>
    </gml:Point>
  </georss:where>
</entry>

JSON-C

{
  "apiVersion": "2.3",
  "data": {
    "kind": "calendar#event",
    "etag": "\"FUoORwVFfSp7IWA6WhJT\"",
    "id": "52f4theojvb86bg16ek0muvnag",
    "selfLink": "https://www.google.com/calendar/feeds/default/private/full/52f4theojvb86bg16ek0muvnag",
    "alternateLink": "https://www.google.com/calendar/event?eid\u003dNTJmNHRoZW9qdmI4NmJnMTZlazBtdXZuYWcgcmF2ZW1hbitjYWxlbmRhcjVAZ29vZ2xlLmNvbQ",
    "canEdit": true,
    "title": "Lunch with Darcy",
    "updated": "2010-03-31T17:35:43.000Z",
    ...
    "location": "Saint Petersburg",
    "geoLocation": "59.939039 30.315785",
    ...
  }
}

The location is optional in the event feed and read-only. It is not guaranteed that GeoRSS information will be present in every event entry, even if the event location is set.

If the location is present, it contains latitute/longtitude data. For more information about the GeoRSS format, see http://georss.org.

Improving performance

Some special features are available to help you optimize your Calendar Data API requests.

Requesting a partial response (Experimental)

If there are many items in a feed, the Atom or JSON-C that is returned by the server can be quite long. With the Calendar Data API, you can ask for only the feed or entry information you need at the given point in your application. By requesting a partial response, you can significantly reduce the overhead of transferring and parsing unneeded data.

To request a partial response, use the fields query parameter, as shown in the following example.

The Atom and JSON-C formats have different field names, so the fields values are different.

Note: As with all query parameter values, the fields parameter value must be URL encoded. For better readability, the example below omits the encoding.

Atom

GET /calendar/feeds/default/private/full?fields=entry(@gd:*,title,gd:when)
GData-Version: 2

JSON-C

  Partial response in JSON-C format is coming soon.

This returns a partial representation that contains only the requested information for each entry. For example, the above Atom example returns all the gd namespace attributes (including gd:etag), the title, and time periods for all events, as shown below.

If your application is only displaying times and titles (or some other limited subset of event data), you can use a request like this to fetch only the data you need, eliminating a large amount of unneeded data from the response.

Atom

<?xml version='1.0' encoding='UTF-8'?>
<feed xmlns='http://www.w3.org/2005/Atom'
    xmlns:gd='http://schemas.google.com/g/2005'>
  <entry gd:etag='"FE8LQQJJeSp7IWA6WhVa"'
      gd:kind='calendar#event'
      gd:fields='@gd:*,title,gd:when'>
    <title>Meet Elizabeth for lunch</title>
    <gd:when endTime='2010-02-22T12:30:00.000-08:00'
        startTime='2010-02-22T11:00:00.000-08:00'>
      <gd:reminder method='alert' minutes='10' />
      <gd:reminder method='sms' minutes='10' />
    </gd:when>
  </entry>
  ...More entries here...
</feed>

JSON-C

  Partial response in JSON-C format is coming soon.

You can use partial response with any Calendar request that returns data, including GET, POST, and PUT, as well as PATCH, which is used for making partial update requests.

Note: If you want to use the result of a partial response as the basis of a subsequent PATCH request, it can be useful to include the ETag and edit link information in the results: fields='@gd:*,entry(@gd:*,link[@rel="edit"](@href),...)

For more information, see Partial response in the protocol reference document.

Making a partial update (Experimental)

You can also use a partial representation when modifying an entry. With partial update, you send only the changes, rather than a modified version of the full resource representation. This lets your client application be more efficient when making updates.

Instead of using PUT, however, you must use PATCH when requesting a partial update. You send the PATCH request to the same edit URI that you normally use with PUT. The data you send is a partial entry that represents the changes you want to make to the target resource.

When the server processes a PATCH request, it first checks to see if the partial entry includes a gd:fields attribute. If it does, everything specified by the gd:fields value is first removed from the target resource. Then each field provided in the body of the partial entry is merged:

  • If the field can only exist once in the target entry then, on merging, the field in the partial representation overwrites the corresponding field in the target entry.
  • If the field can exist more than once in the target entry then, on merging, the field is added to the target entry.

For more information on PATCH semantics, see Partial update in the protocol reference document.

The following example deletes a specific attendee from the event:

PATCH /calendar/feeds/default/private/full/eventID
Content-Type: application/xml
GData-Version: 2
If-Match: "FE8LQQJJeSp7IWA6WhVa"

Atom

<?xml version='1.0' encoding='UTF-8'?>
<entry xmlns='http://www.w3.org/2005/Atom'
    xmlns:gd='http://schemas.google.com/g/2005'
    gd:fields='gd:who[@email="liz@gmail.com"]'>
</entry>

JSON-C

  Partial update in JSON-C format is coming soon.

The partial entry representation provided has a gd:fields attribute of 'gd:who[@email="liz@gmail.com"]' or a fields property of attendees[email='liz@gmail.com'], so that email address is first removed from the target resource. Since there is no data provided in the request body, the effect is that the attendee with email address 'liz@gmail.com' is deleted from the event.

When a user responds to an event, you can use a partial update to change the attendee status, as shown in the following example:

PATCH /calendar/feeds/default/private/full/eventID
Content-Type: application/xml
GData-Version: 2
If-Match: "FE8LQQJJeSp7IWA6WhVa"

Atom

<?xml version='1.0' encoding='UTF-8'?>
<entry xmlns='http://www.w3.org/2005/Atom'
    xmlns:gd='http://schemas.google.com/g/2005'
    gd:fields='gd:who[@email="will@gmail.com"]'>
  <gd:who email='will@gmail.com'>
    <gd:attendeeStatus value='http://schemas.google.com/g/2005#event.accepted'/>
  </gd:who>
</entry>

JSON-C

 Partial update in JSON-C format is coming soon.

First, the existing data for the attendee with email address 'will@gmail.com' is removed from the event. Then the new data provided for the same attendee is merged. The new data indicates that the attendee accepted the event. In effect, the new <gd:who> element or attendee object replaces the one specified by the fields attribute or property.

Note that in this case, it was important to remove the existing data for the attendee first. Since the <gd:who> element or attendee object can exist more than once in the target entry, the merging process would have added it as another attendee with the same email address. Only by removing the existing data first can you replace a particular instance of a repeating item with a new value.

After processing a valid PATCH request, the server returns an HTTP 200 status code, along with a copy of the full representation of the updated calendar event.

If you prefer to have the server return only certain parts of an entry, you can use the fields query parameter with PATCH to request a partial response.

Performing multiple operations with a batch request

If you're performing a lot of operations, the time it takes to send and receive all those HTTP messages can really add up, making your app slow and unresponsive. With batch requests you can have the server perform multiple operations with a single HTTP request. The basic idea is that you create a calendar event feed and add an entry for each operation you want to perform. The following snippet shows a batch request that contains four operations, one each for creating, querying, updating, and deleting an event, but you can use any combination of operations that you want. Most of the unnecessary elements have been omitted.

Note: Batch requests are available only in Atom format, not JSON-C.

Note: In Atom, in addition to the usual namespace declarations, you also need to add the xmlns:batch namespace, as shown below.

Atom

<feed xmlns='http://www.w3.org/2005/Atom'
      xmlns:app='http://www.w3.org/2007/app'
      xmlns:batch='http://schemas.google.com/gdata/batch'
      xmlns:gCal='http://schemas.google.com/gCal/2005'
      xmlns:gd='http://schemas.google.com/g/2005'>
  <category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event' />
  <entry>
    <batch:id>Insert itemA</batch:id>
    <batch:operation type='insert' />
    <category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event' />
    <title type='text'>Event inserted via batch</title>
    ... additional fields for new entry ...
  </entry>
  <entry>
    <batch:id>Query itemB</batch:id>
    <batch:operation type='query' />
    <id>http://www.google.com/calendar/feeds/default/events/glcs0kv2qqa0gf52qi1jo018gc</id>
  </entry>
  <entry gd:etag='"FkkOQgZGeip7ImA6WhVR"'>
    <batch:id>Update itemC</batch:id>
    <batch:operation type='update' />
    <id>http://www.google.com/calendar/feeds/default/events/ujm0go5dtngdkr6u91dcqvj0qs</id>
    <category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event' />
    <title type='text'>Event updated via batch</title>
    <link rel='alternate' type='text/html'
        href='https://www.google.com/calendar/event?eid=dWptMGdvNWR0bmdka3I2dTkxZGNxdmowcXMgaGFyaXNodi50ZXN0QG0' title='alternate' />
    <link rel='self' type='application/atom+xml'
        href='https://www.google.com/calendar/feeds/default/private/full/ujm0go5dtngdkr6u91dcqvj0qs' />
    <link rel='edit' type='application/atom+xml'
        href='https://www.google.com/calendar/feeds/default/private/full/ujm0go5dtngdkr6u91dcqvj0qs/63326098791' />
   ... rest of modified full resource representation ...
  </entry>
  <entry gd:etag='"GUoNTgZCfCp7ImA6WhVW"'>
    <batch:id>Delete itemD</batch:id>
    <batch:operation type='delete' />
    <id>http://www.google.com/calendar/feeds/default/events/d8qbg9egk1n6lhsgq1sjbqffqc</id>
  </entry>
</feed>

JSON-C

Batch requests aren't available in JSON-C format.

Once you build your batch request feed, you need to send an authenticated POST request to the batch URL of the events feed. The batch URL is highlighted in the following events feed:

Atom

<feed xmlns='http://www.w3.org/2005/Atom' xmlns:gd='http://schemas.google.com/g/2005'>
  <id>http://www.google.com/calendar/feeds/<calendarID>/private/full</id>
  <updated>2007-09-21T22:59:51.000Z</updated>
  <title type='text'>Jo March</title>
  <subtitle type='text'>This is my main calendar.</subtitle>
  ...
  <link rel='http://schemas.google.com/g/2005#batch' type='application/atom+xml'
      href='https://www.google.com/calendar/feeds/<calendarID>/private/full/batch' />
  ...
</feed>

JSON-C

Batch requests aren't available in JSON-C format.

After submitting the batch request, the server will respond with a feed that contains the status of each operation. You can parse this response to see if each operation was successful or not. Here's an abbreviated version of the response when submitting the above batch request feed.

Atom

<feed xmlns='http://www.w3.org/2005/Atom'
      xmlns:batch='http://schemas.google.com/gdata/batch'
      xmlns:gCal='http://schemas.google.com/gCal/2005'>
  <id>http://www.google.com/calendar/feeds/default/events</id>
  <updated>2007-09-21T23:01:00.380Z</updated>
  <category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category>
  <title type='text'>Batch Feed</title>
  <link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml'
      href='https://www.google.com/calendar/feeds/default/private/full' />
  <link rel='http://schemas.google.com/g/2005#post' type='application/atom+xml'
      href='https://www.google.com/calendar/feeds/default/private/full' />
  <link rel='http://schemas.google.com/g/2005#batch' type='application/atom+xml'
      href='https://www.google.com/calendar/feeds/default/private/full/batch' />
  <entry>
    <batch:id>Insert itemA</batch:id>
    <batch:status code='201' reason='Created' />
    <batch:operation type='insert' />
    <id>http://www.google.com/calendar/feeds/default/events/n9ug78gd9tv53ppn4hdjvk68ek</id>
    <category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event' />
    <title type='text'>Event inserted via batch</title>
    <link rel='alternate' type='text/html'
        href='https://www.google.com/calendar/event?eid=bjl1Zzc4Z2Q5dHY1M3BwbjRoZGp2azY4ZWsgaGFyaXNodi50ZXN0QG0' title='alternate' />
    <link rel='self' type='application/atom+xml'
        href='https://www.google.com/calendar/feeds/default/private/full/n9ug78gd9tv53ppn4hdjvk68ek' />
    <link rel='edit' type='application/atom+xml'
      href='https://www.google.com/calendar/feeds/default/private/full/n9ug78gd9tv53ppn4hdjvk68ek/63326098860' />
    ... rest of full resource representation ...
  </entry>
  <entry>
    <batch:id>Query itemB</batch:id>
    <batch:status code='200' reason='Success' />
    <batch:operation type='query' />
    <id>http://www.google.com/calendar/feeds/default/events/glsc0kv2aqa0ff52qi1jo018gc</id>
    <category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event' />
    <title type='text'>Existing event</title>
    <link rel='alternate' type='text/html'
        href='https://www.google.com/calendar/event?eid=Z2xzYzBrdjJhcWEwZmY1MnFpMWpvMDE4Z2MgaGFyaXNodi50ZXN0QG0' title='alternate' />
    <link rel='self' type='application/atom+xml'
        href='https://www.google.com/calendar/feeds/default/private/full/glsc0kv2aqa0ff52qi1jo018gc' />
    <link rel='edit' type='application/atom+xml'
        href='https://www.google.com/calendar/feeds/default/private/full/glsc0kv2aqa0ff52qi1jo018gc/63326098791' />
    ... rest of full resource representation ...
  </entry>
  <entry xmlns:gCal='http://schemas.google.com/gCal/2005'>
    <batch:id>Update itemC</batch:id>
    <batch:status code='200' reason='Success' />
    <batch:operation type='update' />
    <id>http://www.google.com/calendar/feeds/default/events/ujm0go5dtngdkr6u91dcqvj0qs</id>
    <category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event' />
    <title type='text'>Event updated via batch</title>
    <link rel='alternate' type='text/html'
        href='https://www.google.com/calendar/event?eid=dWptMGdvNWR0bmdka3I2dTkxZGNxdmowcXMgaGFyaXNodi50ZXN0QG0' title='alternate' />
    <link rel='self' type='application/atom+xml'
        href='https://www.google.com/calendar/feeds/default/private/full/ujm0go5dtngdkr6u91dcqvj0qs' />
    <link rel='edit' type='application/atom+xml'
        href='https://www.google.com/calendar/feeds/default/private/full/ujm0go5dtngdkr6u91dcqvj0qs/63326098860' />
    ... rest of full resource representation ...
  </entry>
  <entry>
    <batch:id>Delete itemD</batch:id>
    <batch:status code='200' reason='Success' />
    <batch:operation type='delete' />
    <id>http://www.google.com/calendar/feeds/default/events/d8qbg9egk1n6lhsgq1sjbqffqc</id>
    <updated>2010-03-25T00:28:03.819Z</updated>
    <title>Deleted</title>
    <content>Deleted</content>
  </entry>
</feed>

JSON-C

Batch requests aren't available in JSON-C format.

When working with batch requests, the size of the request must be under a megabyte and it's best to limit batches to 50-100 operations at a time. You can find more information about batch operations in the Google Data Protocol batch processing documentation.

Note: The batch request URL for the freebusy feed is https://www.google.com/calendar/feeds/default/freebusy/busy-times/batch

Using the JSON-C data format

JSON-C, sometimes called "Compact JSON," is a compact alternative to the Atom XML data format that the Calendar Data API uses by default.

JSON-C uses standard JSON to encode the same information without having to exactly correspond to the equivalent Atom representation. In addition to being a significantly more compact format, JSON-C is also faster to parse than XML.

To request that Google Calendar return data in JSON-C format, append the alt=jsonc query parameter to a query.

This developer's guide provides both Atom and JSON-C versions of most examples.

Note: The client libraries don't support JSON-C; if you want your client to use JSON-C, you have to send the HTTP requests and parse the responses.

In most cases, JSON-C properties have names similar or identical to the corresponding Atom elements and attributes. Where the JSON-C names and corresponding Atom names differ, it is in the interest of making the JSON-C representation more compact.

Some specific differences worth noting:

  • The main property of a JSON-C feed is a data object.
  • The JSON-C equivalent of a list of <entry> elements is a list of item objects.
  • In JSON-C, a location is specified with a location property, which corresponds to the Atom <gd:where> element.
  • The JSON-C geoLocation property corresponds to the Atom <gml:pos> element (contained in the <gml:Point> part of a <georss:where> element).
  • The JSON-C attendees property corresponds to the Atom <gd:who> element.

(The Google Data Protocol can also use a different JSON format, but that format was designed to map precisely to the much less compact Atom representation.)

Authentication required

You need to be signed in with Google+ to do that.

Signing you in...

Google Developers needs your permission to do that.