Google Apps Platform

Google Documents List API version 3.0

Important: Version 3 of the Google Documents List API has been officially deprecated as of September 14, 2012. It will continue to work as per our deprecation policy, but we encourage you to move to the Google Drive API.

The Google Documents List API allows client applications to view and manipulate files in a user's Documents List. Your application can use this API to store files and to integrate the Google Docs experience.



Introduction

This guide discusses how to use the Google Documents List API version 3.0.

What can this API do?

The Google Documents List API allows developers to create, retrieve, update, and delete Google Docs (including but not limited to text documents, spreadsheets, presentations, and drawings), files, and collections. It also provides some advanced features like resource archives, Optical Character Recognition, translation, and revision history.

You will find this API useful if you need to store data in the cloud, perform resource management, convert document formats, etc. All interactions with the API require a valid Google Account, which can be a "consumer" account (e.g. Gmail), or a Google Apps account.

Audience

This developer's guide is intended for software developers needing a technical reference for using the Google Documents List API. The information you find in this guide is written by Google engineers, and is authoritative on how the API behaves.

Terminology used in this guide

Throughout this guide, we refer to a series of terms like document or file, which we intend to have specific meanings.

document
Any item maintained by Google Docs that is hosted in a native Google Docs format. This can include a text document, spreadsheet, presentation, or drawing. A document is created by either creating an empty Google Doc in the web interface or by using the API to upload an existing file. When you upload something like a Microsoft Excel® file, if you opt to convert it to a Google Doc, then it is considered a "document" in this guide. If you do not convert it when you upload, then it is considered a "file" (see below).
file
Any item maintained by Google Docs that is not hosted in the native format. This could include a PDF file, MP3 file, MPEG file, TXT file, etc. A file is created by uploading an item to Google Docs, and not converting it to the native Google Docs format. That is to say, you could have an unconverted Microsoft Excel file hosted in Google Docs. If you were to do this though, the file would not be available for conversion to other formats, full text search, or many other features provided by this API.
collection
A container of other documents, files, or collections. These were previously named folders. In order to avoid issues with backward-compatibility, we have not renamed folders to collections in the API protocol. The API still returns resource IDs with a type of folder.
resource
Any item maintained by the API, including documents, files, and collections.
resource ID
A unique identifier for each resource. This is usually of the format [type]:[id], e.g. document:12345. Throughout this guide, if not specified, a typed resource ID should be assumed.
untyped resource ID
A resource ID, without the type prefix. Given the previous example, an untyped resource ID would be 12345.

Should I use version 3 of the API?

There are currently three versions of the Google Documents List API. Version 1 has been deprecated, and should not be used. Version 2 is no longer recommended.

Version 3 of the API (the version you're currently reading about) has many more features than versions 1 or 2. We highly recommend that you use version 3 if at all possible.

Additional resources, information about this guide

Occasionally, we make a mistake in this documentation, or unknowingly break a feature that you depend on.

If this has happened to you, sorry! You can help us fix the issue by posting in the forum or by filing a bug. We appreciate your help!

Setting up your client library

A number of client libraries are provided in various languages. These client libraries make it easier to interact with the Documents List API.

This section is not relevant to applications using the Documents List API at the protocol level, but all application developers should strongly consider using a GData client library to interact with the API.

Java

The Java client library is maintained in an open-source project on Google Project hosting. The Java library itself is distributed as a ZIP file, containing a number of JARs that applications can import in order to gain access to the library.

The Java client library requires JDK 5.0 or greater. The latest version of the Oracle JDK is available from http://www.oracle.com/technetwork/java/index.html.

Unfortunately, due to restrictive licensing, we cannot at this time just give developers a ZIP of all JARs required to interact with the API. Some of the JARs are not available without additional license agreements. Because of this, some of the JARs must be downloaded individually. We sincerely apologize for this inconvenience.

To setup a development environment for working with the Documents List API, perform the following steps.

  1. Download the latest gdata-src.java-*.zip file from the project's Downloads page. Replace * in this case with something like 1.46.0.

  2. Extract the ZIP file into a new directory.

    unzip gdata-src.java-1.46.0.zip -d ./gdata-java-client
    
  3. Copy the JARs from gdata-java-client/gdata/java/lib into a directory included in the application's classpath.

    cp gdata-java-client/gdata/java/lib/* /path/to/application/lib
    
  4. Copy the JARs from gdata-java-client/gdata/java/deps into the application's classpath.

    cp gdata-java-client/gdata/java/deps/* /path/to/application/lib
    
  5. Download the JavaMail API (version 1.4 or greater) from here. Extract the ZIP file and copy mail.jar to the application's classpath.

    unzip javamail1_4_4.zip -d javamail
    cp javamail/javamail-1.4.4/mail.jar /path/to/application/lib
    
  6. If using the Oracle JDK version 1.5, download the JavaBeans Activation Framework from here. Extract the ZIP file and copy activation.jar to the application's classpath.

    unzip jaf-1_1_1.zip -d jaf
    cp jaf/jaf-1.1.1/activation.jar /path/to/application/lib
    
  7. To implement any of the code discussed in this document, use the following class template.

    import com.google.gdata.client.authn.oauth.*;
    import com.google.gdata.client.docs.*;
    import com.google.gdata.data.*;
    import com.google.gdata.data.batch.*;
    import com.google.gdata.data.docs.*;
    import com.google.gdata.util.*;
    
    import java.io.IOException;
    import java.net.*;
    import java.util.*;
    
    public class MyDocumentsListIntegration {
      public static void main(String[] args)
          throws AuthenticationException, MalformedURLException, IOException, ServiceException {
    
        // Application code here
    
      }
    }
    
  8. Once the above template is in place, continue reading the rest of this document, applying the Java code samples as necessary.

.NET

The .NET client library is maintained in an open-source project on Google Project hosting. The .NET library itself is distributed as a MSI installer, containing a number of DLLs that applications can import in order to gain access to the library.

The .NET client library requires the .NET Framework 2.0 or greater.

To setup a development environment for working with the Documents List API, perform the following steps.

  1. Download the latest Google_Data_API_Setup_*.msi file from the project's Downloads page. Replace * in this case with something like 1.9.0.0.

  2. Run the installer and follow the instructions in the setup wizard.

  3. To implement any of the code discussed in this document, use the following class template.

    using Google.GData.Client;
    using Google.GData.Documents;
    
    namespace MyDocumentsListIntegration
    {
      class Program {
        static void Main(string[] args)
        {
    
          // Application code here
    
        }
      }
    }
    
  4. Once the above template is in place, continue reading the rest of this document, applying the .NET code samples as necessary.

Authorizing requests

When your application requests non-public user data, it must include an authorization token. The token also identifies your application to Google.

About authorization protocols

We recommend using OAuth 2.0 to authorize requests.

The Google Documents List Data API also supports older authorization options, such as OAuth 1.0, AuthSub, or ClientLogin; however, in most cases we don't recommend using those other options. If your application already uses those options, we recommend migrating to OAuth 2.0 if possible.

If your application has certain unusual authorization requirements, such as logging in at the same time as requesting data access (hybrid) or domain-wide delegation of authority (2LO), then you cannot currently use OAuth 2.0 tokens. In such cases, you must instead use OAuth 1.0 tokens.

Authorizing requests with OAuth 2.0

Requests to the Google Documents List Data API for non-public user data must be authorized by an authenticated user.

The details of the authorization process, or "flow," for OAuth 2.0 vary somewhat depending on what kind of application you're writing. The following general process applies to all application types:

  1. When you create your application, you register it with Google. Google then provides information you'll need later, such as a client ID and a client secret.
  2. Activate the Google Documents List Data API in the Services pane of the Google APIs Console. (If it isn't listed in the Console, then skip this step.)
  3. When your application needs access to user data, it asks Google for a particular scope of access.
  4. Google displays an OAuth dialog to the user, asking them to authorize your application to request some of their data.
  5. If the user approves, then Google gives your application a short-lived access token.
  6. Your application requests user data, attaching the access token to the request.
  7. If Google determines that your request and the token are valid, it returns the requested data.

Some flows include additional steps, such as using refresh tokens to acquire new access tokens. For detailed information about flows for various types of applications, see Google's OAuth 2.0 documentation.

Here's the OAuth 2.0 scope information for the Google Documents List Data API:

https://docs.google.com/feeds/ https://docs.googleusercontent.com/ https://spreadsheets.google.com/feeds/

To request access using OAuth 2.0, your application needs the scope information, as well as information that Google supplies during application registration (such as the client ID and/or the client secret).

Performing OAuth 2.0

.NET

The following example is copied from the google-gdata project's sample directory. It has been modified to accommodate the Documents List API, and is provided here for ease of reference.

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      ////////////////////////////////////////////////////////////////////////////
      // STEP 1: Configure how to perform OAuth 2.0
      ////////////////////////////////////////////////////////////////////////////

      // TODO: Update the following information with that obtained from
      // https://code.google.com/apis/console. After registering
      // your application, these will be provided for you.

      string CLIENT_ID = "12345678.apps.googleusercontent.com";

      // This is the OAuth 2.0 Client Secret retrieved
      // above.  Be sure to store this value securely.  Leaking this
      // value would enable others to act on behalf of your application!
      string CLIENT_SECRET = "Gc0230jdsah01jqpowpgff";

      // Space separated list of scopes for which to request access.
      string SCOPE = "https://docs.google.com/feeds/ https://docs.googleusercontent.com/ https://spreadsheets.google.com/feeds/";

      // This is the Redirect URI for installed applications.
      // If you are building a web application, you have to set your
      // Redirect URI at https://code.google.com/apis/console.
      string REDIRECT_URI = "urn:ietf:wg:oauth:2.0:oob";

      ////////////////////////////////////////////////////////////////////////////
      // STEP 2: Set up the OAuth 2.0 object
      ////////////////////////////////////////////////////////////////////////////

      // OAuth2Parameters holds all the parameters related to OAuth 2.0.
      OAuth2Parameters parameters = new OAuth2Parameters();

      // Set your OAuth 2.0 Client Id (which you can register at
      // https://code.google.com/apis/console).
      parameters.ClientId = CLIENT_ID;

      // Set your OAuth 2.0 Client Secret, which can be obtained at
      // https://code.google.com/apis/console.
      parameters.ClientSecret = CLIENT_SECRET;

      // Set your Redirect URI, which can be registered at
      // https://code.google.com/apis/console.
      parameters.RedirectUri = REDIRECT_URI;

      ////////////////////////////////////////////////////////////////////////////
      // STEP 3: Get the Authorization URL
      ////////////////////////////////////////////////////////////////////////////

      // Set the scope for this particular service.
      parameters.Scope = SCOPE;

      // Get the authorization url.  The user of your application must visit
      // this url in order to authorize with Google.  If you are building a
      // browser-based application, you can redirect the user to the authorization
      // url.
      string authorizationUrl = OAuthUtil.CreateOAuth2AuthorizationUrl(parameters);
      Console.WriteLine(authorizationUrl);
      Console.WriteLine("Please visit the URL above to authorize your OAuth "
        + "request token.  Once that is complete, type in your access code to "
        + "continue...");
      parameters.AccessCode = Console.ReadLine();

      ////////////////////////////////////////////////////////////////////////////
      // STEP 4: Get the Access Token
      ////////////////////////////////////////////////////////////////////////////

      // Once the user authorizes with Google, the request token can be exchanged
      // for a long-lived access token.  If you are building a browser-based
      // application, you should parse the incoming request token from the url and
      // set it in OAuthParameters before calling GetAccessToken().
      OAuthUtil.GetAccessToken(parameters);
      string accessToken = parameters.AccessToken;
      Console.WriteLine("OAuth Access Token: " + accessToken);

      ////////////////////////////////////////////////////////////////////////////
      // STEP 5: Make an OAuth authorized request to Google
      ////////////////////////////////////////////////////////////////////////////

      // Initialize the variables needed to make the request
      GOAuth2RequestFactory requestFactory =
          new GOAuth2RequestFactory(null, "MyDocumentsListIntegration-v1", parameters);
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
      service.RequestFactory = requestFactory;

      // Make the request to Google
      // See other portions of this guide for code to put here...
    }
  }
}

Authorizing requests with OAuth 1.0a

As with OAuth 2.0, the scope to request for OAuth 1.0a while working with the Documents List API is:

https://docs.google.com/feeds/ https://docs.googleusercontent.com/ https://spreadsheets.google.com/feeds/

As mentioned previously, the Java client library does not currently support OAuth 2.0. Instead, to authorize with OAuth 1.0a, use the following code.

Performing 3-Legged OAuth 1.0a (OAuth 1.0a for Web Applications)

Java

The following example is copied from the gdata-java-client project's sample directory. It has been modified to accommodate the Spreadsheets API, and is provided here for ease of reference.

import com.google.gdata.client.authn.oauth.GoogleOAuthHelper;
import com.google.gdata.client.authn.oauth.GoogleOAuthParameters;
import com.google.gdata.client.authn.oauth.OAuthHmacSha1Signer;
import com.google.gdata.client.authn.oauth.OAuthRsaSha1Signer;
import com.google.gdata.client.authn.oauth.OAuthSigner;
import com.google.gdata.client.docs.*;
import com.google.gdata.data.Link;
import com.google.gdata.data.batch.BatchOperationType;
import com.google.gdata.data.batch.BatchStatus;
import com.google.gdata.data.batch.BatchUtils;
import com.google.gdata.data.docs.*;
import com.google.gdata.util.*;

import java.io.IOException;
import java.net.*;
import java.util.*;

public class MyDocumentsListIntegration {
  public static void main(String[] args)
      throws AuthenticationException, MalformedURLException, IOException, ServiceException {

    ////////////////////////////////////////////////////////////////////////////
    // STEP 1: Configure how to perform OAuth 1.0a
    ////////////////////////////////////////////////////////////////////////////

    boolean USE_RSA_SIGNING = false;

    // TODO: Update the following information with that obtained from
    // https://www.google.com/accounts/ManageDomains. After registering
    // your application, these will be provided for you.

    String CONSUMER_KEY = "yourappdomain.com";

    // TODO: Replace this with base-64 encoded private key conforming
    // to PKCS #8 standard, if and only if you will use RSA-SHA1
    // signing.  Otherwise, this is the OAuth Consumer Secret retrieved
    // above.  Be sure to store this value securely.  Leaking this
    // value would enable others to act on behalf of your application!
    String CONSUMER_SECRET = "Gc0230jdsah01jqpowpgff";

    // Space separated list of scopes for which to request access.
    String SCOPES = "https://docs.google.com/feeds/ https://docs.googleusercontent.com/ https://spreadsheets.google.com/feeds/";

    ////////////////////////////////////////////////////////////////////////////
    // STEP 2: Set up the OAuth objects
    ////////////////////////////////////////////////////////////////////////////

    // You first need to initialize a few OAuth-related objects.
    // GoogleOAuthParameters holds all the parameters related to OAuth.
    // OAuthSigner is responsible for signing the OAuth base string.
    GoogleOAuthParameters oauthParameters = new GoogleOAuthParameters();

    // Set your OAuth Consumer Key (which you can register at
    // https://www.google.com/accounts/ManageDomains).
    oauthParameters.setOAuthConsumerKey(CONSUMER_KEY);

    // Initialize the OAuth Signer.  If you are using RSA-SHA1, you must provide
    // your private key as a Base-64 string conforming to the PKCS #8 standard.
    // Visit http://code.google.com/apis/gdata/authsub.html#Registered to learn
    // more about creating a key/certificate pair.  If you are using HMAC-SHA1,
    // you must set your OAuth Consumer Secret, which can be obtained at
    // https://www.google.com/accounts/ManageDomains.
    OAuthSigner signer;
    if (USE_RSA_SIGNING){
      signer = new OAuthRsaSha1Signer(CONSUMER_SECRET);
    } else {
      oauthParameters.setOAuthConsumerSecret(CONSUMER_SECRET);
      signer = new OAuthHmacSha1Signer();
    }

    // Finally, create a new GoogleOAuthHelperObject.  This is the object you
    // will use for all OAuth-related interaction.
    GoogleOAuthHelper oauthHelper = new GoogleOAuthHelper(signer);

    ////////////////////////////////////////////////////////////////////////////
    // STEP 3: Get the Authorization URL
    ////////////////////////////////////////////////////////////////////////////

    // Set the scope for this particular service.
    oauthParameters.setScope(SCOPES);

    // This method also makes a request to get the unauthorized request token,
    // and adds it to the oauthParameters object, along with the token secret
    // (if it is present).
    oauthHelper.getUnauthorizedRequestToken(oauthParameters);

    // Get the authorization url.  The user of your application must visit
    // this url in order to authorize with Google.  If you are building a
    // browser-based application, you can redirect the user to the authorization
    // url.
    String requestUrl = oauthHelper.createUserAuthorizationUrl(oauthParameters);
    System.out.println(requestUrl);
    System.out.println("Please visit the URL above to authorize your OAuth "
        + "request token.  Once that is complete, press any key to "
        + "continue...");
    System.in.read();

    ////////////////////////////////////////////////////////////////////////////
    // STEP 4: Get the Access Token
    ////////////////////////////////////////////////////////////////////////////

    // Once the user authorizes with Google, the request token can be exchanged
    // for a long-lived access token.  If you are building a browser-based
    // application, you should parse the incoming request token from the url and
    // set it in GoogleOAuthParameters before calling getAccessToken().
    String token = oauthHelper.getAccessToken(oauthParameters);
    System.out.println("OAuth Access Token: " + token);
    System.out.println();

    ////////////////////////////////////////////////////////////////////////////
    // STEP 5: Make an OAuth authorized request to Google
    ////////////////////////////////////////////////////////////////////////////

    // Initialize the variables needed to make the request
    URL feedUrl = new URL(variables.getFeedUrl());
    System.out.println("Sending request to " + feedUrl.toString());
    System.out.println();
    DocsService service =
        new DocsService("MyDocumentsListIntegration-v1");

    // Set the OAuth credentials which were obtained from the step above.
    service.setOAuthCredentials(oauthParameters, signer);

    // Make the request to Google
    // See other portions of this guide for code to put here...

    ////////////////////////////////////////////////////////////////////////////
    // STEP 6: Revoke the OAuth token
    ////////////////////////////////////////////////////////////////////////////

    System.out.println("Revoking OAuth Token...");
    oauthHelper.revokeToken(oauthParameters);
    System.out.println("OAuth Token revoked...");
  }
}

.NET

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      ////////////////////////////////////////////////////////////////////////////
      // STEP 1: Configure how to perform OAuth 1.0a
      ////////////////////////////////////////////////////////////////////////////

      // TODO: Update the following information with that obtained from
      // https://www.google.com/accounts/ManageDomains. After registering
      // your application, these will be provided for you.

      string CONSUMER_KEY = "yourappdomain.com";

      // This is the OAuth Consumer Secret retrieved
      // above.  Be sure to store this value securely.  Leaking this
      // value would enable others to act on behalf of your application!
      string CONSUMER_SECRET = "Gc0230jdsah01jqpowpgff";

      // Space separated list of scopes for which to request access.
      string SCOPE = "https://docs.google.com/feeds/ https://docs.googleusercontent.com/ https://spreadsheets.google.com/feeds/";

      ////////////////////////////////////////////////////////////////////////////
      // STEP 2: Set up the OAuth object
      ////////////////////////////////////////////////////////////////////////////

      // OAuthParameters holds all the parameters related to OAuth.
      OAuthParameters parameters = new OAuthParameters();

      // Set your OAuth Consumer Key (which you can register at
      // https://www.google.com/accounts/ManageDomains).
      parameters.ConsumerKey = CONSUMER_KEY;

      // Set your OAuth Consumer Secret, which can be obtained at
      // https://www.google.com/accounts/ManageDomains.
      parameters.ConsumerSecret = CONSUMER_SECRET;

      // HMAC-SHA1 is the only signature method supported by the .NET library.
      parameters.SignatureMethod = OAuthBase.HMACSHA1SignatureType;

      ////////////////////////////////////////////////////////////////////////////
      // STEP 3: Get the Authorization URL
      ////////////////////////////////////////////////////////////////////////////

      // Set the scope for this particular service.
      parameters.Scope = SCOPE;

      // This method also makes a request to get the unauthorized request token,
      // and adds it to the oauthParameters object, along with the token secret
      // (if it is present).
      OAuthUtil.GetUnauthorizedRequestToken(parameters);

      // Get the authorization url.  The user of your application must visit
      // this url in order to authorize with Google.  If you are building a
      // browser-based application, you can redirect the user to the authorization
      // url.
      string authorizationUrl = OAuthUtil.CreateUserAuthorizationUrl(parameters);
      Console.WriteLine(authorizationUrl);
      Console.WriteLine("Please visit the URL above to authorize your OAuth "
        + "request token.  Once that is complete, press any key to "
        + "continue...");
      Console.ReadLine();

      ////////////////////////////////////////////////////////////////////////////
      // STEP 4: Get the Access Token
      ////////////////////////////////////////////////////////////////////////////

      // Once the user authorizes with Google, the request token can be exchanged
      // for a long-lived access token.  If you are building a browser-based
      // application, you should parse the incoming request token from the url and
      // set it in OAuthParameters before calling GetAccessToken().
      OAuthUtil.GetAccessToken(parameters);
      string accessToken = parameters.Token;
      Console.WriteLine("OAuth Access Token: " + accessToken);

      ////////////////////////////////////////////////////////////////////////////
      // STEP 5: Make an OAuth authorized request to Google
      ////////////////////////////////////////////////////////////////////////////

      // Initialize the variables needed to make the request
      GOAuthRequestFactory requestFactory =
          new GOAuthRequestFactory(null, "MyDocumentsListIntegration-v1", parameters);
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
      service.RequestFactory = requestFactory;

      // Make the request to Google
      // See other portions of this guide for code to put here...
    }
  }
}

Authorizing requests with ClientLogin

ClientLogin allows applications to make requests to the Spreadsheets API using the username and application-specific password of a Google account. When using this mechanism, applications must take extreme caution when handling these credentials, as leaking the credentials could have severe consequences. Any application experiencing a security concern should immediately notify affected users.

To implement the ClientLogin mechanism, make an authorized request to the Spreadsheets API, with the appropriate Authorization header.

Protocol

Detailed information on implementing ClientLogin from a protocol perspective is available here.

When fetching a ClientLogin token for the Documents List API, be sure to use the writely service name.

Java

The following is a code sample in which a DocsService object is configured to use ClientLogin for authorization.

import com.google.gdata.client.docs.*;
import com.google.gdata.data.docs.*;
import com.google.gdata.util.*;

import java.io.IOException;
import java.net.*;

public class MyDocumentsListIntegration {
  public static void main(String[] args)
      throws AuthenticationException, MalformedURLException, IOException, ServiceException {

    String USERNAME = "someuser@gmail.com";
    String PASSWORD = "testing123";

    DocsService service = new DocsService("MyDocumentsListIntegration-v1");
    service.setUserCredentials(USERNAME, PASSWORD);

    // TODO: See other portions of this guide for code to put here...
  }
}

.NET

The following is a code sample in which a DocumentsService object is configured to use ClientLogin for authorization.

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      string USERNAME = "someuser@gmail.com";
      string PASSWORD = "testing123";

      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
      service.setUserCredentials(USERNAME, PASSWORD);

      // TODO: See other portions of this guide for code to put here...
    }
  }
}

Specifying a version

Every request that you send using version 3 of the API must specify that it is a version 3 request (version 2 is currently the default if you do not specify a version). You can skip this section if you are using the Java, Python, or .NET client libraries provided by Google, because those libraries automatically use version 3 of the API.

To specify a version number, use the GData-Version HTTP header. The value of this header must be 3.0. The decimal and the zero are required.

GData-Version: 3.0

Alternatively, you can specify v=3 as a query parameter in the URL. This is often needed when working behind a firewall that strips HTTP headers, or from some JavaScript requests. Use of the HTTP header is recommended when possible.

https://docs.google.com/feeds/default/private/full?v=3

Handling API errors

The Documents List API utilizes HTTP response codes to inform clients of the success or failure of each request. Clients should use the HTTP response code to trigger error handling if necessary (many errors can be resolved by retrying the request after a short delay). This section discusses various API error responses, and how to best handle them.

Suggested methods for handling various API responses

The following list represents the majority of cases clients encounter when using the API. Developers witnessing a response or error not listed here should post in the forum.

HTTP status code Description Resolution
200 A request succeeded. No error handling necessary.
201 A resource has been successfully created. No error handling necessary.
302 A request has been made to a resource's content link, and the requested data is on a different Google system. Make the same request again, but against the URI given in the response's Location header.
304 A conditional `GET` of a resource is requested, and the resource is unchanged. No error handling necessary.
400 A request has been made to a malformed URI. This error often impacts new users of the API, who forget to specify the GData-Version: 3.0 header. Modify the implementation of the client to make the request again to the correct URI, or specify the appropriate version header.
400 A request has been made with a malformed XML body. This is often caused by clients manually generating XML for requests, and not specifying some required XML namespaces. All sample requests in this guide show needed XML namespaces. Modify the implementation of the client to make the request again with valid XML.
400 A request has been made to upload a resource with content for conversion, but the conversion of the content failed. Reasons for conversion failure include the content being malformed, the content being well-formed but the API being unable to convert it, or conversion failing temporarily. Implement exponential backoff.
400 An unexpected error has occurred with the request. The occurrence of this situation is rare and almost never happens. Post in the forum. Before posting, please ensure the 400 response is not due to one of the reasons discussed above.
401 The given Authorization header is invalid, and the request is not authorized to continue. Modify the implementation of the client to provide a valid Authorization header. Developers implementing OAuth for the first time often have this problem. It is recommended to use one of the provided API client libraries instead, which automate many authorization mechanisms.
403 The authorized user is not permitted to make the given request. For example, the authorized user is not a writer on a resource, and therefore may not update the resource's content. Each client application must define an error handling strategy which fits their use case. It could make the request again as an authorized user, or add the already authorized user to the ACL of the resource.
404 The requested URI or resource does not exist. It is possible for this response to be given after a resource has been deleted. Each client application must define an error handling strategy which fits their use case. This could involve modifying the implementation to correct the URI or request the correct resource.
409, 412 The requested change to a resource conflicts with another change made by another API client or in a Google web UI. Fetch the resource, merge the conflicting changes, and make the request again with the latest ETag of the resource. Alternatively, force the change through, disregarding the other party's changes. Forcing the change through is described in Updating/changing documents and files.
411 A resumable upload request is made, but the Content-Length of the content being uploaded is not specified. Modify the client implementation to make the request with a valid Content-Length header.
500 An unexpected error has occurred in the API. This is probably a severe error. This response code is intended to indicate a temporary failure, so implementing exponential backoff is a reasonable error handling strategy for clients. If the problem persists, please post in the forum.
503 The client has made too many requests recently, or the requested API endpoint is temporarily unavailable. The API provides a minimum time in seconds within a Retry-After header that the client should wait before retrying the request. Implement exponential backoff.

Implementing exponential backoff

Exponential backoff is the process of a client periodically retrying a failed request over an increasing amount of time. It is a standard error handling strategy for network applications. The Documents List API is designed with the expectation that clients which choose to retry failed requests do so using exponential backoff. Besides being "required", using exponential backoff increases the efficiency of bandwidth usage, reduces the number of requests required to get a successful response, and maximizes the throughput of requests in concurrent environments.

The flow for implementing simple exponential backoff is as follows.

  1. Make a request to the API
  2. Receive a response indicating to retry the request
  3. Wait 1 + random_number_milliseconds seconds
  4. Retry request
  5. Receive a response indicating to retry the request
  6. Wait 2 + random_number_milliseconds seconds
  7. Retry request
  8. Receive a response indicating to retry the request
  9. Wait 4 + random_number_milliseconds seconds
  10. Retry request
  11. Receive a response indicating to retry the request
  12. Wait 8 + random_number_milliseconds seconds
  13. Retry request
  14. Receive a response indicating to retry the request
  15. Wait 16 + random_number_milliseconds seconds
  16. Retry request
  17. Stop. Report or log an error.

In the above flow, random_number_milliseconds is a random number of milliseconds less than or equal to 1000. This is necessary to avoid certain lock errors in some concurrent implementations. random_number_milliseconds must be redefined after each wait.

If the API response includes a Retry-After header providing a minimum wait time in seconds, clients should wait max(retry_after, computed_wait_time).

The algorithm is set to terminate when n is 5. This ceiling is in place only to stop clients from retrying infinitely, and results in a total delay of around 32 seconds before a request is deemed "an unrecoverable error".

The following Python code is an implementation of the above flow for recovering from errors when pulling the resources feed.

import random
import time
import gdata.client

def GetResourcesWithExponentialBackoff(client):
  """Gets all of the resources for the user authorized on the given client.

  Args:
    client: gdata.docs.client.DocsClient authorized for a user.
  Returns:
    gdata.docs.data.ResourceFeed representing Resources found in the request.
  """
  for n in range(0, 5):
    try:
      response = client.GetResources()
      return response
    except gdata.client.RequestError, error:
      computed_time = (2 ** n) + (random.randint(0, 1000) / 1000)
      time.sleep(max(error.headers.get('Retry-After'), computed_time))
    except:
      time.sleep((2 ** n) + (random.randint(0, 1000) / 1000))
  print "There has been an error, the request never succeeded."
  return None

Resource IDs explained

Every resource has a resource ID. As mentioned in the Terminology section, resource IDs have two forms: typed and untyped.

In an XML or JSON response from the API, the gd:resourceId element will always be a typed resource ID, like document:12345.

The types of typed resource IDs can include but are not limited to:

  • document (text document)
  • drawing
  • file
  • folder
  • pdf
  • presentation
  • spreadsheet

In a URL referring to an individual resource, you will sometimes see an untyped resource ID, like 12345.

Using Google Apps administrative access to impersonate other domain users

Usually, requests sent to the Documents List API are of the form:

https://docs.google.com/feeds/default/...

In this case, default indicates to the API that it should act as the currently authorized user (the default user). For 3-Legged OAuth, AuthSub, and ClientLogin, it is obvious who the currently authorized user is, because the authorization token is only valid for a single user. When using 2-Legged OAuth, the authorized user for a request is specified by the xoauth_requestor_id URL parameter. This is only supported for active (non-suspended) users. If a user is suspended, it is not possible to authorize requests as that specific user via a URL that specifies default.

Administrative users may make API requests that act on behalf of other users in the same domain by replacing default in the API URL with the username of the user to impersonate (e.g. user@yourdomain.com). In order to utilize this feature, the request must be authorized as an administrative user of the same domain (e.g. admin@yourdomain.com). When impersonating a user, it does not matter if the target user is suspended or not. It is assumed that the Google Apps admin is capable of logging in, unsuspending the user, and making the request. Because of this, we circumvent that step for you, and allow Google Apps admins to make requests on behalf of suspended users (for example to copy a suspended user's resources).

An example of replacing default with the email address of the intended user is:

https://docs.google.com/feeds/user@yourdomain.com/...

An example request URL to impersonate user@yourdomain.com while authorized as admin@yourdomain.com using 3-Legged OAuth, AuthSub, or ClientLogin is:

https://docs.google.com/feeds/user@yourdomain.com/private/full/

An example request URL to impersonate user@yourdomain.com while authorized as admin@yourdomain.com using 2-Legged OAuth is:

https://docs.google.com/feeds/user@yourdomain.com/private/full?xoauth_requestor_id=admin@yourdomain.com

Although an @ symbol is shown in the above examples for clarity, URLs must be encoded prior to sending them to the API. With the above examples, that means replacing @ with %40. An example encoded URL is:

https://docs.google.com/feeds/user%40yourdomain.com/private/full?xoauth_requestor_id=admin%40yourdomain.com

Getting general information about a user's account

The metadata feed is a read-only feed that provides information about the feature set available to a given user account. For example, it can provide the necessary information for your client to customize its UI elements according to the feature set of the user.

To access a user's metadata, send an HTTP GET to the following URI:

https://docs.google.com/feeds/metadata/<user-id>

Here, user-id is the user's Google account email address (user@example.com, user@gmail.com, etc.), or it is default if you want metadata for the currently authorized user. This value must be URL encoded. Most commonly, you'll use default:

https://docs.google.com/feeds/metadata/default

The response from the API includes a list of export formats supported by the API, quota information for the account, features available (and their request limits), maximum upload sizes, and additional roles supported by individual resource types. The following example is for a Google Apps for Business account:

Protocol

GET https://docs.google.com/feeds/metadata/default

<entry xmlns="http://www.w3.org/2005/Atom" xmlns:docs="http://schemas.google.com/docs/2007" xmlns:gAcl="http://schemas.google.com/acl/2007" xmlns:gd="http://schemas.google.com/g/2005" gd:etag="W/"CkcMQH0zcSt7ImA9WhdQF0w."">
  <id>https://docs.google.com/feeds/metadata/user%40example.com</id>
  <updated>2011-08-18T23:28:01.389Z</updated>
  <category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/docs/2007#metadata" label="metadata"/>
  <title>Document List User Metadata</title>
  <link rel="self" type="application/atom+xml" href="https://docs.google.com/feeds/metadata/user%40example.com"/>
  <author>
    <name>Some User</name>
    <email>user@example.com</email>
  </author>
  <gd:quotaBytesTotal>1073741824</gd:quotaBytesTotal>
  <gd:quotaBytesUsed>17936436</gd:quotaBytesUsed>
  <docs:quotaBytesUsedInTrash>0</docs:quotaBytesUsedInTrash>
  <docs:largestChangestamp value="101019"/>
  <docs:importFormat source="application/vnd.openxmlformats-officedocument.presentationml.presentation" target="presentation"/>
  <docs:importFormat source="application/vnd.ms-powerpoint" target="presentation"/>
  <docs:importFormat source="text/tab-separated-values" target="spreadsheet"/>
  <docs:importFormat source="image/gif" target="document"/>
  <docs:importFormat source="application/x-msmetafile" target="drawing"/>
  <docs:importFormat source="application/vnd.sun.xml.writer" target="document"/>
  <docs:importFormat source="image/png" target="document"/>
  <docs:importFormat source="application/vnd.ms-excel" target="spreadsheet"/>
  <docs:importFormat source="image/bmp" target="document"/>
  <docs:importFormat source="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" target="spreadsheet"/>
  <docs:importFormat source="application/rtf" target="document"/>
  <docs:importFormat source="application/msword" target="document"/>
  <docs:importFormat source="application/vnd.oasis.opendocument.text" target="document"/>
  <docs:importFormat source="text/plain" target="document"/>
  <docs:importFormat source="text/csv" target="spreadsheet"/>
  <docs:importFormat source="image/jpeg" target="document"/>
  <docs:importFormat source="application/x-vnd.oasis.opendocument.spreadsheet" target="spreadsheet"/>
  <docs:importFormat source="application/pdf" target="document"/>
  <docs:importFormat source="application/vnd.openxmlformats-officedocument.wordprocessingml.document" target="document"/>
  <docs:importFormat source="text/html" target="document"/>
  <docs:exportFormat source="drawing" target="image/png"/>
  <docs:exportFormat source="drawing" target="application/pdf"/>
  <docs:exportFormat source="drawing" target="image/jpeg"/>
  <docs:exportFormat source="document" target="application/msword"/>
  <docs:exportFormat source="drawing" target="image/svg+xml"/>
  <docs:exportFormat source="spreadsheet" target="application/pdf"/>
  <docs:exportFormat source="document" target="application/rtf"/>
  <docs:exportFormat source="spreadsheet" target="application/x-vnd.oasis.opendocument.spreadsheet"/>
  <docs:exportFormat source="presentation" target="text/plain"/>
  <docs:exportFormat source="document" target="application/pdf"/>
  <docs:exportFormat source="document" target="text/plain"/>
  <docs:exportFormat source="document" target="text/html"/>
  <docs:exportFormat source="presentation" target="application/vnd.ms-powerpoint"/>
  <docs:exportFormat source="spreadsheet" target="application/vnd.ms-excel"/>
  <docs:exportFormat source="document" target="application/vnd.oasis.opendocument.text"/>
  <docs:exportFormat source="document" target="text/rtf"/>
  <docs:exportFormat source="presentation" target="application/pdf"/>
  <docs:feature>
    <docs:featureName>ocr</docs:featureName>
  </docs:feature>
  <docs:feature>
    <docs:featureName>translation</docs:featureName>
    <docs:featureRate>2.0</docs:featureRate>
  </docs:feature>
  <docs:feature>
    <docs:featureName>upload_any</docs:featureName>
  </docs:feature>
  <docs:maxUploadSize kind="document">26214400</docs:maxUploadSize>
  <docs:maxUploadSize kind="spreadsheet">10485760</docs:maxUploadSize>
  <docs:maxUploadSize kind="presentation">10485760</docs:maxUploadSize>
  <docs:maxUploadSize kind="drawing">2097152</docs:maxUploadSize>
  <docs:maxUploadSize kind="pdf">10737418240</docs:maxUploadSize>
  <docs:maxUploadSize kind="file">10737418240</docs:maxUploadSize>
  <!-- The document resource type supports the additionalRoleSets given within. -->
  <docs:additionalRoleInfo kind="document">
    <!-- The reader role supports all additionalRoles given within. -->
    <docs:additionalRoleSet primaryRole="reader">
      <!-- Readers of text document resources are also able to comment on said
      resources if the relevant additionalRole is provided in an ACL entry. -->
      <gAcl:additionalRole value="commenter"/>
    </docs:additionalRoleSet>
  </docs:additionalRoleInfo>
</entry>

.NET

The following code fetches the feature set available to the currently authenticated user's account, and prints out the quota information and the list of supported import formats.

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a MetadataQuery object to retrieve metadata.
      MetadataQuery query = new MetadataQuery();

      // Make a request to the API and get all information.
      MetadataFeed feed = service.Query(query);

      if (feed.Entries.Count == 0)
      {
        throw new Exception("The metadata feed should always contain an entry");
      }

      // The metadata feed contains a single entry
      MetadataEntry entry = (MetadataEntry)feed.Entries[0];

      // Print quota information to the screen
      Console.WriteLine(entry.QuotaBytesUsed);
      Console.WriteLine(entry.QuotaBytesTotal);

      // Iterate through all of the supported import formats
      foreach (ConversionFormat format in entry.ImportFormats)
      {
        // Print the source and target formats
        Console.WriteLine(format.Source + " -> " + format.Target);
      }
    }
  }
}

The metadata feed has some optional parameters used by clients to determine the fastest way to reset a local cache. In some environments, like a mobile environment, both space and bandwidth may be limited. In these environments, a local cache consists of a small number of resources. This cache often represents the last X resources that were changed. Resources not tracked within the cache are found using some other mechanism, such as a search query.

One design consideration clients make in these environments involves the fact that the changes feed is FIFO, where as the main resources feed is LIFO. Thus, clients in these environments are often left with the question: "what is the fastest way to get the current state of the last X resources?" Is it to pull all changes from the changes feed, up to the latest change? Or, is it to pull X resources from the main resources feed? The former method is faster for small change sets. The latter method is faster for large changes sets, for instance if a client has not synced in a long time.

The metadata feed is used to answer this question. Given a changestamp and a limit, the metadata feed yields the number of changestamps since the given changestamp, up to the given limit.

Protocol

GET https://docs.google.com/feeds/metadata/default?remaining-changestamps-first=[changestamp-plus-one]&remaining-changestamps-limit=500

<entry xmlns="http://www.w3.org/2005/Atom"
    xmlns:docs="http://schemas.google.com/docs/2007"
    xmlns:gAcl="http://schemas.google.com/acl/2007"
    xmlns:gd="http://schemas.google.com/g/2005"
    gd:etag="W/"CkcMQH0zcSt7ImA9WhdQF0w."">
  ...
  <docs:remainingChangestamps>344</docs:remainingChangestamps>
  ...
</entry>

.NET

The following code fetches the number of changestamps since changestamp 100, up to 500 changestamps.

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a MetadataQuery object to retrieve metadata.
      MetadataQuery query = new MetadataQuery();

      // Set the RemainingChangestampsFirst parameter.
      query.RemainingChangestampsFirst = 100;

      // Set the RemainingChangestampsLimit parameter.
      query.RemainingChangestampsLimit = 500;

      // Make a request to the API and get all information.
      MetadataFeed feed = service.Query(query);

      if (feed.Entries.Count == 0)
      {
        throw new Exception("The metadata feed should always contain an entry");
      }

      // The metadata feed contains a single entry
      MetadataEntry entry = (MetadataEntry)feed.Entries[0];

      // Print the number of remaining changestamps to the screen
      Console.WriteLine(entry.RemainingChangestamps);
  }
}

Providing the remaining-changestamps-first parameter causes the metadata feed to return the number of changestamps since the given changestamp, including the given changestamp. Thus, to get the number of changestamps since a given changestamp, clients must provide the last synced changestamp, plus one.

Using this mechanism of the metadata feed can increase the latency of a metadata feed request. To minimize this latency, clients are required to provide the remaining-changestamps-limit parameter. This parameter gives an upper bound to the value returned in docs:remainingChangestamps. The previous example indicates 344 changes since the given changestamp, because the given remaining-changestamps-limit is 500. The following example, assuming the same environment and changestamp are provided, indicates only 10 changes since the given changestamp, because of the lower remaining-changestamps-limit value. Technically, the following example yields a response more quickly than the previous example.

GET https://docs.google.com/feeds/metadata/default?remaining-changestamps-first=[changestamp-plus-one]&remaining-changestamps-limit=10

<entry xmlns="http://www.w3.org/2005/Atom"
    xmlns:docs="http://schemas.google.com/docs/2007"
    xmlns:gAcl="http://schemas.google.com/acl/2007"
    xmlns:gd="http://schemas.google.com/g/2005"
    gd:etag="W/"CkcMQH0zcSt7ImA9WhdQF0w."">
  ...
  <docs:remainingChangestamps>10</docs:remainingChangestamps>
  ...
</entry>

Once a client obtains the docs:remainingChangestamps value, the client decides whether to iterate over everything returned by the changes feed, or to reset the local cache by pulling X resources from the main resources feed. If there are a small number of changes, clients in a limited environment should use the changes feed. If there are a large number of changes, said clients should use the main resources feed. The definitions of small and large are up to clients, as performance needs vary in each specific environment.

Detecting changes to resources

The changes feed is a read-only feed that provides information about all changes to all resources, including resources that have been shared with a user. The feed works by providing the current state of each resource, if and only if the resource has changed since the given changestamp.

For example, to detect changes to resources for synchronization with another data source, query the changes feed to detect the current state of resources that have changed.

The changes feed provides a more efficient way to detect changes to resources. Previously, developers polled all resources from a user's account repeatedly, which was inefficient and resource-intensive. The changes feed addresses these problems, and now developers must collect less data from the API to detect updates.

Using changestamps to identify changes

The concept of a changestamp is important to understand in order to use the changes feed. A changestamp is a unique, monotonically increasing integer representing each change to a user's documents list. Each entry in the feed has a changestamp value that uniquely and globally identifies a specific change to the relevant resource. Developers must store the value of the latest changestamp consumed by their application, and then query the API from that changestamp in the future. This process is repeated over time to detect changes. This ensures an application never receives the same change twice from the API. The exact URL structure for using changestamps is discussed below.

A given changestamp is only valid until the associated resource is changed again. Once a resource changes, all previous changestamps for the resource become invalid. This results in gaps between changestamps when the changes feed is pulled. To detect if a specific resource has changed, GET the self link of the change. A 404 response to this request indicates that the resource has since changed; a new changestamp is now associated with the resource and the original changestamp is no longer valid. Otherwise, the change entry is returned.

Retrieving changes for a user

Entries in the changes feed are ordered in ascending chronological order. That is, the oldest changes show up first. To collect all changes, follow all next links in the returned feed until there is no next link returned.

To access a user's changes feed, send an HTTP GET to the following URI:

https://docs.google.com/feeds/<user-id>/private/changes

Here, user-id is the user's Google account email address (user@example.com, user@gmail.com, etc.), or it is default if you want changes for the currently authorized user. This value must be URL encoded. Most commonly, you'll use default:

https://docs.google.com/feeds/default/private/changes

The response from the API includes a GData feed of change entries. A change entry is exactly like a normal resource entry from /feeds/default/private/full, except it also contains a docs:changestamp field and possibly a docs:removed field.

Protocol

GET https://docs.google.com/feeds/default/private/changes

<?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:docs="http://schemas.google.com/docs/2007" xmlns:gd="http://schemas.google.com/g/2005"
    gd:etag="W/"DEEMQ3w8eyt7ImA9WhZUGUo."">
  <id>https://docs.google.com/feeds/default/private/changes</id>
  <updated>2011-06-13T14:51:22.273Z</updated>
  <category scheme="http://schemas.google.com/g/2005#kind"
      term="http://schemas.google.com/docs/2007#change" label="change"/>
  <title>Changed Documents - joe.smith@example.com</title>

  <!-- Largest changestamp for the currently authorized user. -->
  <!-- This value is also given in the Metadata feed. -->
  <docs:largestChangestamp value="5635"/>

  <!-- Follow this to get the next set of changes. -->
  <!-- If this is not provided, there are no additional changes at the current time. -->
  <link rel="next" type="application/atom+xml"
      href="https://docs.google.com/feeds/default/private/changes?start-index=5636"/>

  <link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"
      href="https://docs.google.com/feeds/default/private/changes"/>
  <link rel="self" type="application/atom+xml"
      href="https://docs.google.com/feeds/default/private/changes?start-index=5620"/>
  <author>
    <name>joe.smith</name>
    <email>joe.smith@example.com</email>
  </author>
  <openSearch:totalResults>5635</openSearch:totalResults>
  <openSearch:startIndex>5620</openSearch:startIndex>

  <!-- This change represents a document being permanently deleted. -->
  <entry gd:etag="W/"DUcMRHg5cCt7ImA9WhZUGUo."">
    <id>https://docs.google.com/feeds/id/unknown%3A1H38bELcnXOWXL8eRZYAP4XvfR_EpEu_AJ1GZNJb9-N-4</id>
    <updated>2011-06-13T14:58:05.628Z</updated>

    <!-- Label representing that this is a change entry. -->
    <category scheme="http://schemas.google.com/g/2005#kind"
    term="http://schemas.google.com/docs/2007#change" label="change"/>

    <!-- docs:removed means this is change is a permanent deletion.  Use this to detect deletes. -->
    <!-- This field does NOT mean this resource was trashed.  To identify trashed resources, use the gd:deleted tag. -->
    <docs:removed/>

    <!-- Title is unknown because this change is a deletion. -->
    <title>Unknown</title>

    <!-- Content link is empty because this change is a deletion. -->
    <content/>

    <link rel="self" type="application/atom+xml"
        href="https://docs.google.com/feeds/default/private/changes/5623"/>

    <!-- Author is unknown because this change is a deletion. -->
    <author>
      <name>Unknown</name>
    </author>

    <!-- Resource type is unknown because this change is a deletion. -->
    <gd:resourceId>unknown:1H38bELcnXOWXL8eRZYAP4XvfR_EpEu_AJ1GZNJb9-N-4</gd:resourceId>

    <!-- Unique identifier for this change.  Store this to query again in the future. -->
    <docs:changestamp value="5623"/>
  </entry>

  <!-- This change represents a document being permanently deleted. -->
  <entry gd:etag="W/"DUYEQH85cCt7ImA9WhZUGUo."">
    <id>https://docs.google.com/feeds/id/unknown%3A17vRlM9HeTv_V03nxDXXnl9QvY-sL53e4tbiE0-5xD7e4</id>
    <updated>2011-06-13T14:58:21.128Z</updated>
    <category scheme="http://schemas.google.com/g/2005#kind"
        term="http://schemas.google.com/docs/2007#change" label="change"/>
    <title>Unknown</title>
    <content/>
    <link rel="self" type="application/atom+xml"
        href="https://docs.google.com/feeds/default/private/changes/5630"/>
    <author>
      <name>Unknown</name>
    </author>
    <gd:resourceId>unknown:17vRlM9HeTv_V03nxDXXnl9QvY-sL53e4tbiE0-5xD7e4</gd:resourceId>
    <docs:removed/>
    <docs:changestamp value="5630"/>
  </entry>

  <!-- This change represents a document being created. -->
  <entry gd:etag=""BlAIEQdOHCt7ImBr"">
    <id>https://docs.google.com/feeds/id/document%3A1DJ1Qrt_N41aX1nDxxo0QHs5XIM90zTT-seYG2FYxrRk</id>
    <published>2011-06-13T15:05:37.544Z</published>
    <updated>2011-06-13T15:05:38.108Z</updated>
    <app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-13T15:05:38.456Z</app:edited>
    <category scheme="http://schemas.google.com/g/2005#kind"
        term="http://schemas.google.com/docs/2007#document" label="document"/>
    <category scheme="http://schemas.google.com/g/2005/labels"
        term="http://schemas.google.com/g/2005/labels#viewed" label="viewed"/>
    <title>Meeting Notes</title>
    <content type="text/html"
        src="https://docs.google.com/feeds/download/documents/export/Export?id=1DJ1Qrt_N41aX1nDxxo0QHs5XIM90zTT-seYG2FYxrRk"/>
    <link rel="alternate" type="text/html"
        href="https://docs.google.com/a/example.com/document/d/1DJ1Qrt_N41aX1nDxxo0QHs5XIM90zTT-seYG2FYxrRk/edit?hl=en_US"/>
    <link rel="http://schemas.google.com/g/2005#resumable-edit-media" type="application/atom+xml"
        href="https://docs.google.com/feeds/upload/create-session/default/private/full/document%3A1DJ1Qrt_N41aX1nDxxo0QHs5XIM90zTT-seYG2FYxrRk"/>
    <link rel="http://schemas.google.com/docs/2007/thumbnail" type="image/jpeg"
        href="https://lh5.googleusercontent.com/u7NNUBIcKwb74epx_cb5ff_UoJDo5wm5M9zVRZq33qDfTnJyYo98uvP1CYI6hkEGFzEzG_QwqnLOabNkAg=s220"/>
    <link rel="edit" type="application/atom+xml"
        href="https://docs.google.com/feeds/default/private/full/document%3A1DJ1Qrt_N41aX1nDxxo0QHs5XIM90zTT-seYG2FYxrRk"/>
    <link rel="edit-media" type="text/html"
        href="https://docs.google.com/feeds/default/media/document%3A1DJ1Qrt_N41aX1nDxxo0QHs5XIM90zTT-seYG2FYxrRk"/>
    <link rel="self" type="application/atom+xml"
        href="https://docs.google.com/feeds/default/private/changes/5635"/>
    <author>
      <name>joe.smith</name>
      <email>joe.smith@example.com</email>
    </author>
    <gd:resourceId>document:1DJ1Qrt_N41aX1nDxxo0QHs5XIM90zTT-seYG2FYxrRk</gd:resourceId>
    <gd:lastModifiedBy>
      <name>joe.smith</name>
      <email>joe.smith@example.com</email>
    </gd:lastModifiedBy>
    <gd:lastViewed>2011-06-13T15:05:38.108Z</gd:lastViewed>
    <gd:quotaBytesUsed>0</gd:quotaBytesUsed>
    <docs:writersCanInvite value="true"/>
    <docs:changestamp value="5635"/>
    <gd:feedLink rel="http://schemas.google.com/acl/2007#accessControlList"
        href="https://docs.google.com/feeds/default/private/full/document%3A1DJ1Qrt_N41aX1nDxxo0QHs5XIM90zTT-seYG2FYxrRk/acl"/>
    <gd:feedLink rel="http://schemas.google.com/docs/2007/revisions"
        href="https://docs.google.com/feeds/default/private/full/document%3A1DJ1Qrt_N41aX1nDxxo0QHs5XIM90zTT-seYG2FYxrRk/revisions"/>
  </entry>

...
</feed>

.NET

The following code fetches a list of the currently authenticated user's changes, and prints out the title and changestamp of each of them.

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a ChangesQuery object to retrieve changes.
      ChangesQuery query = new ChangesQuery();

      // Make a request to the API and get all changes.
      ChangesFeed feed = service.Query(query);

      // Iterate through all of the changes returned
      foreach (ChangeEntry entry in feed.Entries)
      {
        // Print the title and changestamp of this document to the screen
        Console.WriteLine(entry.Title.Text);
        Console.WriteLine(entry.Changestamp);
      }
    }
  }
}

After pulling the changes feed, the feed may or may not contain a next link. If the next link is present, it may be used to gather the next set of changes. If the next link is not present, the client application should store the changestamp of the last entry in the feed for future use. Changes in the feed are given in ascending chronological order, so the last change in the last page of the feed is the most recent change.

Retrieving all changes since a given changestamp

With the latest changestamp stored, the client application is prepared to query again for changes in the future. The next time the application queries for changes, it should use this URI:

https://docs.google.com/feeds/default/private/changes?start-index=[changestamp-plus-one]

Replace [changestamp-plus-one] with the latest stored changestamp, plus one. If the latest stored changestamp is 4351, then send 4352 here. This guarantees that in the next request to the feed, an application does not also receive a change received previously.

Protocol

GET https://docs.google.com/feeds/default/private/changes?start-index=4352

.NET

The following code fetches a list of the currently authenticated user's changes, starting from change 4352, and prints out the title and changestamp of each of them.

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a ChangesQuery object to retrieve changes.
      ChangesQuery query = new ChangesQuery();

      // Set the StartIndex parameter.
      query.StartIndex = 4352;

      // Make a request to the API and get all changes.
      ChangesFeed feed = service.Query(query);

      // Iterate through all of the changes returned
      foreach (ChangeEntry entry in feed.Entries)
      {
        // Print the title and changestamp of this document to the screen
        Console.WriteLine(entry.Title.Text);
        Console.WriteLine(entry.Changestamp);
      }
    }
  }
}

Retrieving fewer changes per request

By default, the changes feed returns at most 100 changes. An application can request up to 1000 changes per request. Also, if an application needs to receive less data at once, for instance in a mobile setting, it can request fewer changes. To change the number of changes returned, set the max-results GET parameter to a number less than or equal to 1000.

Protocol

GET https://docs.google.com/feeds/default/private/changes?start-index=[changestamp-plus-one]&max-results=900

.NET

The following code fetches a list of up to 900 of the currently authenticated user's changes, starting from change 4352, and prints out the title and changestamp of each of them.

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a ChangesQuery object to retrieve changes.
      ChangesQuery query = new ChangesQuery();

      // Set the StartIndex parameter.
      query.StartIndex = 4352;

      // Set the NumberToRetrieve parameter.
      query.NumberToRetrieve = 900;

      // Make a request to the API and get all changes.
      ChangesFeed feed = service.Query(query);

      // Iterate through all of the changes returned
      foreach (ChangeEntry entry in feed.Entries)
      {
        // Print the title and changestamp of this document to the screen
        Console.WriteLine(entry.Title.Text);
        Console.WriteLine(entry.Changestamp);
      }
    }
  }
}

Showing the root collection as a parent in change entries

Just like the main Documents List API feed, the changes feed supports the showroot query parameter. This parameter causes the root collection to be shown as a parent of any resource in the changes feed that has the root collection as a parent. For more information, see Determining which resources are in the root collection.

Retrieving ACL information for each change in the same request

The changes feed has a special parameter, expand-acl, that expands the ACL of each resource returned in the feed if set to true. As changes may show up in the feed because of an ACL change, this can be particularly useful to applications.

GET https://docs.google.com/feeds/default/private/changes?start-index=[changestamp-plus-one]&expand-acl=true

Protocol

https://docs.google.com/feeds/default/private/changes?start-index=[changestamp-plus-one]&expand-acl=true

.NET

The following code fetches a list of the currently authenticated user's changes, starting from change 4352 and with expanded ACL, and prints out the title and changestamp of each of them.

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a ChangesQuery object to retrieve changes.
      ChangesQuery query = new ChangesQuery();

      // Set the StartIndex parameter.
      query.StartIndex = 4352;

      // Set the ExpandAcl parameter.
      query.ExpandAcl = true;

      // Make a request to the API and get all changes.
      ChangesFeed feed = service.Query(query);

      // Iterate through all of the changes returned
      foreach (ChangeEntry entry in feed.Entries)
      {
        // Print the title and changestamp of this document to the screen
        Console.WriteLine(entry.Title.Text);
        Console.WriteLine(entry.Changestamp);
      }
    }
  }
}

Changes representing a deletion

Changes that represent a deletion have a typed resource ID in which the original type is replaced with unknown. For example, if there is a document with a typed resource ID of document:1234abcd, and this document is permanently deleted, a change entry is created. The change entry has a resource ID of unknown:1234abcd. Note that the untyped resource ID does not change after resource deletion. In the previous example, the untyped resource ID remains 1234abcd.

Getting profile information for users

Throughout the API, there are a number of places in which information about a specific user is returned. By default, this information is limited to an email address, and the first portion of the email address before the @.

Applications requiring additional information on these users can ask the API to add public profile information for the users if it is available. If available, the API adds a link to the primary public photo of the relevant user's Google account. This is requested by appending include-profile-info=true to any request that may return user information, including the changes feed, resources feed, ACL feed, etc.

Protocol

GET https://docs.google.com/feeds/default/private/full?include-profile-info=true

...
<entry>
  ...
  <gd:lastModifiedBy>
    <name>Joe Smith</name>
    <uri>https://lh5.googleusercontent.com/-4IL6021224n0/AAAAAAI/AAREAAAA/rc12312LidA/photo.jpg</uri>
    <email>joe.smith.test@gmail.com</email>
  </gd:lastModifiedBy>
  ...
</entry>
...

.NET

The following code fetches a list of the currently authenticated user's documents, and prints out the email address of the user who last modified each of them.

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a DocumentsListQuery object to retrieve documents.
      DocumentsListQuery query = new DocumentsListQuery();

      // Set the IncludeProfileInfo parameter.
      query.IncludeProfileInfo = true;

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      // Iterate through all of the documents returned
      foreach (DocumentEntry entry in feed.Entries)
      {
        // Print the email address of the user who last modified the document.
        Console.WriteLine(entry.LastModified.EMail);
      }
    }
  }
}

Managing document and file metadata and content

The Documents List API has a primary feed for working with documents and files. This feed is exposed at the following URL.

https://docs.google.com/feeds/default/private/full

The following sections discuss how this URL, or some variation of it, can be used to manage resources.

Getting a list of documents and files

Protocol

You can get a feed containing a list of the currently authenticated user's documents and files by sending an authorized GET request to the following URL:

https://docs.google.com/feeds/default/private/full

The result is a feed that lists the user's documents and files; each entry in the feed represents a resource associated with the user.

The result will look something like this (comments have been added for clarity):

<feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/"
      xmlns:docs="http://schemas.google.com/docs/2007" xmlns:batch="http://schemas.google.com/gdata/batch"
      xmlns:gd="http://schemas.google.com/g/2005" gd:etag="W/&quot;DUMFR3YyfCt7ImA9WxNTFU0.&quot;">

  <!-- Unique identifier of this feed.  Not unique between users. -->
  <id>https://docs.google.com/feeds/default/private/full</id>

  <!-- Date this feed was last updated.  Do NOT use this, provided for Atom compliance only. -->
  <updated>2009-08-17T11:10:16.894Z</updated>

  <!-- Title of this feed result. -->
  <title>Available Documents - john.smith.example@gmail.com</title>

  <!-- Link at which a user could consume the same content given here, but in a web browser with a user interface. -->
  <link rel="alternate" type="text/html" href="https://docs.google.com"/>

  <!-- Link at which you can add documents or files using resumable upload. -->
  <link rel="http://schemas.google.com/g/2005#resumable-create-media" type="application/atom+xml"
      href="https://docs.google.com/feeds/upload/create-session/default/private/full"/>

  <!-- Link at which you can fetch the next page of results from this feed. -->
  <link rel="next" type="application/atom+xml"
      href="https://docs.google.com/feeds/default/private/full?start-key=EAEaFgoSCb2YGEPMAAACAG"/>

  <!-- Link at which you can fetch this same feed. -->
  <link rel="self" type="application/atom+xml"
      href="https://docs.google.com/feeds/default/private/full/"/>

  <!-- Link at which you can fetch this same feed. -->
  <link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"
      href="https://docs.google.com/feeds/default/private/full"/>

  <!-- Deprecated.  Use resumable-create-media instead. -->
  <!-- Link at which you can POST new entries with metadata only to this feed. -->
  <link rel="http://schemas.google.com/g/2005#post" type="application/atom+xml"
      href="https://docs.google.com/feeds/default/private/full"/>

  <!-- Link at which you can send batch requests to this feed. -->
  <link rel="http://schemas.google.com/g/2005#batch" type="application/atom+xml"
      href="https://docs.google.com/feeds/default/private/full/batch"/>

  <!-- Information about the user who authorized this request. -->
  <author>
    <name>John Smith</name>
    <email>john.smith.example@gmail.com</email>
  </author>

  <!-- NOT supported, provided for protocol compliance only. -->
  <openSearch:startIndex>1</openSearch:startIndex>

  <!-- The ETag here is used to identify the version of this entry. -->
  <entry gd:etag="'EVJVTBICRit7ImBq'">

    <!-- A unique, permanent identifier for this entry. -->
    <id>https://docs.google.com/feeds/id/document%3A12345</id>

    <!-- Title of this resource. -->
    <title>2010 Income Tax Policy</title>

    <!-- Description of this resource (currently visible in the preview pane in the UI). -->
    <docs:description>Describes how to file income tax for 2010.</docs:description>

    <!-- Resource ID of this document. -->
    <gd:resourceId>document:12345</gd:resourceId>

    <!-- Date this document was created (the "published" name of this element is mis-leading, but this is Atom standard). -->
    <published>2009-07-22T19:02:57.616Z</published>

    <!-- Information about the owner of this document (not necessarily the user authorizing this request). -->
    <author>
      <name>Jenna Dolsom</name>
      <email>jenna.dolsom.example@gmail.com</email>
    </author>

    <!-- Date this entry was last updated (either by Google's systems, the API, or a user in a web browser). -->
    <updated>2009-07-29T20:31:39.804Z</updated>

    <!-- Date this document was last edited by a user in the document editor in a web browser. -->
    <app:edited xmlns:app="http://www.w3.org/2007/app">2009-07-31T17:21:26.497Z</app:edited>

    <!-- Information about the user who last modified this entry (not necessarily the user authorizing this request). -->
    <gd:lastModifiedBy>
      <name>Aaron Jensen</name>
      <email>aaron.jensen.example@gmail.com</email>
    </gd:lastModifiedBy>

    <!-- Date this document was last viewed in a web browser by any user. -->
    <gd:lastViewed>2009-07-31T17:21:26.273Z</gd:lastViewed>

    <!-- The "kind" of this entry.  In this case, a word processing document. -->
    <category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/docs/2007#document" label="document"/>

    <!-- This entry has been viewed by the user, so it has a "viewed" category. -->
    <category scheme="http://schemas.google.com/g/2005/labels" term="http://schemas.google.com/g/2005/labels#viewed" label="viewed"/>

    <!-- Link at which you can download the actual document this entry describes. -->
    <content type="text/html" src="https://docs.google.com/feeds/download/documents/Export?docId=12345"/>

    <!-- This document is in one collection, detailed here. -->
    <link rel="http://schemas.google.com/docs/2007#parent" type="application/atom+xml"
        href="https://docs.google.com/feeds/default/private/full/folder%3A12345" title="ACollectionName"/>

    <!-- Link at which you can open this document in a web browser. -->
    <link rel="alternate" type="text/html" href="https://docs.google.com/Doc?docid=12345&amp;hl=en"/>

    <!-- Link at which you can fetch only this entry. -->
    <link rel="self" type="application/atom+xml" href="https://docs.google.com/feeds/default/private/full/document%3A12345"/>

    <!-- Link at which you can PUT updates to this entry. -->
    <link rel="edit" type="application/atom+xml" href="https://docs.google.com/feeds/default/private/full/document%3A12345"/>

    <!-- Link at which you can PUT updates to this entry's content (deprecated, use resumable below). -->
    <link rel="edit-media" type="text/html" href="https://docs.google.com/feeds/default/media/document%3A12345"/>

    <!-- Link at which you can PUT resumable updates to this entry's content. -->
    <link rel="http://schemas.google.com/g/2005#resumable-edit-media" type="application/atom+xml"
        href="https://docs.google.com/feeds/upload/create-session/default/private/full/document%3A12345"/>

    <!-- Link at which you can fetch a thumbnail of this resource. -->
    <link rel="http://schemas.google.com/docs/2007/thumbnail" type="image/jpeg" href="https://lh3.googleusercontent.com/TQRs812345=s220"/>

    <!-- Link at which you can create, retrieve, update, and delete ACL entries for this document. -->
    <gd:feedLink rel="http://schemas.google.com/acl/2007#accessControlList"
         href="https://docs.google.com/feeds/default/private/full/document%3A12345/acl"/>

    <!-- Link at which you can create, retrieve, update, and delete revisions of this document. -->
    <gd:feedLink rel="http://schemas.google.com/docs/2007/revisions"
         href="https://docs.google.com/feeds/default/private/full/document%3A12345/revisions"/>

    <!-- Number of bytes of the owner's quota this document uses.  Native Google Docs currently use 0 bytes. -->
    <gd:quotaBytesUsed>0</gd:quotaBytesUsed>

    <!-- "true" if writers can invite other users to view and edit this document. -->
    <docs:writersCanInvite value="true"/>

    <!-- Given for files only. An MD5 checksum used to verify the contents of this file. -->
    <!-- Some old files are being processed. Those files will not have this element yet. -->
    <docs:md5Checksum>2b01142f7481c7b056c4b410d28f33cf</docs:md5Checksum>

    <!-- Original filename of file at time of upload, if available. -->
    <!-- Only available for resources of type file or pdf. -->
    <!-- Shown here as example only. This element is not given for resources of type document. -->
    <docs:filename>MyFile.pdf</docs:filename>

    <!-- Current name of resource, with file extension from docs:filename appended, if available. -->
    <!-- If the current name already has an extension, then the extension from docs:filename is not appended. -->
    <!-- If docs:filename does not have an extension, then the current name is given unaltered. -->
    <!-- Only available for resources of type file or pdf. -->
    <!-- Shown here as example only. This element is not given for resources of type document. -->
    <docs:suggestedFilename>TaxDocument.pdf</docs:suggestedFilename>
  </entry>
  <entry xmlns:gd="http://schemas.google.com/g/2005" gd:etag="'HhJSFgpeRyt7ImBq'">
    <id>https://docs.google.com/feeds/id/pdf%3A12345</id>
    <published>2009-04-09T18:23:09.035Z</published>
    <updated>2009-04-09T18:23:09.035Z</updated>
    <app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-18T22:16:02.388Z</app:edited>
    <category scheme="http://schemas.google.com/g/2005/labels" term="http://schemas.google.com/g/2005/labels#starred" label="starred"/>
    <category scheme="http://schemas.google.com/g/2005/labels" term="http://schemas.google.com/g/2005/labels#viewed" label="viewed"/>
    <category scheme="http://schemas.google.com/g/2005/labels" term="http://schemas.google.com/g/2005/labels#hidden" label="hidden"/>
    <category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/docs/2007#pdf" label="pdf"/>
    <title>PDF's Title</title>
    <content type="application/pdf"
         src="https://doc-04-20-docs.googleusercontent.com/docs/secure/m71240...U1?h=1630126&amp;e=download&amp;gd=true"/>
    <link rel="alternate" type="text/html" href="https://docs.google.com/fileview?id=12345&amp;hl=en"/>
    <link rel="self" type="application/atom+xml" href="https://docs.google.com/feeds/default/private/full/pdf%3A12345"/>
    <link rel="edit" type="application/atom+xml" href="https://docs.google.com/feeds/default/private/full/pdf%3A12345"/>
    <link rel="edit-media" type="application/pdf" href="https://docs.google.com/feeds/default/media/pdf%3A12345"/>
    <link rel="http://schemas.google.com/g/2005#resumable-edit-media" type="application/atom+xml"
        href="https://docs.google.com/feeds/upload/create-session/default/private/full/pdf%3A12345"/>
    <author>
      <name>user</name>
      <email>user@gmail.com</email>
    </author>
    <gd:resourceId>pdf:12345</gd:resourceId>
    <gd:lastModifiedBy>
      <name>user</name>
      <email>user@gmail.com</email>
    </gd:lastModifiedBy>
    <gd:lastViewed>2009-06-18T22:16:02.384Z</gd:lastViewed>
    <gd:quotaBytesUsed>108538</gd:quotaBytesUsed>
    <docs:writersCanInvite value="false"/>
    <docs:md5Checksum>2b01142f7481c7b056c4b410d28f33cf</docs:md5Checksum>
    <gd:feedLink rel="http://schemas.google.com/acl/2007#accessControlList"
         href="https://docs.google.com/feeds/default/private/full/pdf%3A12345/acl"/>
    <gd:feedLink rel="http://schemas.google.com/docs/2007/revisions"
         href="https://docs.google.com/feeds/default/private/full/document%3A12345/revisions"/>
  </entry>
  ...
</feed>

By default the API will return the first 100 documents and files in the user's resource list. This saves bandwidth and improves performance. To request more or less than 100 resources, use the max-results GET parameter with any resources feed URL. Valid values for this parameter are integers from 1 to 1000, inclusive.

https://docs.google.com/feeds/default/private/full?max-results=1000

To include ACL information in this feed response, replace default with expandAcl in the request URI.

https://docs.google.com/feeds/expandAcl/private/full

.NET

The following code fetches a list of the currently authenticated user's documents, and prints out the title of each of them.

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a DocumentsListQuery object to retrieve documents.
      DocumentsListQuery query = new DocumentsListQuery();

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      // Iterate through all of the documents returned
      foreach (DocumentEntry entry in feed.Entries)
      {
        // Print the title of this document to the screen
        Console.WriteLine(entry.Title.Text);
      }
    }
  }
}

Parameter reference for resources collection URI

Parameter Meaning Notes
title Specifies the search terms for the title of a document. This parameter used without title-exact will only submit partial queries, not exact queries.
title-exact Specifies whether the title query should be taken as an exact string. Meaningless without title. Possible values are true and false.
Note: Matches are case-insensitive.
opened-min Lower bound on the last time a document was opened by the current user. Use the RFC 3339 timestamp format. For example: opened-min=2005-08-09T09:57:00-08:00
opened-max Upper bound on the last time a document was opened by the current user. Use the RFC 3339 timestamp format. For example: opened-max=2009-03-02T10:00:00
edited-min Lower bound on the last time a document was edited by the current user. This value corresponds to the <app:edited> value in the Atom entry, which represents changes to the document's content or metadata. Use the RFC 3339 timestamp format. For example: edited-min=2005-08-09T09:57:00-08:00
edited-max Upper bound on the last time a document was edited by the user. This value corresponds to the <app:edited> value in the Atom entry, which represents changes to the document's content or metadata. Use the RFC 3339 timestamp format. For example: edited-max=2009-08-09T09:57:00-08:00
owner Searches for documents with a specific owner. Use the email address of the owner. For example: owner=user%40gmail.com
writer Searches for documents which can be written to by specific users. Use a single email address or a comma separated list of email addresses. For example: writer=user1%40gmail.com%2Cuser2%40example.com
reader Searches for documents which can be read by specific users. Use a single email address or a comma separated list of email addresses. For example: reader=user1%40gmail.com%2Cuser2%40example.com
showfolders Specifies whether the query should return folders as well as documents. Possible values are true and false. Default is false
showdeleted Specifies whether the query should return documents which are in the trash as well as other documents. Possible values are true and false. Default is false
ocr Specifies whether to attempt OCR on a .jpg, .png, of .gif upload. Possible values are true and false. Default is false.
targetLanguage Specifies the language to translate a document into.
sourceLanguage Specifies the source language of the original document. Optional when using the translation service. If not provided, Google will attempt to auto-detect the source language.
delete Specifies whether or to permanently delete a document when trashing it. Possible values are true and false. Default is false, meaning a document is moved to the trash.
convert Specifies whether or not a document-type arbitrary file upload should be converted into a native Google Doc. Optional when uploading a file. Possible values are true and false. Default is true. This parameter has no effect on PDFs or arbitrary file uploads.

Getting all pages of documents and files

To retrieve resources beyond the first page, page through results by following the next link of a feed. In the example above, that link is:

<link rel="next" type="application/atom+xml"
    href="https://docs.google.com/feeds/default/private/full?start-key=EAEaFgoSCb2YGEPMAAACAG"/>

Getting a resource entry again

If you want to get a resource entry that you've retrieved before, you can improve efficiency by querying that specific entry and telling the server to send the entry 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 element's or element's gd:etag attribute. For example:

GET https://docs.google.com/feeds/default/private/full/resource_id
If-None-Match: "BxAaTxRZAyp7ImBq"

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

If the ETag doesn't match, then the item has been modified since the last time you requested it, and the server returns the item.

Searching for documents and files

You can search for documents or files using some of the standard Google Data API query parameters. Categories are used to restrict the type of resource (word processor, spreadsheet, presentation, collection, etc). returned. The full-text query string is used to search the content of all the documents.

Searching for resources by type

Retrieving all documents, files and collections

Collection entries are not returned in the feed by default. A list of all resources, including collections, can be retrieved by using the showfolders parameter on the list feed:

Protocol

GET https://docs.google.com/feeds/default/private/full?showfolders=true

.NET

The following code fetches a list of the currently authenticated user's documents and collections, and prints out the title of each of them.

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a DocumentsListQuery object to retrieve documents.
      DocumentsListQuery query = new DocumentsListQuery();

      // Set the showfolders parameter
      query.ShowFolders = true;

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      // Iterate through all of the documents returned
      foreach (DocumentEntry entry in feed.Entries)
      {
        // Print the title of this document to the screen
        Console.WriteLine(entry.Title.Text);
      }
    }
  }
}

For an example entry of the feed returned, look at the Getting a list of documents and files section.

Retrieving all text documents

A list of only word processor documents can be retrieved by using the document category as follows:

Protocol

GET https://docs.google.com/feeds/default/private/full/-/document

.NET

The following code fetches a list of the currently authenticated user's text documents, and prints out the title of each of them.

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a TextDocumentQuery object to retrieve text documents.
      TextDocumentQuery query = new TextDocumentQuery();

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      // Iterate through all of the documents returned
      foreach (DocumentEntry entry in feed.Entries)
      {
        // Print the title of this document to the screen
        Console.WriteLine(entry.Title.Text);
      }
    }
  }
}
Retrieving all spreadsheets

A list of only spreadsheets can be retrieved by using the spreadsheet category as follows:

Protocol

GET https://docs.google.com/feeds/default/private/full/-/spreadsheet

.NET

The following code fetches a list of the currently authenticated user's spreadsheets, and prints out the title of each of them.

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a SpreadsheetQuery object to retrieve spreadsheets.
      SpreadsheetQuery query = new SpreadsheetQuery();

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      // Iterate through all of the documents returned
      foreach (DocumentEntry entry in feed.Entries)
      {
        // Print the title of this document to the screen
        Console.WriteLine(entry.Title.Text);
      }
    }
  }
}
Retrieving all presentations

A list of only presentations can be retrieved by using the presentation category as follows:

Protocol

GET https://docs.google.com/feeds/default/private/full/-/presentation

.NET

The following code fetches a list of the currently authenticated user's presentations, and prints out the title of each of them.

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a PresentationsQuery object to retrieve presentations.
      PresentationsQuery query = new PresentationsQuery();

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      // Iterate through all of the documents returned
      foreach (DocumentEntry entry in feed.Entries)
      {
        // Print the title of this document to the screen
        Console.WriteLine(entry.Title.Text);
      }
    }
  }
}
Retrieving all drawings

A list of only drawings can be retrieved by using the drawing category as follows:

Protocol

GET https://docs.google.com/feeds/default/private/full/-/drawing

.NET

The following code fetches a list of the currently authenticated user's drawings, and prints out the title of each of them.

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a DrawingsQuery object to retrieve drawings.
      DrawingsQuery query = new DrawingsQuery();

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      // Iterate through all of the documents returned
      foreach (DocumentEntry entry in feed.Entries)
      {
        // Print the title of this document to the screen
        Console.WriteLine(entry.Title.Text);
      }
    }
  }
}
Retrieving files by type

To return a list of files of MIME type application/msword, send a category query that includes the scheme + content type:

Protocol

GET https://docs.google.com/feeds/default/private/full/-/{http://schemas.google.com/g/2005#kind}application/msword
GET https://docs.google.com/feeds/default/private/full/-/%7Bhttp%3A%2F%2Fschemas.google.com%2Fg%2F2005%23kind%7Dapplication%2Fmsword

.NET

The following code fetches a list of the currently authenticated user's application/msword files, and prints out the title of each of them.

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a DocumentsListQuery object to retrieve documents.
      DocumentsListQuery query = new DocumentsListQuery();

      // Add a QueryCategory corresponding to application/msword MIME type.
      query.Categories.Add(new QueryCategory(
          new AtomCategory("{http://schemas.google.com/g/2005#kind}application/msword")));

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      // Iterate through all of the documents returned
      foreach (DocumentEntry entry in feed.Entries)
      {
        // Print the title of this document to the screen
        Console.WriteLine(entry.Title.Text);
      }
    }
  }
}
Retrieving all starred presentations

You can combine more than one category. As an example, to retrieve a list of only starred presentations, use the presentation and starred categories together:

Protocol

GET https://docs.google.com/feeds/default/private/full/-/presentation/starred

.NET

The following code fetches a list of the currently authenticated user's starred presentations, and prints out the title of each of them.

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a PresentationsQuery object to retrieve presentations.
      PresentationsQuery query = new PresentationsQuery();

      // Set the starred category
      query.Starred = true;

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      // Iterate through all of the documents returned
      foreach (DocumentEntry entry in feed.Entries)
      {
        // Print the title of this document to the screen
        Console.WriteLine(entry.Title.Text);
      }
    }
  }
}
Retrieving all PDFs the user has viewed

As an example, to retrieve a list of viewed PDFs, use the viewed and pdf categories together:

Protocol

GET https://docs.google.com/feeds/default/private/full/-/pdf/viewed

.NET

The following code fetches a list of the currently authenticated user's starred presentations, and prints out the title of each of them.

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a PDFsQuery object to retrieve PDFs.
      PDFsQuery query = new PDFsQuery();

      // Set the viewed category
      query.Viewed = true;

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      // Iterate through all of the documents returned
      foreach (DocumentEntry entry in feed.Entries)
      {
        // Print the title of this document to the screen
        Console.WriteLine(entry.Title.Text);
      }
    }
  }
}
Retrieving a list of collections

A list of only collections can be retrieved by using the collection category as follows:

Protocol

GET https://docs.google.com/feeds/default/private/full/-/folder

.NET

The following code fetches a list of the currently authenticated user's folders, and prints out the title of each of them.

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a FolderQuery object to retrieve folders.
      FolderQuery query = new FolderQuery();

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      // Iterate through all of the documents returned
      foreach (DocumentEntry entry in feed.Entries)
      {
        // Print the title of this document to the screen
        Console.WriteLine(entry.Title.Text);
      }
    }
  }
}
Retrieving a list of trashed documents and files

A list of a user's trashed documents and files can be retrieved by using the trashed category as follows:

Protocol

GET https://docs.google.com/feeds/default/private/full/-/trashed

Trashed resources are not included by default in query results. To include them, use the showdeleted parameter:

GET https://docs.google.com/feeds/default/private/full?showdeleted=true

.NET

The following code fetches a list of the currently authenticated user's trashed documents, and prints out the title of each of them.

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a DocumentsListQuery object to retrieve documents.
      DocumentsListQuery query = new DocumentsListQuery();

      // Set the trashed category
      query.Trashed = true;

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      // Iterate through all of the documents returned
      foreach (DocumentEntry entry in feed.Entries)
      {
        // Print the title of this document to the screen
        Console.WriteLine(entry.Title.Text);
      }
    }
  }
}

Trashed resources are not included by default in query results. To include them, use the showdeleted parameter:

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a DocumentsListQuery object to retrieve documents.
      DocumentsListQuery query = new DocumentsListQuery();

      // Set the showdeleted parameter
      query.ShowDeleted = true;

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      // Iterate through all of the documents returned
      foreach (DocumentEntry entry in feed.Entries)
      {
        // Print the title of this document to the screen
        Console.WriteLine(entry.Title.Text);
      }
    }
  }
}
Retrieving resources owned by a user

A list of PDFs owned by the requesting user:

Protocol

GET https://docs.google.com/feeds/default/private/full/-/pdf/mine

.NET

The following code fetches a list of the currently authenticated user's own PDFs, and prints out the title of each of them.

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a PDFsQuery object to retrieve PDFs.
      PDFsQuery query = new PDFsQuery();

      // Set the mine category
      query.Mine = true;

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      // Iterate through all of the documents returned
      foreach (DocumentEntry entry in feed.Entries)
      {
        // Print the title of this document to the screen
        Console.WriteLine(entry.Title.Text);
      }
    }
  }
}
Retrieving only shared resources

All resources that user1@gmail.com and user2@gmail.com are collaborating on:

Protocol

GET https://docs.google.com/feeds/default/private/full?writer=user1%40gmail.com%2Cuser2%gmail.com

.NET

The following code fetches a list of the resources user1@mail.com and user2@gmail.com are collaborating on, and prints out the title of each of them.

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a DocumentsListQuery object to retrieve documents.
      DocumentsListQuery query = new DocumentsListQuery();

      // Set the writer parameter
      query.Writer = "user1@gmail.com,user2@gmail.com";

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      // Iterate through all of the documents returned
      foreach (DocumentEntry entry in feed.Entries)
      {
        // Print the title of this document to the screen
        Console.WriteLine(entry.Title.Text);
      }
    }
  }
}

Searching for resources by title

You can search for resources matching an exact title or portion of a title by using the title-exact and title query parameters, respectively. For example, to search for resources matching the partial title "PR Handbook", send:

Protocol

GET https://docs.google.com/feeds/default/private/full?title=%22PR+Handbook%22

To match a title exactly, add the title-exact parameter:

GET https://docs.google.com/feeds/default/private/full?title=PR+Handbook&title-exact=true

.NET

The following code fetches a list of the resources matching the partial title "PR Handbook", and prints out the title of each of them.

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a DocumentsListQuery object to retrieve documents.
      DocumentsListQuery query = new DocumentsListQuery();

      // Set the title parameter
      query.Title = "PR Handbook";

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      // Iterate through all of the documents returned
      foreach (DocumentEntry entry in feed.Entries)
      {
        // Print the title of this document to the screen
        Console.WriteLine(entry.Title.Text);
      }
    }
  }
}

To match a title exactly, add the title-exact parameter:

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a DocumentsListQuery object to retrieve documents.
      DocumentsListQuery query = new DocumentsListQuery();

      // Set the title parameter
      query.Title = "PR Handbook";
      query.TitleExact = true;

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      // Iterate through all of the documents returned
      foreach (DocumentEntry entry in feed.Entries)
      {
        // Print the title of this document to the screen
        Console.WriteLine(entry.Title.Text);
      }
    }
  }
}

Searching for documents by full text query

You can search the content of documents by using the q query parameter on the feed. For example, to search a user's documents for the the words "dog" and "cat", send the following authenticated GET:

Protocol

GET https://docs.google.com/feeds/default/private/full?q=dog+cat

.NET

The following code searches the user's documents for the the words "dog" and "cat", and prints out the title of each of them.

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a DocumentsListQuery object to retrieve documents.
      DocumentsListQuery query = new DocumentsListQuery();

      // Set the q parameter
      query.Query = "dog+cat";

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      // Iterate through all of the documents returned
      foreach (DocumentEntry entry in feed.Entries)
      {
        // Print the title of this document to the screen
        Console.WriteLine(entry.Title.Text);
      }
    }
  }
}
Full text query operators

The q parameter supports a series of operators that allow searches to return very specific results. These operators can be combined in order to narrow down search results. An example is:

from:fluffy@catsndogs.com to:fido@catsndogs.com title:peace title:treaty after:2007-07-24 is:starred owner:fluffy@catsndogs.com
Name Description Example
Quotes Matches contain the exact phrase in quotes. "The quick brown fox jumps over the lazy dog."
Conjunctions Matches contain all of the given words. This is the default behavior. cats AND dogs AND lizards
Disjunctions Matches contain one of the given words. cats OR dogs OR lizards
Exclusions Matches do not contain the given words. cats -dogs
Title Matches contain the given word in their title. title:peace title:treaty
Items shared by a user Matches are shared by the given user. from:fluffy@catsndogs.com
Items shared with a user Matches are shared with the given user. to:fido@catsndogs.com
Items owned by a user Matches are owned by the given user. owner:fluffy@catsndogs.com
Starred items Matches are starred. is:starred
Hidden items Matches are hidden. is:hidden
Items of a certain type Matches are of the given resource type. type:document OR type:spreadsheet OR type:presentation OR type:video
Edited date Matches are edited before or after the given date. before:2010-07-13 OR after:2007-07-24

Creating and uploading documents and files

Resources are uploaded to the API using a mechanism called resumable upload. This mechanism allows uploads to be broken up into individual parts, so that if uploading a single part fails, the part can be resent. Advantages of resumable upload include easier uploading of large files, better performance in bandwidth constrained environments, and easier user interface integrations (e.g. progress bars).

Below, the term metadata refers to the XML entry of a resource. The metadata of a resource is the series of attributes of the resource, including things like title or whether or not writers can invite others to the resource. It does not include resource content, which is the actual file content of a resource.

Clients creating and uploading resources are always in one of three scenarios.

Creating a new, empty document or file with metadata only
Clients in this scenario must send only a resource entry, but no resource content. Clients do this in order to create empty resources with just a title and/or other metadata.
Uploading a new document or file with content only
Clients in this scenario must send only resource content, but no resource entry. Clients do this to upload resources that do not need a title or other metadata.
Uploading a new document or file with both metadata and content
Clients in this scenario must send both a resource entry and resource content. Clients do this in order to, for example, upload a resource and give it a title, at the same time.

In all scenarios, clients must send an HTTP POST request to the resumable-create-media link of the resources feed. To acquire this link, clients query https://docs.google.com/feeds/default/private/full. It is recommended that clients not hard-code this link, in case the link changes. In the following sections, this link is referred to as [resumable-create-media link].

<link rel="http://schemas.google.com/g/2005#resumable-create-media"
    type="application/atom+xml"
    href="https://docs.google.com/feeds/upload/create-session/default/private/full"/>

Creating a new document or file with metadata only

Creating a new, empty resource with only metadata is the simplest way to create a resource, because it does not involve uploading any resource content. This scenario does not use most parts of the GData resumable upload protocol.

Protocol

The following example demonstrates a single HTTP request and the consequent HTTP response for creating an empty text document. The example can be applied to create other empty resources simply by changing the category of the provided resource entry.

POST [resumable-create-media link]
Content-Length: 359
Content-Type: application/atom+xml
X-Upload-Content-Length: 0

<?xml version="1.0" encoding="UTF-8"?>
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:docs="http://schemas.google.com/docs/2007">
  <!-- Replace the following line appropriately to create another type of resource. -->
  <category scheme="http://schemas.google.com/g/2005#kind"
      term="http://schemas.google.com/docs/2007#document"/>
  <title>Legal Contract</title>
</entry>

The API responds with the relevant response code and the new resource entry. Clients in this scenario need not do anything further. The resource has been created.

HTTP/1.1 201 Created
ETag: "HRcET05QHyt7ImBr"
...

<?xml version="1.0" encoding="UTF-8"?>
<entry xmlns="http://www.w3.org/2005/Atom"
    xmlns:docs="http://schemas.google.com/docs/2007"
    xmlns:batch="http://schemas.google.com/gdata/batch"
    xmlns:gd="http://schemas.google.com/g/2005"
    gd:etag="&quot;HRcET05QHyt7ImBr&quot;">
  <id>https://docs.google.com/feeds/id/file%3A0B9j-hQNOVsTFZTZkMmU0Y2UtNjNmYi00Y2RkLTkwODctMTg0NzdiZDNjZTg4</id>
  <title>Legal Contract</title>
...
</entry>

.NET

The following code creates an empty text document with title "Legal Contract".

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a DocumentEntry object to be inserted.
      DocumentEntry entry = new DocumentEntry();

      // Set the document title
      entry.Title.Text = "Legal Contract";

      // Add the document category
      entry.Categories.Add(DocumentEntry.DOCUMENT_CATEGORY);

      // Make a request to the API and create the document.
      DocumentEntry newEntry = service.Insert(
          DocumentsListQuery.documentsBaseUri, entry);
    }
  }
}

Uploading a new document or file with content only

Creating a new resource with only content requires the use of the GData resumable upload protocol. When uploading a resource in this scenario, the resource will have a default title and metadata, depending on the MIME type of the content uploaded.

The following example demonstrates a full HTTP request and response sequence for uploading a 1 gigabyte PDF. The sequence consists of an initial request to create a resumable upload session, and then a large number of requests to upload the PDF in chunks of 512 kilobytes each. After all chunks are uploaded, the API issues a response indicating success or failure. The example can be applied to upload resources of any type.

POST [resumable-create-media link]
Content-Length: 0
X-Upload-Content-Type: application/pdf
X-Upload-Content-Length: 1073741824
HTTP/1.1 200 OK
Location: [next location]
...

PUT [next location]
Content-Length: 524288
Content-Type: application/pdf
Content-Range: bytes 0-524287/1073741824

[bytes 0-524287]
HTTP/1.1 308 Resume Incomplete
Range: 0-524287
Location: [next location]
...

After receiving each chunk, the API issues an HTTP 308 response indicating which bytes were successfully received. In the case that an HTTP 308 response is not returned, clients must resend the failed chunk to the given [next location]. An example HTTP response requiring the previous chunk to be resent is an HTTP 503.

If an HTTP 308 is received and the byte range matches that which was last sent, clients should proceed to send the next chunk.

PUT [next location]
Content-Length: 524288
Content-Type: application/pdf
Content-Range: bytes 524288-1048575/1073741824

[bytes 524288-1048575]
HTTP/1.1 308 Resume Incomplete
Range: 524288-1048575
Location: [next location]
...

Repeat the previous step, sending the next consecutive 512 kilobytes, until there are no more bytes to send. After all bytes are uploaded, the server responds with a relevant status and the new resource entry.

HTTP/1.1 201 Created
ETag: "HRcET05QHyt7ImBr"
...

<?xml version="1.0" encoding="UTF-8"?>
<entry xmlns="http://www.w3.org/2005/Atom"
    xmlns:docs="http://schemas.google.com/docs/2007"
    xmlns:batch="http://schemas.google.com/gdata/batch"
    xmlns:gd="http://schemas.google.com/g/2005"
    gd:etag=""HRcET05QHyt7ImBr"">
  <id>https://docs.google.com/feeds/id/file%3A0B9j-hQNOVsTFZTZkMmU0Y2UtNjNmYi00Y2RkLTkwODctMTg0NzdiZDNjZTg4</id>
  <title>Untitled document</title>
...
</entry>

Uploading a new document or file with both metadata and content

Creating a new resource with both metadata and content at once requires the use of the GData resumable upload protocol. When uploading a resource in this scenario, the resource will have the given title and metadata, as well as the given content.

The following example demonstrates a full HTTP request and response sequence for uploading a 1 gigabyte PDF titled "Legal Contract". The sequence consists of an initial request to create a resumable upload session with the given metadata, and then a large number of requests to upload the PDF in chunks of 512 kilobytes each. After all chunks are uploaded, the API issues a response indicating success or failure. The example can be applied to upload resources of any type with metadata.

Protocol

POST [resumable-create-media link]
Content-Length: 359
Content-Type: application/atom+xml
X-Upload-Content-Type: application/pdf
X-Upload-Content-Length: 1073741824

<?xml version="1.0" encoding="UTF-8"?>
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:docs="http://schemas.google.com/docs/2007">
  <title>Legal Contract</title>
</entry>

HTTP/1.1 200 OK
Location: [next location]
...
PUT [next location]
Content-Length: 524288
Content-Type: application/pdf
Content-Range: bytes 0-524287/1073741824

[bytes 0-524287]
HTTP/1.1 308 Resume Incomplete
Range: 0-524287
Location: [next location]
...

After receiving each chunk, the API issues an HTTP 308 response indicating which bytes were successfully received. In the case that an HTTP 308 response is not returned, clients must resend the failed chunk to the given [next location]. An example HTTP response requiring the previous chunk to be resent is an HTTP 503.

If an HTTP 308 is received and the byte range matches that which was last sent, clients should proceed to send the next chunk.

PUT [next location]
Content-Length: 524288
Content-Type: application/pdf
Content-Range: bytes 524288-1048575/1073741824

[bytes 524288-1048575]
HTTP/1.1 308 Resume Incomplete
Range: 524288-1048575
Location: [next location]
...

Repeat the previous step, sending the next consecutive 512 kilobytes, until there are no more bytes to send. After all bytes are uploaded, the server responds with a relevant status and the new resource entry.

HTTP/1.1 201 Created
ETag: "HRcET05QHyt7ImBr"
...

<?xml version="1.0" encoding="UTF-8"?>
<entry xmlns="http://www.w3.org/2005/Atom"
    xmlns:docs="http://schemas.google.com/docs/2007"
    xmlns:batch="http://schemas.google.com/gdata/batch"
    xmlns:gd="http://schemas.google.com/g/2005"
    gd:etag=""HRcET05QHyt7ImBr"">
  <id>https://docs.google.com/feeds/id/pdf%3A0B9j-hQNOVsTFZTZkMmU0Y2UtNjNmYi00Y2RkLTkwODctMTg0NzdiZDNjZTg4</id>
  <title>Legal Contract</title>
...
</entry>

.NET

using System;
using Google.GData.Client;
using Google.GData.Client.ResumableUpload;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Instantiate an Authenticator object according to your authentication
      // mechanism (e.g. OAuth2Authenticator).
      // Authenticator authenticator =  ...

      // Instantiate a DocumentEntry object to be inserted.
      DocumentEntry entry = new DocumentEntry();

      // Set the document title
      entry.Title.Text = "Legal Contract";

      // Set the media source
      entry.MediaSource = new MediaFileSource("c:\\contract.txt", "text/plain");

      // Define the resumable upload link
      Uri createUploadUrl = new Uri("https://docs.google.com/feeds/upload/create-session/default/private/full");
      AtomLink link = new AtomLink(createUploadUrl.AbsoluteUri);
      link.Rel = ResumableUploader.CreateMediaRelation;
      entry.Links.Add(link);

      // Set the service to be used to parse the returned entry
      entry.Service = service;

      // Instantiate the ResumableUploader component.
      ResumableUploader uploader = new ResumableUploader();

      // Set the handlers for the completion and progress events
      uploader.AsyncOperationCompleted += new AsyncOperationCompletedEventHandler(OnDone);
      uploader.AsyncOperationProgress += new AsyncOperationProgressEventHandler(OnProgress);

      // Start the upload process
      uploader.InsertAsync(authenticator, entry, new object());
    }

    static void OnDone(object sender, AsyncOperationCompletedEventArgs e) {
        DocumentEntry entry = e.Entry as DocumentEntry;
    }

    static void OnProgress(object sender, AsyncOperationProgressEventArgs e) {
        int percentage = e.ProgressPercentage;
    }
  }
}

Resuming an incomplete upload

If a request is terminated prior to receiving a resource entry from the API, or if an HTTP 503 response is received, query the current status of the upload by issuing an empty PUT request to the last [next location] received from the API. This allows clients to resume uploads even after a chunk fails to send properly.

PUT [next location]
Content-Length: 0
Content-Range: bytes */1073741824
HTTP/1.1 308 Resume Incomplete
Range: 0-524287
Location: [next location]
...

After querying the status of the upload, resume the upload at the chunk after the chunk described in the query response. In the above example, the byte range 0-524287 is the last chunk successfully sent. Thus, the client next sends the byte range 524288-1048575. At this point, the client continues the resumable upload process described in previous sections.

PUT [next location]
Content-Length: 524288
Content-Type: application/pdf
Content-Range: bytes 524288-1048575/1073741824

[bytes 524288-1048575]

Creating or uploading text documents

To create a new, empty text document, follow the instructions in Creating a new document or file with metadata only. When doing so, use a category term of http://schemas.google.com/docs/2007#document.

To upload and convert a text document, follow the instructions in Uploading a new document or file with both metadata and content. When doing so, specify an HTTP X-Upload-Content-Type of the MIME type of the content being uploaded. Valid content types for conversion to Google Docs text documents are specified by the metadata feed docs:importFormat elements with a target of document.

To upload a text document, but not convert it to a Google Doc (e.g. to upload it as a file), follow the instructions in Uploading a new document or file with both metadata and content, but also append ?convert=false to the resumable-create-media link.

Creating or uploading drawings

To create a new, empty drawing, follow the instructions in Creating a new document or file with metadata only. When doing so, use a category term of http://schemas.google.com/docs/2007#drawing.

To upload and convert a drawing, follow the instructions in Uploading a new document or file with both metadata and content. When doing so, specify an HTTP X-Upload-Content-Type of the MIME type of the content being uploaded. Valid content types for conversion to Google Docs drawings are specified by the metadata feed docs:importFormat elements with a target of drawing.

To upload a drawing, but not convert it to a Google Doc (e.g. to upload it as a file), follow the instructions in Uploading a new document or file with both metadata and content, but also append ?convert=false to the resumable-create-media link.

Creating or uploading presentations

To create a new, empty presentation, follow the instructions in Creating a new document or file with metadata only. When doing so, use a category term of http://schemas.google.com/docs/2007#presentation.

To upload and convert a presentation, follow the instructions in Uploading a new document or file with both metadata and content. When doing so, specify an HTTP X-Upload-Content-Type of the MIME type of the content being uploaded. Valid content types for conversion to Google Docs text documents are specified by the metadata feed docs:importFormat elements with a target of presentation.

To upload a presentation, but not convert it to a Google Doc (e.g. to upload it as a file), follow the instructions in Uploading a new document or file with both metadata and content, but also append ?convert=false to the resumable-create-media link.

Creating or uploading spreadsheets

To create a new, empty spreadsheet, follow the instructions in Creating a new document or file with metadata only. When doing so, use a category term of http://schemas.google.com/docs/2007#spreadsheet.

To upload and convert a spreadsheet, follow the instructions in Uploading a new document or file with both metadata and content. When doing so, specify an HTTP X-Upload-Content-Type of the MIME type of the content being uploaded. Valid content types for conversion to Google Docs text documents are specified by the metadata feed docs:importFormat elements with a target of spreadsheet.

To upload a spreadsheet, but not convert it to a Google Doc (e.g. to upload it as a file), follow the instructions in Uploading a new document or file with both metadata and content, but also append ?convert=false to the resumable-create-media link.

Creating or uploading files

To create a new, empty file, follow the instructions in Uploading a new document or file with both metadata and content. When doing so, send 0 bytes as the content body of the file. Also append ?convert=false to the resumable-create-media link.

To upload a file, follow the instructions in Uploading a new document or file with both metadata and content, but also append ?convert=false to the resumable-create-media link.

Uploading documents using Optical Character Recognition (OCR)

Optical Character Recognition gives applications the ability to convert high-resolution PDFs or images containing typewritten/printed text into editable text. As an example, applications could use this feature to upload scanned letters or old faxes to Google Docs. The API will attempt to extract the text from the PDFs or images, creating a new Google Doc for each image.

Limitations:

  • Supported file formats: application/pdf, image/jpeg, image/png, image/gif
  • Works best with high resolution images (at least 10 pixel character height)
  • OCR is a computationally expensive operation and can take up to 30 seconds.
  • Works only for latin character sets.

To perform OCR on a .pdf, .jpg, .png, or .gif file, include the ocr=true parameter when uploading files:

POST [resumable-create-media link]?ocr=true
...

Hinting at languages

An additional parameter, ocr-language, may be provided in order to hint at which language to use when performing OCR. Even while providing this parameter, if there is overwhelming evidence that a character or paragraph is of a certain language, the hint will not be applied in that case.

Valid values for ocr-language are ISO 639-1 codes. The following codes are currently supported by the API.

bg, ca, chr, cs, da, de, el, en, es, fi, fil, fr, hi, hr, hu, id, it, iw, ja, ko, lt, lv, nl, no, pl, pt, ro, ru, sk, sl, sr, sv, th, tr, uk, vi, zh-Hans, zh-Hant

An example of specifying ocr-language follows.

POST [resumable-create-media link]?ocr=true&ocr-language=zh-Hans
...

Uploading documents and automatically translating them

When uploading documents, clients can optionally translate the text of a document into another language by specifying the targetLanguage=x and sourceLanguage=y parameters. The API attempts to automatically detect the sourceLanguage if one is not provided. Generally, the automatic detection works well, but if it fails, a relevant error is returned. Note also that not all translation pairs are supported (e.g. Estonian to Chinese). If a client attempts to use an unsupported pair, a relevant error message is returned.

This example translates the uploaded resource from English to German and stores the result as a Google Doc:

POST [resumable-create-media link]?sourceLanguage=en&targetLanguage=de
...

A full list of supported translation languages can be found by opening the "Tools > Translate Document" menu in the Google Docs web interface. Viable country codes can be found here.

Downloading documents and files

Once a client retrieves a resource's content element, it can download the file in a variety of formats. The content element is found in each resource entry. An example follows.

<entry xmlns:gd="http://schemas.google.com/g/2005" gd:etag="'HhJSFgpeRyt7ImBq'">
  ...
  <title>My PDF</title>
  <content type="application/pdf"
       src="https://doc-04-20-docs.googleusercontent.com/docs/secure/m71240U1?h=1630126&e=download&gd=true"/>
  ...
</entry>

Note that the content element gives the document or file's default export MIME type, as well as a full download URL for the document or file.

By default, documents are exported as HTML. Use the exportFormat parameter (described below) to download documents in alternate formats. Specifying a different exportFormat for a document upon download is called converting the document.

The default MIME type of a file upon download is the MIME type with which the file was uploaded. Files cannot be converted, and will have a different looking content URL than the ones described below.

Downloading text documents

The download URL for text documents looks something like this:

https://docs.google.com/feeds/download/documents/Export?docID=0AsJD12345&exportFormat=html&format=html

The document's download URL can be found in each entry under the content element, along with the document's default MIME type.

If the download request was successful, an HTTP 200 is returned and the file is served in the requested format.

If the download request failed, you will probably receive an HTTP 400 Could not convert document response, or an HTTP 500 response. Either of these errors indicates an issue on the API's part in converting your document to the specified format. If you received a 401 Unauthorized response, then most likely you did not get your OAuth/AuthSub token with the correct scopes (described above).

Protocol

GET https://docs.google.com/feeds/download/documents/Export?docID=0AsJD12345&exportFormat=html&format=html

.NET

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a DocumentsListQuery object to retrieve documents.
      DocumentsListQuery query = new DocumentsListQuery();

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      if (feed.Entries.Count == 0)
      {
        // TODO: There were no documents, act accordingly.
      }

      // TODO: Choose a resource based on your app's needs.
      DocumentEntry entry = (DocumentEntry)feed.Entries[0];

      // Get the download url from the resource's content element
      string downloadUrl = entry.Content.Src.Content;

      // Add the exportFormat parameter
      downloadUrl += "&exportFormat=html&format=html";

      // Download the document as a stream
      Stream stream = service.Query(new Uri(downloadUrl));
    }
  }
}
Valid download formats for text documents

When downloading text documents, the exportFormat parameter controls the format of the output. Valid values for this parameter appear below.

exportFormat Parameter Value Format of the returned Document
docx Microsoft Word
doc Microsoft Word
html HTML Format
jpeg Joint Photographic Experts Group Image Format (used for Google Drawings)
odt Open Document Format
pdf Portable Document Format
png Portable Networks Graphic Image Format
rtf Rich Text Format
txt Text file
zip ZIP archive. Contains the images (if any) used in the document, as well as a .html file containing the document's text.

Downloading drawings

The download URL for drawings looks something like this:

https://docs.google.com/feeds/download/drawings/Export?docID=0AsJD12345&exportFormat=jpeg

The drawings's download URL can be found in each entry under the element, along with the drawing's default MIME type.

If the download request is successful, an HTTP 200 is returned and the file is served in the requested format.

Protocol

GET https://docs.google.com/feeds/download/drawings/Export?docID=0AsJD12345&exportFormat=jpeg

.NET

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a DocumentsListQuery object to retrieve documents.
      DocumentsListQuery query = new DocumentsListQuery();

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      if (feed.Entries.Count == 0)
      {
        // TODO: There were no documents, act accordingly.
      }

      // TODO: Choose a resource based on your app's needs.
      DocumentEntry entry = (DocumentEntry)feed.Entries[0];

      // Get the download url from the resource's content element
      string downloadUrl = entry.Content.Src.Content;

      // Add the exportFormat parameter
      downloadUrl += "&exportFormat=jpeg";

      // Download the document as a stream
      Stream stream = service.Query(new Uri(downloadUrl));
    }
  }
}
Valid download formats for drawings

Drawing formats are also controlled via the exportFormat parameter. Valid values for this parameter appear below.

exportFormat Parameter Value Format of the returned Document
jpeg Joint Photographic Experts Group Image Format
pdf Portable Document Format
png Portable Networks Graphic Image Format
svg Scalable Vector Graphics Image Format

Downloading presentations

The download URL for presentations looks something like this:

https://docs.google.com/feeds/download/presentations/Export?docID=0AsJD12345&exportFormat=png

The presentation's download URL can be found in each entry under the element, along with the presentation's default MIME type.

If the download request is successful, an HTTP 200 is returned and the presentation is served in the requested format.

Protocol

GET https://docs.google.com/feeds/download/presentations/Export?docID=0AsJD12345&exportFormat=png

.NET

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a DocumentsListQuery object to retrieve documents.
      DocumentsListQuery query = new DocumentsListQuery();

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      if (feed.Entries.Count == 0)
      {
        // TODO: There were no documents, act accordingly.
      }

      // TODO: Choose a resource based on your app's needs.
      DocumentEntry entry = (DocumentEntry)feed.Entries[0];

      // Get the download url from the resource's content element
      string downloadUrl = entry.Content.Src.Content;

      // Add the exportFormat parameter
      downloadUrl += "&exportFormat=png";

      // Download the document as a stream
      Stream stream = service.Query(new Uri(downloadUrl));
    }
  }
}
Valid Formats for Presentations

Presentation formats are also controlled via the exportFormat parameter. Valid values for this parameter appear below.

exportFormat Parameter Value Format of the returned Presentation
pdf Portable Document Format
png Portable Networks Graphic Image Format
ppt Powerpoint Format
txt Text file

Downloading spreadsheets

The download URL for spreadsheets looks something like this:

https://spreadsheets.google.com/feeds/download/spreadsheets/Export?key=0AsJD12345&exportFormat=csv

The spreadsheet's download URL can be found in each entry under the element, along with the spreadsheet's default MIME type.

If the download request is successful, an HTTP 200 is returned and the spreadsheet is served in the requested format.

If you received a 401 Unauthorized response, then most likely you did not get your OAuth/AuthSub token with the correct scopes (described above).

Protocol

GET https://spreadsheets.google.com/feeds/download/spreadsheets/Export?key=0AsJD12345&exportFormat=csv

.NET

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a DocumentsListQuery object to retrieve documents.
      DocumentsListQuery query = new DocumentsListQuery();

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      if (feed.Entries.Count == 0)
      {
        // TODO: There were no documents, act accordingly.
      }

      // TODO: Choose a resource based on your app's needs.
      DocumentEntry entry = (DocumentEntry)feed.Entries[0];

      // Get the download url from the resource's content element
      string downloadUrl = entry.Content.Src.Content;

      // Add the exportFormat parameter
      downloadUrl += "&exportFormat=csv";

      // Download the document as a stream
      Stream stream = service.Query(new Uri(downloadUrl));
    }
  }
}
Valid Formats for Spreadsheets

When downloading spreadsheets, the exportFormat parameter controls the format of the output. Valid values for this parameter appear below:

exportFormat Parameter Value Format of the returned Spreadsheet
xlsx XLSX (Microsoft Excel)
xls XLSX (Microsoft Excel)
csv CSV (Comma Seperated Value). Only the first worksheet is returned in CSV by default.
pdf PDF (Portable Document Format)
ods ODS (Open Document Spreadsheet)
tsv TSV (Tab Seperated Value). Only the first worksheet is returned in TSV by default.
html HTML Format
Downloading a single worksheet from a spreadsheet

When requesting a CSV, TSV, PDF, or HTML file you may specify an additional (optional) parameter called gid which indicates which worksheet you wish to export (the index is 0 based, so gid 1 actually refers to the second worksheet on a given spreadsheet). If left unspecified, the first worksheet is exported for these formats. In the case of a PDF, the whole document is exported.

Here is an example download URL for a CSV representation of the second worksheet in a spreadsheet:

https://spreadsheets.google.com/feeds/download/spreadsheets/Export?key=0AsJD12345&exportFormat=csv&gid=1

Protocol

GET https://spreadsheets.google.com/feeds/download/spreadsheets/Export?key=0AsJD12345&exportFormat=csv&gid=1

.NET

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a DocumentsListQuery object to retrieve documents.
      DocumentsListQuery query = new DocumentsListQuery();

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      if (feed.Entries.Count == 0)
      {
        // TODO: There were no documents, act accordingly.
      }

      // TODO: Choose a resource based on your app's needs.
      DocumentEntry entry = (DocumentEntry)feed.Entries[0];

      // Get the download url from the resource's content element
      string downloadUrl = entry.Content.Src.Content;

      // Add the exportFormat parameter
      downloadUrl += "&exportFormat=csv";

      // Add the gid parameter
      downloadUrl += "&gid=1";

      // Download the document as a stream
      Stream stream = service.Query(new Uri(downloadUrl));
    }
  }
}

Downloading files

Files cannot be downloaded in a format other than the one in which they were originally uploaded.

The download URL for files looks something like this:

https://doc-04-20-docs.googleusercontent.com/docs/secure/m7an0emtau/WJm12345/YzI2Y2ExYWVm?h=16655626&e=download&gd=true

The hostname used to serve files is different than that of documents for security reasons. It ensures that users cannot embed things like Javascript into the context of a page and access cookies created for other Google domains.

If the download request is successful, an HTTP 200 is returned and the file is served in the requested format.

If you received a 401 Unauthorized response, then most likely you did not get your OAuth/AuthSub token with the correct scopes (described above).

Protocol

GET https://doc-04-20-docs.googleusercontent.com/docs/secure/m7an0emtau/WJm12345/YzI2Y2ExYWVm?h=16655626&e=download&gd=true

.NET

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a DocumentsListQuery object to retrieve documents.
      DocumentsListQuery query = new DocumentsListQuery();

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      if (feed.Entries.Count == 0)
      {
        // TODO: There were no documents, act accordingly.
      }

      // TODO: Choose a resource based on your app's needs.
      DocumentEntry entry = (DocumentEntry)feed.Entries[0];

      // Get the download url from the resource's content element
      string downloadUrl = entry.Content.Src.Content;

      // Download the file as a stream
      Stream stream = service.Query(new Uri(downloadUrl));
    }
  }
}

In addition to downloading an entire file in a single request, the API supports downloading portions of a file as described in RFC 2616 using the HTTP Range header.

Assuming that an example file contains the bytes:

abcdefghijklmnopqrstuvwxyz

The following request to download a portion of the file yields only the intended bytes.

GET https://doc-0c-04-docs.googleusercontent.com/docs/securesc/lmdbchpbr0qbcdh0nq22dfe5mj5clv60/chsmg8c7b0gmmj9f3sn1hlahatdp9udr/1324168200000/05910256864069419770/05910256864069419770/0B3v1cNcx6HE-MTFlMTcxNGItMDI4NC00MTE3LTkwNDgtNTFmYzdjYjQ1MmNl?h=08181731109795882708&e=download&gd=true
Range: bytes=5-12
HTTP/1.1 206 Partial Content
status: 206
content-length: 8
x-google-cache-control: remote-fetch
content-disposition: attachment;filename="test.txt";filename*=UTF-8''test.txt
expires: Sun, 18 Dec 2011 00:37:45 GMT
server: HTTP Upload Server Built on Dec 13 2011 15:55:44 (1323820544)
content-range: bytes 5-12/37
via: HTTP/1.1 GWA
cache-control: private, max-age=0
date: Sun, 18 Dec 2011 00:37:45 GMT
content-type: text/plain

fghijklm

Updating/changing documents and files

To update an existing document or file, first retrieve the entry to update, modify it as desired, and send a PUT request to either the edit link or the edit-media link, depending on what is to be updated. Use this method only to update metadata. This mechanism is not recommended for content updates, and may be deprecated in the near future. For content updates, instead use the resumable update mechanism, which is more scalable. If you are updating just a resource's metadata, use the edit link. If you are updating a resource's content, use the edit-media link. If you are updating both metadata and content, use the edit-media link. An example of these edit and edit-media links in an entry follows:

<entry xmlns:gd="http://schemas.google.com/g/2005" gd:etag="'HhJSFgpeRyt7ImBq'">
  ...
  <title>PDF's Title</title>
  ...
  <link rel="edit" type="application/atom+xml" href="https://docs.google.com/feeds/default/private/full/pdf%3A12345"/>
  <link rel="edit-media" type="application/pdf" href="https://docs.google.com/feeds/default/media/pdf%3A12345"/>
  ...
</entry>

Use the self link for metadata changes on documents for which the user does not have edit access. An example would be starring a resource to which the user only has view access.

You can update any of the following:

  • a document or file's metadata
  • a document or file's content
  • both metadata and content at once (using a multipart HTTP request)

The new document contents, which form part of the multipart HTTP request, must have a Content-Type which is supported for conversion. For instance, when updating a text document with new content, a Content-Type of either application/msword or text/plain is supported, but application/vnd.ms-excel is not. However, when updating a spreadsheet, application/vnd.ms-excel is appropriate. Using a Content-Type that is unsuitable for the document type being updated results in an HTTP 400 Bad Request response.

This requirement to use a Content-Type that's compatible with the document type you're working with does not apply to files, as conversion is not supported for files.

For more information, see the complete list of accepted formats.

To make sure that your update doesn't overwrite another client's changes, include the original entry's ETag value. You can do this by providing the ETag value in an HTTP If-Match header, or by including the original entry's gd:etag attribute in the updated entry. To determine the original resource's ETag value, examine the element's gd:etag attribute. For media entries, the ETag of the media may be available in the gd:etag attribute of the edit-media link.

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

Updating document or file metadata

Here is an example of updating a spreadsheet's metadata, but leaving its content unchanged. The spreadsheet's name is changed to example spreadsheet, and collaborators are allowed to share the document with users. Since the request does not contain new spreadsheet content, the edit link is used.

Protocol

PUT https://docs.google.com/feeds/default/private/full/spreadsheet%3A0Aj12345
Authorization: <your authorization header here>
Content-Length: 292
Content-Type: application/atom+xml

<?xml version='1.0' encoding='UTF-8'?>
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:docs="http://schemas.google.com/docs/2007"
    xmlns:gd="http://schemas.google.com/g/2005" gd:etag="BxAaTxRZAyp7ImBq">
  <title>example spreadsheet</title>
  <docs:writersCanInvite value="true" />
</entry>

.NET

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a DocumentsListQuery object to retrieve documents.
      DocumentsListQuery query = new DocumentsListQuery();

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      if (feed.Entries.Count == 0)
      {
        // TODO: There were no documents, act accordingly.
      }

      // TODO: Choose a resource based on your app's needs.
      DocumentEntry entry = (DocumentEntry)feed.Entries[0];

      // Update the document's title
      entry.Title.Text = "example spreadsheet";

      // Allow collaborators to share the document with users
      entry.WritersCanInvite = true;

      // Make a request to the API and update the document.
      entry.Update();
    }
  }
}

Updating document or file content with a simple PUT

Here is an example of changing the content of a document, but leaving its metadata unchanged. The document's name is unchanged, but its contents is replaced with the contents of test.doc. Since the request contains new document content, the edit-media link is used.

PUT https://docs.google.com/feeds/default/media/document:1234abcd
If-Match: <ETag or * here>
Authorization: <your authorization header here>
Content-Length: 70581
Content-Type: application/msword
Slug: test.doc

... doc contents here ...

Updating both metadata and content

Here is an example of updating both the document's metadata and its content at the same time. The document's title is updated to example document and its contents are replaced with the contents of test.doc. Since the request contains new document content, the edit-media link is used.

Note that including the ETag for the metadata provides an implicit If-Match for the media content as well, because any update to the media content causes the metadata's ETag to change.

PUT https://docs.google.com/feeds/default/media/document:1234abcd
Authorization: <your authorization header here>
Content-Length: 73612
Content-Type: multipart/related; boundary="END_OF_PART"
Slug: test.doc
--END_OF_PART
Content-Type: application/atom+xml

<?xml version='1.0' encoding='UTF-8'?>
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:gd="http://schemas.google.com/g/2005" gd:etag="BxAaTxRZAyp7ImBq">
  <category scheme="http://schemas.google.com/g/2005#kind"
      term="http://schemas.google.com/docs/2007#document"/>
  <title>example document</title>
</entry>

--END_OF_PART
Content-Type: application/msword

... doc contents here ...

--END_OF_PART

In all of these cases, a successful update returns an HTTP 200 OK status code with an describing the document on the server.

Updating document or file content with the resumable protocol

Similar to initiating a resumable upload session, you can utilize the resumable upload protocol to replace an existing document's content. To start a resumable update request, send an HTTP PUT to the entry link with rel attribute resumable-edit-media. Each document or file entry that the currently authorized user has permission to update will contain a resumable-edit-media link.

<link rel="http://schemas.google.com/g/2005#resumable-edit-media" type="application/atom+xml"
    href="https://docs.google.com/feeds/upload/create-session/default/private/full/document%3A12345"/>

Protocol

Here is the initial request:

PUT https://docs.google.com/feeds/upload/create-session/default/private/full/document%3A12345
Authorization: <your authorization header here>
If-Match: <ETag or * here>
Content-Length: 1000
Content-Type: text/plain
X-Upload-Content-Length: 1000
X-Upload-Content-Type: text/plain

<empty body>

To update a resource's metadata and content at the same time, include Atom XML instead of an empty body. See the example in the Initiating a resumable upload request section.

When the server responds with the unique upload URI, send a PUT with your payload. Once the unique upload URI is fetched, the process for updating the file's content is the same as uploading a file.

This is an example of updating an existing document's content all at once:

PUT <upload_uri>
Content-Length: 1000
Content-Range: 0-999/1000

<bytes 0-999>

.NET

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Instantiate an Authenticator object according to your authentication
      // mechanism (e.g. OAuth2Authenticator).
      // Authenticator authenticator =  ...

      // Instantiate a DocumentsListQuery object to retrieve documents.
      DocumentsListQuery query = new DocumentsListQuery();

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      if (feed.Entries.Count == 0)
      {
        // TODO: There were no documents, act accordingly.
      }

      // TODO: Choose a resource based on your app's needs.
      DocumentEntry entry = (DocumentEntry)feed.Entries[0];

      // Update the document's title
      entry.Title.Text = "example spreadsheet";

      // Set the media source
      entry.MediaSource = new MediaFileSource("c:\\new_contract.txt", "text/plain");

      // Instantiate the ResumableUploader component.
      ResumableUploader uploader = new ResumableUploader();

      // Set the handlers for the completion and progress events
      uploader.AsyncOperationCompleted += new AsyncOperationCompletedEventHandler(OnDone);
      uploader.AsyncOperationProgress += new AsyncOperationProgressEventHandler(OnProgress);

      // Start the update process.
      uploader.UpdateAsync(authenticator, entry, new object());
    }

    static void OnDone(object sender, AsyncOperationCompletedEventArgs e) {
        DocumentEntry entry = e.Entry as DocumentEntry;
    }

    static void OnProgress(object sender, AsyncOperationProgressEventArgs e) {
        int percentage = e.ProgressPercentage;
    }
  }
}

Forcing a new revision to be created when updating a resource

To force a new revision to be created when updating a resource, append new-revision=true to the PUT URL.

PUT https://docs.google.com/feeds/upload/create-session/default/private/full/document%3A12345?new-revision=true

Managing revisions of documents and files

Getting revisions of a document or file

Document and file revisions are available via the revisions feed. Every document or file entry has a pointing to the revisions feed:

<gd:feedLink rel="http://schemas.google.com/docs/2007/revisions"
    href="https://docs.google.com/feeds/default/private/full/resource_id/revisions"/>

Protocol

To fetch the revision history for an item, send an HTTP GET to the which has the rel attribute of http://schemas.google.com/docs/2007/revisions:

GET https://docs.google.com/feeds/default/private/full/resource_id/revisions
Authorization: <your authorization header here>

<feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/"
    xmlns:batch="http://schemas.google.com/gdata/batch" xmlns:gd="http://schemas.google.com/g/2005"
    xmlns:docs="http://schemas.google.com/docs/2007"
    gd:etag="W/&quot;CE4HQX08cCt7ImA9WxNTFEU.&quot;">
<id>https://docs.google.com/feeds/default/private/full/resource_id/revisions</id>
<updated>2009-08-17T04:22:10.378Z</updated>
<title>Document Revisions</title>
<link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"
    href="https://docs.google.com/feeds/default/private/full/resource_id/revisions"/>
<link rel="http://schemas.google.com/g/2005#batch" type="application/atom+xml"
    href="https://docs.google.com/feeds/default/private/full/resource_id/revisions/batch"/>
<link rel="self" type="application/atom+xml"
    href="https://docs.google.com/feeds/default/private/full/resource_id/revisions"/>
<openSearch:totalResults>6</openSearch:totalResults>
<openSearch:startIndex>1</openSearch:startIndex>
<entry>
  <id>https://docs.google.com/feeds/id/resource_id/revisions/0</id>
  <updated>2009-08-17T04:22:10.440Z</updated>
  <app:edited xmlns:app="http://www.w3.org/2007/app">2009-08-06T03:25:07.798Z</app:edited>
  <title>Revision 0</title>
  <content type="text/html" src="https://docs.google.com/feeds/download/documents/Export?docId=doc_id&amp;revision=0"/>
  <link rel="alternate" type="text/html"
      href="https://docs.google.com/Doc?id=doc_id&amp;revision=0"/>
  <link rel="self" type="application/atom+xml"
      href="https://docs.google.com/feeds/default/private/full/resource_id/revisions/0"/>
  <author>
    <name>user</name>
    <email>user@gmail.com</email>
  </author>
</entry>
<entry>
  <id>https://docs.google.com/feeds/id/resource_id/revisions/1</id>
  <updated>2009-08-17T04:22:10.440Z</updated>
  <app:edited xmlns:app="http://www.w3.org/2007/app">2009-08-06T03:25:07.799Z</app:edited>
  <title>Revision 1</title>
  <content type="text/html" src="https://docs.google.com/feeds/download/documents/Export?docId=doc_id&amp;revision=1"/>
  <link rel="alternate" type="text/html"
      href="https://docs.google.com/Doc?id=doc_id&amp;revision=1"/>
  <link rel="self" type="application/atom+xml"
      href="https://docs.google.com/feeds/default/private/full/resource_id/revisions/1"/>
  <author>
    <name>user</name>
    <email>user@gmail.com</email>
  </author>
</entry>
<entry>
  <id>https://docs.google.com/feeds/id/resource_id/revisions/2</id>
  <updated>2009-08-17T04:22:10.440Z</updated>
  <app:edited xmlns:app="http://www.w3.org/2007/app">2009-08-14T07:11:34.197Z</app:edited>
  <title>Revision 2</title>
  <content type="text/html" src="https://docs.google.com/feeds/download/documents/Export?docId=doc_id&amp;revision=2"/>
  <link rel="alternate" type="text/html"
      href="https://docs.google.com/Doc?id=doc_id&amp;revision=2"/>
  <link rel="self" type="application/atom+xml"
      href="https://docs.google.com/feeds/default/private/full/resource_id/revisions/2"/>
  <link rel="http://schemas.google.com/docs/2007#publish" type="text/html"
      href="https://docs.google.com/View?docid=doc_id&pageview=1&hgd=1"/>
  <author>
    <name>another_user</name>
    <email>another_user@gmail.com</email>
  </author>
  <docs:publish value="true"/>
  <docs:publishAuto value="true"/>
  <docs:publishOutsideDomain value="false"/>
</entry>
</feed>

.NET

The following code fetches the list of revision for the first document in a feed. It first prints out the title of the document, and then prints a list of all revisions of that document.

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a DocumentsListQuery object to retrieve documents.
      DocumentsListQuery query = new DocumentsListQuery();

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      if (feed.Entries.Count == 0)
      {
        // TODO: There were no documents, act accordingly.
      }

      // TODO: Choose a resource based on your app's needs.
      DocumentEntry entry = (DocumentEntry)feed.Entries[0];
      Console.WriteLine(entry.Title.Text);

      // Instantiate a RevisionQuery object to retrieve revisions.
      RevisionQuery revisionQuery = new RevisionQuery(entry.RevisionDocument);

      // Make a request to the API and get all revisions.
      RevisionFeed revisions = service.Query(revisionQuery);

      // Iterate through all of the revisions returned
      foreach (RevisionEntry revision in revisions.Entries)
      {
        // Print the title of this revision to the screen
        Console.WriteLine(revision.Title.Text);
        Console.WriteLine(revision.Publish);
        foreach (AtomPerson author in revision.Authors)
        {
            // Print the name of each revision's author to the screen
            Console.WriteLine(author.Name);
        }
      }
    }
  }
}

Properties of a revision entry:

  • The <updated> field is the timestamp a revision was created.
  • The <author> field is the creator of that revision.
  • A <docs:publish> field is present and set to true if the revision is published. The entry has a link with rel set to "http://schemas.google.com/docs/2007#publish" pointing to the published document on the web. A <docs:publishAuto> field is present if the revision is published. Its value is true if the "Automatically re-publish when changes are made" checkbox is selected in the Google Docs UI.
  • A <docs:publishOutsideDomain> field is present if the revision is published and the document is in a Google Apps domain. Its value is true (the default) if the document is published outside of the domain.

Downloading individual revisions

The <content> field's src attribute can be used to Export a particular revision in the API's supported exportFormats:

<content type="text/html" src="https://docs.google.com/feeds/download/documents/Export?docId=doc_id&revision=2"/>

The following example downloads 'Revision 2' (from the XML above) as a .txt file:

Protocol

GET https://docs.google.com/feeds/download/documents/Export?docId=doc_id&revision=2&exportFormat=txt
Authorization: <your authorization header here>

.NET

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a DocumentsListQuery object to retrieve documents.
      DocumentsListQuery query = new DocumentsListQuery();

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      if (feed.Entries.Count == 0)
      {
        // TODO: There were no documents, act accordingly.
      }

      // TODO: Choose a resource based on your app's needs.
      DocumentEntry entry = (DocumentEntry)feed.Entries[0];

      // Get the download url from the resource's content element
      string downloadUrl = entry.Content.Src.Content;

      // Add the exportFormat parameter
      downloadUrl += "&exportFormat=txt";

      // Add the revision parameter
      downloadUrl += "&revision=2";

      // Download the document as a stream
      Stream stream = service.Query(new Uri(downloadUrl));
    }
  }
}

Deleting file revisions

At this time, only file revisions may be deleted with the API. The ability to delete document revisions may be added in a later release.

To delete file revisions, simply send a DELETE request to the edit link of a revision entry.

DELETE https://docs.google.com/feeds/default/private/full/resource_id/revisions/revision_id

An HTTP 200 response indicates success in deleting the revision.

Protocol

DELETE https://docs.google.com/feeds/default/private/full/resource_id/revisions/revision_id
Authorization: <your authorization header here>

.NET

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a DocumentsListQuery object to retrieve documents.
      DocumentsListQuery query = new DocumentsListQuery();

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      if (feed.Entries.Count == 0)
      {
        // TODO: There were no documents, act accordingly.
      }

      // TODO: Choose a resource based on your app's needs.
      DocumentEntry entry = (DocumentEntry)feed.Entries[0];

      // Instantiate a RevisionQuery object to retrieve revisions.
      RevisionQuery revisionQuery = new RevisionQuery(entry.RevisionDocument);

      // Make a request to the API and get all revisions.
      RevisionFeed revisions = service.Query(revisionQuery);

      if (revisions.Entries.Count == 0)
      {
        // TODO: There were no revisions, act accordingly.
      }

      // TODO: Choose a revision based on your app's needs.
      RevisionEntry revision = (RevisionEntry)revisions.Entries[0];

      // Make a request to the API and delete the revision.
      revision.Delete();
    }
  }
}

Publishing documents by publishing a single revision

The API supports the following modifications to a document's published settings:

  • Publish/unpublish a document
  • Publish a document at a different revision
  • Change whether document changes are auto-republished
  • Change whether documents are published outside of a Google Apps domain

To change the published settings on a document, send an HTTP PUT to the edit link on the revision entry for the revision you want to change. The request body should contain the modified revision entry.

This example publishes revision 1 from the revision feed example above by adding the necessary published elements to the entry:

Protocol

PUT https://docs.google.com/feeds/default/private/full/resource_id/revisions/revision_number
Authorization: <your authorization header here>
Content-Length: 722
Content-Type: application/atom+xml

<entry xmlns="http://www.w3.org/2005/Atom" xmlns:gd='http://schemas.google.com/g/2005'
       xmlns:docs="http://schemas.google.com/docs/2007" gd:etag="W/"DkIBR3st7ImA9WxNbF0o."">
  <id>https://docs.google.com/feeds/id/resource_id/revisions/1</id>
  <updated>2009-08-17T04:22:10.440Z</updated>
  <app:edited xmlns:app="http://www.w3.org/2007/app">2009-08-06T03:25:07.799Z</app:edited>
  <title>Revision 1</title>
  <content type="text/html" src="https://docs.google.com/feeds/download/documents/Export?docId=doc_id&amp;revision=1"/>
  <link rel="alternate" type="text/html"
      href="https://docs.google.com/Doc?id=doc_id&amp;revision=1"/>
  <link rel="self" type="application/atom+xml"
      href="https://docs.google.com/feeds/default/private/full/resource_id/revisions/1"/>
  <author>
    <name>user</name>
    <email>user@gmail.com</email>
  </author>
  <docs:publish value="true"/>
  <docs:publishAuto value="false"/>
</entry>

.NET

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a DocumentsListQuery object to retrieve documents.
      DocumentsListQuery query = new DocumentsListQuery();

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      if (feed.Entries.Count == 0)
      {
        // TODO: There were no documents, act accordingly.
      }

      // TODO: Choose a resource based on your app's needs.
      DocumentEntry entry = (DocumentEntry)feed.Entries[0];

      // Instantiate a RevisionQuery object to retrieve revisions.
      RevisionQuery revisionQuery = new RevisionQuery(entry.RevisionDocument);

      // Make a request to the API and get all revisions.
      RevisionFeed revisions = service.Query(revisionQuery);

      if (revisions.Entries.Count == 0)
      {
        // TODO: There were no revisions, act accordingly.
      }

      // TODO: Choose a revision based on your app's needs.
      RevisionEntry revision = (RevisionEntry)revisions.Entries[0];

      // Change the publishing settings.
      revision.Publish = true;
      revision.PublishAuto = true;

      // Make a request to the API and update the revision.
      revision.Update();
    }
  }
}

Note that is set to false in order to allow a previous version of the document to be published. If is set to true, the document's head revision remains the version published.

Toggling properties of documents and files

Resources optionally have a number of category elements indicating that the given resource belongs to some category. Examples are the viewed, starred, and hidden categories. Boolean resource properties such as these may be toggled on or off.

To toggle a given property on when creating or updating a resource, provide the full category element representing the relevant category.

<entry>
...
<!-- Set the resource as viewed. -->
<category scheme="http://schemas.google.com/g/2005/labels" term="http://schemas.google.com/g/2005/labels#viewed" label="viewed"/>
...
</entry>

To toggle a given property off when creating or updating a resource, provide the category element, but set the label attribute to empty.

<entry>
...
<!-- Unstar the resource. -->
<category scheme="http://schemas.google.com/g/2005/labels" term="http://schemas.google.com/g/2005/labels#starred" label=""/>
...
</entry>

Copying documents

To duplicate a document in a user's Google Docs list, send an HTTP POST to the URI https://docs.google.com/feeds/default/private/full. The POST body must be an entry with an id element set to one of the following:

  • the self link of the entry from which you are copying
  • the resource ID of the source entry

The following example shows how to duplicate a document in Google Docs:

Protocol

This example uses the self link of the source entry:

POST https://docs.google.com/feeds/default/private/full
Authorization: <your authorization header here>
Content-Length: 292
Content-Type: application/atom+xml

<?xml version='1.0' encoding='UTF-8'?>
<entry xmlns="http://www.w3.org/2005/Atom">
  <id>https://docs.google.com/feeds/default/private/full/document:12345</id>
  <title>My Copy</title>
</entry>

.NET

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a DocumentsListQuery object to retrieve documents.
      DocumentsListQuery query = new DocumentsListQuery();

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      if (feed.Entries.Count == 0)
      {
        // TODO: There were no documents, act accordingly.
      }

      // TODO: Choose a resource based on your app's needs.
      DocumentEntry source = (DocumentEntry)feed.Entries[0];

      // Instantiate a DocumentEntry object to be inserted.
      DocumentEntry entry = new DocumentEntry();

      // Set the document title
      entry.Title.Text = "Copy of Legal Contract";

      // Copy the resource ID of the source document
      entry.Id = source.Id;

      // Make a request to the API and copy the document.
      entry = service.Insert(DocumentsListQuery.documentsBaseUri, entry);
    }
  }
}

Trashing documents and files

Trashing a document or file moves the resource to the user's trash collection. First, retrieve the entry for the document or file, then send a DELETE request to the entry's edit URL. This is the same URL used to update the document or file.

Protocol

DELETE https://docs.google.com/feeds/default/private/full/resource_id
If-Match: <ETag or * here>
Authorization: <your authorization header here>

.NET

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a DocumentsListQuery object to retrieve documents.
      DocumentsListQuery query = new DocumentsListQuery();

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      if (feed.Entries.Count == 0)
      {
        // TODO: There were no documents, act accordingly.
      }

      // TODO: Choose a resource based on your app's needs.
      DocumentEntry entry = (DocumentEntry)feed.Entries[0];

      // Make a request to the API and trash the document.
      service.Delete(entry);
    }
  }
}

If the resource is trashed successfully, the server responds with an HTTP 200 OK.

To protect against deleting a document or file that has been changed by another client since the entry was last retrieved, include an HTTP If-Match header that contains the original entry's ETag value. Determine the original entry's ETag value by examining the entry element's gd:etag attribute.

To delete the document or file regardless of whether another user has updated it since the entry was last retrieved, use If-Match: * and don't include the ETag. It's not necessary to retrieve the ETag entry attribute before deleting the document in this case.

Deleting documents and files

Deleting a document or file permanently removes the resource from the user's documents list. The process for deleting a document or file is similar to trashing, but you must include the delete=true parameter.

Protocol

DELETE https://docs.google.com/feeds/default/private/full/resource_id?delete=true
If-Match: <ETag or * here>
Authorization: <your authorization header here>

.NET

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a DocumentsListQuery object to retrieve documents.
      DocumentsListQuery query = new DocumentsListQuery();

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      if (feed.Entries.Count == 0)
      {
        // TODO: There were no documents, act accordingly.
      }

      // TODO: Choose a resource based on your app's needs.
      DocumentEntry entry = (DocumentEntry)feed.Entries[0];

      // Make a request to the API and delete the document.
      service.Delete(entry, true);
    }
  }
}

If the resource is deleted successfully, the server responds with an HTTP 200 OK.

Batching resource operations into a single request

The Google Documents List API supports GData batch processing. This allows clients to combine multiple operations into a single request that without batch processing are more than one request. For instance, a client can fetch resource A, create an empty resource B, update the metadata of resource C, and delete resource D, all in a single request. There are a number of advantages to performing batch operations, one of which is bandwidth conservation in bandwidth constrained environments.

To perform batch processing of operations, POST a resource feed to the batch link given with each Documents List API resource feed request.

<link rel="http://schemas.google.com/g/2005#batch" type="application/atom+xml"
    href="https://docs.google.com/feeds/default/private/full/batch"/>

Each resource in the POSTed feed must contain a batch:operation element, describing which operation to perform on the resource. Valid operations are query, insert, update, and delete.

When creating new, empty resources in a batch operation, assign the operations a batch:id so that clients can identify the new resource in the batch response.

The following is an example of a batch request and response that retrieves, creates, updates, and deletes four resources.

POST https://docs.google.com/feeds/default/private/full/batch
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"
    xmlns:docs="http://schemas.google.com/docs/2007"
    xmlns:batch="http://schemas.google.com/gdata/batch"
    xmlns:gd="http://schemas.google.com/g/2005">

  <entry>
    <id>https://docs.google.com/feeds/id/file:1234abcd</id>
    <batch:operation type="query"/>
  </entry>
  <entry>
    <!-- Since a new resource has no ID, specify a batch operation ID in
        order to identify this resource in the response. -->
    <batch:id>1</batch:id>
    <batch:operation type="insert"/>
    <category scheme="http://schemas.google.com/g/2005#kind"
        term="http://schemas.google.com/docs/2007#document"
        label="document"/>
   <title>New Text Document</title>
  </entry>
  <entry gd:etag=""SJDnxi3203sns"">
    <id>https://docs.google.com/feeds/id/drawing:5678efgh</id>
    <batch:operation type="update"/>
    <category scheme="http://schemas.google.com/g/2005#kind"
        term="http://schemas.google.com/docs/2007#drawing"
        label="drawing"/>
    <title>Updating Drawing</title>
  </entry>
  <entry gd:etag=""ghxcoi309sjhdDHD"">
    <id>https://docs.google.com/feeds/id/pdf:9012ijkl</id>
    <batch:operation type="delete"/>
  </entry>
</feed>

The corresponding response to the above request follows, containing one entry for each operation in the request.

<?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:docs="http://schemas.google.com/docs/2007"
    xmlns:batch="http://schemas.google.com/gdata/batch"
    xmlns:gd="http://schemas.google.com/g/2005">
  <id>https://docs.google.com/feeds/id/batch/1316013557203</id>
  <updated>2011-09-14T15:19:17.683Z</updated>
  <title>Batch Feed</title>
  <entry gd:etag=""Gk4MUA9MGSt7ImBr"">
    <id>https://docs.google.com/feeds/id/file:1234abcd</id>
    <published>2011-09-09T15:05:02.608Z</published>
    <updated>2011-09-10T22:55:20.141Z</updated>
    <app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-12T16:46:09.251Z</app:edited>
    <category scheme="http://schemas.google.com/g/2005/labels"
        term="http://schemas.google.com/g/2005/labels#viewed" label="viewed"/>
    <category scheme="http://schemas.google.com/g/2005#kind"
        term="http://schemas.google.com/docs/2007#file" label="file"/>
    <title>Photo of Doug falling in the pool</title>
    ...
    <batch:status code="200" reason="Success"/>
    <batch:operation type="query"/>
    ...
  </entry>
  <entry gd:etag=""Gk0ESAkKRCt7ImBr"">
    <id>https://docs.google.com/feeds/id/document:3456mnop</id>
    <published>2011-09-14T15:19:17.840Z</published>
    <updated>2011-09-14T15:19:19.053Z</updated>
    <app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-14T15:19:19.059Z</app:edited>
    <category scheme="http://schemas.google.com/g/2005#kind"
        term="http://schemas.google.com/docs/2007#document"
        label="document"/>
    <category scheme="http://schemas.google.com/g/2005/labels"
        term="http://schemas.google.com/g/2005/labels#viewed"
        label="viewed"/>
    <title>New Text Document</title>
    ...
    <batch:id>1</batch:id>
    <batch:status code="201" reason="Created"/>
    <batch:operation type="insert"/>
    ...
  </entry>
  <entry gd:etag=""Gk0EUhxCASt7ImBr"">
    <id>https://docs.google.com/feeds/id/drawing:5678efgh</id>
    <published>2011-09-01T16:11:17.781Z</published>
    <updated>2011-09-14T15:26:42.209Z</updated>
    <app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-14T15:26:42.211Z</app:edited>
    <category scheme="http://schemas.google.com/g/2005/labels"
        term="http://schemas.google.com/g/2005/labels#viewed"
        label="viewed"/>
    <category scheme="http://schemas.google.com/g/2005#kind"
        term="http://schemas.google.com/docs/2007#drawing"
        label="drawing"/>
    <title>Updating Drawing</title>
    ...
    <batch:status code="200" reason="Success"/>
    <batch:operation type="update"/>
    ...
  </entry>
  <entry>
    <id>https://docs.google.com/feeds/id/pdf:9012ijkl</id>
    <updated>2011-09-14T15:26:42.765Z</updated>
    <title>Deleted</title>
    <content>Deleted</content>
    <batch:status code="200" reason="Success"/>
    <batch:operation type="delete"/>
  </entry>
</feed>

Managing collections and their contents

Before reading this section, make sure you read the Terminology used in this guide.

The API allows you to manage collections in the Google Docs user interface. With the API, you can create, retrieve, update, trash, and delete collections. Other operations, like "move", are provided via create, retrieve, update, and delete operations on a collection's content feed.

How Google Docs organizes and manages collections

Collections allow a resource to maintain a "many to many" relationship with each other. In other words, collections allow resources to exist in multiple collections at the same time. Collections are conceptually similar to "labels" in Gmail, except that collections also allow for hierarchy. This is possible because a collection is also a resource, and therefore can also exist within other collections, allowing this hierarchy to form in a composite pattern.

In general, resources link directly to the collection that contains them. In the API, every resource has a set of parent links, and each link represents a link to a collection that contains that given resource. A parent link cannot occur more than once in a resource's set of parent links, and the set of parent links is always of size 0 or greater.

If a resource does not link to a named collection that's visible in the Google Docs user interface, it is usually in the "root" collection by default.

There are two cases where a resource may not be linked to a visible parent collection and will not appear in the "root" collection. In both of these cases, the resource still appears in the user's feed.

The first case is when a resource is shared with a user but not placed in a collection. In this case, the resource appears in the user's feed, and does not appear in any collection, including the "root" collection.

The second case is when a resource is shared with a Google Apps domain, not placed in a collection, and opened up for viewing by the user. In this case the resource is in no collections, including the root, but appears in the user's feed.

The "root" collection itself only exists in the API and is not directly represented in the user interface. Instead, all of a user's resources fall under the visual labels "All items," "My collections," and "Collections shared with me."

The overall hierarchy of a given account is complex and can't be visualized like a "tree" despite having a root collection. Instead, think of it more like an interconnected net attached to a single root point. The root collection contains other collections, documents, and files, but beyond this, there isn't necessarily a linear hierarchy. Documents and files within "root" may also exist in other collection, creating a complex web of relationships between resources.

Getting a list of collections

To get a list of all collections for a user, use the collection search query. To include collections in result sets that would normally just include documents and files, add showfolders=true to the URL. Collections are by default not included in API responses that do not contain exclusively collections (e.g. a request to /feeds/default/private/full will not include collection entries by default). Thus, to search for collections by title, see the section Searching for documents and files, and just add showfolders=true to any of the search examples given there.

Determining which resources are in the root collection

To determine which resources are in the root collection, attach showroot=true to any HTTP request to the API that returns resources.

Protocol

GET https://docs.google.com/feeds/default/private/full?showroot=true
Authorization: <your authorization header here>

This will cause the API to return a feed of resources that looks something like:

<entry xmlns:gd="http://schemas.google.com/g/2005" gd:etag="'HhJSFgpeRyt7ImBq'">
  ...
  <title>PDF's Title</title>
  ...
</entry>
<entry xmlns:gd="http://schemas.google.com/g/2005" gd:etag="'HhJSFgpeRyt7ImBq'">
  ...
  <title>PDF's Title</title>
  ...
  <link rel="http://schemas.google.com/docs/2007#parent"
      type="application/atom+xml"
      href="https://docs.google.com/feeds/default/private/full/folder%3Aroot"
      title="My items"/>
  ...
</entry>
...

.NET

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a DocumentsListQuery object to retrieve documents.
      DocumentsListQuery query = new DocumentsListQuery();

      // Set the ShowRoot parameter.
      query.ShowRoot = true;

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);
    }
  }
}

Note how the second resource in the above example actually belongs to the root collection, while the first resource does not. My items is not necessarily always the name of the root collection. Detect the root collection instead by using the resource ID folder:root.

The showroot parameter does not cause the root collection to show up as a separate entry in feeds of collections. It only causes the root collection to be shown as a parent of relevant resources. For instance, if you made the following request, you would NOT see the root collection as an entry. The root collection would be included, as appropriate, in the parent list of the resulting collection entries.

https://docs.google.com/feeds/default/private/full/-/folder?showroot=true

When getting entries back from API feeds, you will never find a resource entry with a resource ID of folder:root because the root collection does not have its own entry. You cannot update, delete, move, or otherwise change the root collection.

The resource ID of the root collection will always be folder:root, and its parent link href in resource entries will always be:

https://docs.google.com/feeds/default/private/full/folder%3Aroot

When writing code that interfaces with the API and uses the root collection, it is recommended you declare a constant for the above link, and use that to test for presence of a root collection parent link.

If you're looking for things that are only in the root collection, an easier way to find them is to make the following query:

https://docs.google.com/feeds/default/private/full/folder%3Aroot/contents

Because the root collection is almost like any other collection, it has a contents feed, which is described in more detail below.

A list of collections in the root collection can be queried using the root collection's collection category feed:

https://docs.google.com/feeds/default/private/full/folder%3Aroot/contents/-/folder

Similarly, a list of spreadsheets in the root collection can be queried using the root collection's spreadsheet category feed:

https://docs.google.com/feeds/default/private/full/folder%3Aroot/contents/-/spreadsheet

Getting the metadata and contents of an individual collection

To retrieve a list of items in a particular collection, send an HTTP GET to the collection's feed URL:

https://docs.google.com/feeds/default/private/full/folder%3Acollection_id/contents

By default, collection entries will also be returned within the collections feed (e.g. you don't have to include the showfolders=true parameter).

Protocol

GET https://docs.google.com/feeds/default/private/full/folder%3Acollection_id/contents
Authorization: <your authorization header here>

The feed of a collection's contents will look something like this:

<feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/"
    xmlns:docs="http://schemas.google.com/docs/2007" xmlns:batch="http://schemas.google.com/gdata/batch" xmlns:gd="http://schemas.google.com/g/2005"
    gd:etag="W/&quot;DkQDQH4_eSt7ImA9WxNTEkw.&quot;">

<!-- Unique identifier of this feed.  Not unique between users. -->
<id>https://docs.google.com/feeds/default/private/full/folder%3A0B9kQ4KIBsdfYzNmNiMjI4N/contents</id>

<!-- Date this collection's contents were last updated.  Do NOT use this, provided for Atom compliance only. -->
<updated>2009-08-14T01:46:11.041Z</updated>

<!-- Title of this feed result. -->
<title>Available Documents - john.smith.example@gmail.com</title>

<!-- Link at which a user could see this collection's contents in a web browser. -->
<link rel="alternate" type="text/html" href="https://docs.google.com/#folders/folder.0.0B9kQ4KIBsdfYzNmNiMjI4N"/>

<!-- Link at which you can fetch this same feed. -->
<link rel="self" type="application/atom+xml"
    href="https://docs.google.com/feeds/default/private/full/folder%3A0B9kQ4KIBsdfYzNmNiMjI4N/contents"/>

<!-- Link at which you can fetch this same feed. -->
<link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"
    href="https://docs.google.com/feeds/default/private/full/folder%3A0B9kQ4KIBsdfYzNmNiMjI4N/contents"/>

<!-- Link at which you can POST new entries with metadata only to this feed (e.g. to add items to this collection). -->
<link rel="http://schemas.google.com/g/2005#post" type="application/atom+xml"
    href="https://docs.google.com/feeds/default/private/full/folder%3A0B9kQ4KIBsdfYzNmNiMjI4N/contents"/>

<!-- Link at which you can send batch requests to this feed.  NOT supported by Documents List API, provided for GData compliance. -->
<link rel="http://schemas.google.com/g/2005#batch" type="application/atom+xml"
    href="https://docs.google.com/feeds/default/private/full/folder%3A0B9kQ4KIBsdfYzNmNiMjI4N/contents/batch"/>

<!-- Information about the owner of this collection. -->
<author>
  <name>John Smith</name>
  <email>john.smith.example@gmail.com</email>
</author>

<!-- NOT supported, provided for protocol compliance only. -->
<openSearch:startIndex>1</openSearch:startIndex>

<entry gd:etag=""BEFd33dgfImBr"">
  <id>https://docs.google.com/feeds/id/document%3A1j8yrZUCg234gdsgaxcz7tyBDHsy_vZeUfXfZNAffHatXXqk</id>
  <published>2011-04-13T10:44:28.877Z</published>
  <updated>2011-04-13T10:44:29.253Z</updated>
  <app:edited xmlns:app="http://www.w3.org/2007/app">2011-04-13T10:44:30.113Z</app:edited>
  <category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/docs/2007#document" label="document"/>
  <category scheme="http://schemas.google.com/g/2005/labels" term="http://schemas.google.com/g/2005/labels#viewed" label="viewed"/>
  <title>My document</title>
  <content type="text/html" src="https://docs.google.com/feeds/download/documents/export/Export?id=1j8yrZUCg234gdsgaxcz7tyBDHsy_vZeUfXfZNAffHatXXqk"/>
  <link rel="http://schemas.google.com/docs/2007#parent" type="application/atom+xml" href="https://docs.google.com/feeds/default/private/full/folder%3A0B9kQ4KIBsdfYzNmNiMjI4N" title="Example Folder"/>
  <link rel="alternate" type="text/html" href="https://docs.google.com/a/google.com/document/d/1j8yrZUCg234gdsgaxcz7tyBDHsy_vZeUfXfZNAffHatXXqk/edit?hl=en"/>
  <link rel="http://schemas.google.com/g/2005#resumable-edit-media" type="application/atom+xml" href="https://docs.google.com/feeds/upload/create-session/default/private/full/document%3A1j8yrZUCg234gdsgaxcz7tyBDHsy_vZeUfXfZNAffHatXXqk"/>
  <link rel="http://schemas.google.com/docs/2007/thumbnail" type="image/jpeg" href="https://lh6.googleusercontent.com/q78pafbgaRCrpzxcbdfgw437h4o-Jqv1s5MS7vwaIBfWxMSXIEg9-geu2g73EvvV5oiTlunjpnf9H0OQ=s220"/>
  <link rel="self" type="application/atom+xml" href="https://docs.google.com/feeds/default/private/full/folder%3A0B9kQ4KIBsdfYzNmNiMjI4N/contents/document%3A1j8yrZUCgmanua9Rz7tyBDHsy_vZeUfXfZNAzHatXXqk"/>
  <link rel="edit" type="application/atom+xml" href="https://docs.google.com/feeds/default/private/full/folder%3A0B9kQ4KIBsdfYzNmNiMjI4N/contents/document%3A1j8yrZUCgmanua9Rz7tyBDHsy_vZeUfXfZNAzHatXXqk"/>
  <link rel="edit-media" type="text/html" href="https://docs.google.com/feeds/default/contentmedia/folder%3A0B9kQ4KIBsdfYzNmNiMjI4N/document%3A1j8yrZUCgmanua9Rz7tyBDHsy_vZeUfXfZNAzHatXXqk"/>
  <author>
    <name>user</name>
    <email>user@gmail.com</email>
  </author>
  <gd:resourceId>document:1j8yrZUCg234gdsgaxcz7tyBDHsy_vZeUfXfZNAffHatXXqk</gd:resourceId>
  <gd:lastModifiedBy>
    <name>user</name>
    <email>user@gmak..com</email>
  </gd:lastModifiedBy>
  <gd:lastViewed>2011-04-13T10:44:29.253Z</gd:lastViewed>
  <gd:quotaBytesUsed>0</gd:quotaBytesUsed>
  <docs:writersCanInvite value="true"/>
  <gd:feedLink rel="http://schemas.google.com/acl/2007#accessControlList" href="https://docs.google.com/feeds/default/private/full/document%3A1j8yrZUCgmanua9Rz7tyBDHsy_vZeUfXfZNAzHatXXqk/acl"/>
  <gd:feedLink rel="http://schemas.google.com/docs/2007/revisions" href="https://docs.google.com/feeds/default/private/full/document%3A1j8yrZUCgmanua9Rz7tyBDHsy_vZeUfXfZNAzHatXXqk/revisions"/>
</entry>

...
</feed>

.NET

The following code fetches a list of the currently authenticated user's folders, then prints out the content of the first of them.

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a FolderQuery object to retrieve folders.
      FolderQuery query = new FolderQuery();

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      if (feed.Entries.Count == 0)
      {
        // TODO: There were no folders, act accordingly.
      }

      // TODO: Choose a folder based on your app's needs.
      DocumentEntry folder = (DocumentEntry)feed.Entries[0];

      // Instantiate a FolderQuery object to retrieve the content of the folder.
      FolderQuery contentQuery = new FolderQuery(folder.ResourceId);

      // Make a request to the API and get the folder contents.
      DocumentsFeed contents = service.Query(contentQuery);

      // Iterate through all of the documents returned
      foreach (DocumentEntry entry in contents.Entries) {
      {
        // Print the title of this document to the screen
        Console.WriteLine(entry.Title.Text);
        Console.WriteLine(entry.Title.Text);
      }
    }
  }
}

Creating collections

To create a collection, send an HTTP POST request with an <atom:entry> containing a category element with http://schemas.google.com/g/2005#kind scheme and http://schemas.google.com/docs/2007#folder term. The collection name is determined by the value of the atom:title element if present. If no atom:title element is submitted, a default name is chosen.

Here is an example of creating a collection titled Example Collection.

Protocol

POST https://docs.google.com/feeds/default/private/full
Authorization: <your authorization header here>
Content-Length: 245
Content-Type: application/atom+xml

<?xml version='1.0' encoding='UTF-8'?>
<entry xmlns="http://www.w3.org/2005/Atom">
  <category scheme="http://schemas.google.com/g/2005#kind"
      term="http://schemas.google.com/docs/2007#folder"/>
  <title>Example Collection</title>
</entry>

.NET

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a DocumentEntry object to be inserted.
      DocumentEntry folder = new DocumentEntry();

      // Set the folder category.
      folder.IsFolder = true;

      // Set the folder title.
      folder.Title.Text = "Example Collection";

      // Make a request to the API and create the folder.
      DocumentEntry newFolder = service.Insert(DocumentsListQuery.documentsBaseUri, folder);
    }
  }
}

If the request is successful, a 201 Created response is returned along with a <atom:entry> describing the collection on the server.

Creating subcollections

Creating a subcollection is similar to creating a normal collection. This example creates a new subcollection named new subcollection by POSTing to the contents link of the target parent collection.

Protocol

POST https://docs.google.com/feeds/default/private/full/folder%3Acollection_id/contents
Authorization: <your authorization header here>
Content-Length: 244
Content-Type: application/atom+xml

<?xml version='1.0' encoding='UTF-8'?>
<entry xmlns="http://www.w3.org/2005/Atom">
  <category scheme="http://schemas.google.com/g/2005#kind"
      term="http://schemas.google.com/docs/2007#folder"/>
  <title>New subcollection</title>
</entry>

.NET

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a FolderQuery object to retrieve folders.
      FolderQuery query = new FolderQuery();

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      if (feed.Entries.Count == 0)
      {
        // TODO: There were no folders, act accordingly.
      }

      // TODO: Choose a folder based on your app's needs.
      DocumentEntry folder = (DocumentEntry)feed.Entries[0];

      // Instantiate a FolderQuery object to retrieve the content of the folder.
      FolderQuery contentQuery = new FolderQuery(folder.ResourceId);

      // Instantiate a DocumentEntry object to be inserted.
      DocumentEntry subfolder = new DocumentEntry();

      // Set the folder category.
      subfolder.IsFolder = true;

      // Set the folder title.
      subfolder.Title.Text = "Example Collection";

      // Make a request to the API and create the subfolder.
      DocumentEntry newFolder = service.Insert(contentQuery.Uri, subfolder);
    }
  }
}

Adding a resource to a collection

To add a resource to a collection, send an HTTP POST request to the contents feed of the destination collection. The feed URL will have the collection ID represented by destination_collection_id in the example below. The request should contain an <atom:entry> with the document's <atom:id> you want to add.

Protocol

POST https://docs.google.com/feeds/default/private/full/folder%3Adestination_collection_id/contents
Authorization: <your authorization header here>
Content-Length: 180
Content-Type: application/atom+xml

<?xml version='1.0' encoding='UTF-8'?>
<entry xmlns="http://www.w3.org/2005/Atom">
  <id>https://docs.google.com/feeds/default/private/full/document:1234abcd</id>
</entry>

.NET

The following code copies the first of the currently authenticated user's documents into the first folder.

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a FolderQuery object to retrieve folders.
      FolderQuery folderQuery = new FolderQuery();

      // Make a request to the API and get all folder.
      DocumentsFeed folderFeed = service.Query(folderQuery);

      if (folderFeed.Entries.Count == 0)
      {
        // TODO: There were no folders, act accordingly.
      }

      // TODO: Choose a folder based on your app's needs.
      DocumentEntry folder = (DocumentEntry)folderFeed.Entries[0];

      // Instantiate a FolderQuery object to retrieve the content of the folder.
      FolderQuery contentQuery = new FolderQuery(folder.ResourceId);

      // Instantiate a DocumentsListQuery object to retrieve documents.
      DocumentsListQuery query = new DocumentsListQuery();

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      if (feed.Entries.Count == 0)
      {
        // TODO: There were no documents, act accordingly.
      }

      // TODO: Choose a document based on your app's needs.
      DocumentEntry source = (DocumentEntry)feed.Entries[0];

      // Instantiate a DocumentEntry object to be inserted.
      DocumentEntry entry = new DocumentEntry();

      // Copy the resource ID of the source document
      entry.Id = source.Id;

      // Make a request to the API and copy the document into the folder.
      entry = service.Insert(contentQuery.Uri, entry);
    }
  }
}

The entry is a word processor document with ID document_id.

Removing a resource from collection

To remove a resource from a collection, send an HTTP DELETE request to the collection content entry's edit link. The edit link will have a collection ID and a resource ID, represented by collection_id and resource_id respectively in the example below.

Protocol

DELETE https://docs.google.com/feeds/default/private/full/folder%3Acollection_id/contents/resource_id
Authorization: <your authorization header here>

.NET

The following code removes the first document from the first of the currently authenticated user's folders.

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a FolderQuery object to retrieve folders.
      FolderQuery folderQuery = new FolderQuery();

      // Make a request to the API and get all folder.
      DocumentsFeed folderFeed = service.Query(folderQuery);

      if (folderFeed.Entries.Count == 0)
      {
        // TODO: There were no folders, act accordingly.
      }

      // TODO: Choose a folder based on your app's needs.
      DocumentEntry folder = (DocumentEntry)folderFeed.Entries[0];

      // Instantiate a FolderQuery object to retrieve the content of the folder.
      FolderQuery contentQuery = new FolderQuery(folder.ResourceId);

      // Make a request to the API and get the folder contents.
      DocumentsFeed contentFeed = service.Query(contentQuery);

      if (contentFeed.Entries.Count == 0)
      {
        // TODO: There were no documents, act accordingly.
      }

      // TODO: Choose a document based on your app's needs.
      DocumentEntry entry = (DocumentEntry)contentFeed.Entries[0];

      // Make a request to the API and remove the document from the folder.
      entry.Delete();
    }
  }
}

Trashing collections

Trashing a collection moves the collection to the trash.

Protocol

DELETE https://docs.google.com/feeds/default/private/full/folder:12345
If-Match: <ETag or * here>

.NET

The following code removes the first of the currently authenticated user's folders.

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a FolderQuery object to retrieve folders.
      FolderQuery query = new FolderQuery();

      // Make a request to the API and get all folder.
      DocumentsFeed feed = service.Query(query);

      if (feed.Entries.Count == 0)
      {
        // TODO: There were no folders, act accordingly.
      }

      // TODO: Choose a folder based on your app's needs.
      DocumentEntry folder = (DocumentEntry)feed.Entries[0];

      service.Delete(folder);
    }
  }
}

If the collection is trashed successfully, the server responds with an HTTP 200 OK.

Deleting collections

Deleting a collection permanently removes the collection from the user's documents list. The process for deleting a collection is similar to trashing a collection, just include the delete=true parameter.

Protocol

DELETE https://docs.google.com/feeds/default/private/full/resource_id?delete=true
If-Match: <ETag or * here>

.NET

The following code removes the first of the currently authenticated user's folders.

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a FolderQuery object to retrieve folders.
      FolderQuery query = new FolderQuery();

      // Make a request to the API and get all folder.
      DocumentsFeed feed = service.Query(query);

      if (feed.Entries.Count == 0)
      {
        // TODO: There were no folders, act accordingly.
      }

      // TODO: Choose a folder based on your app's needs.
      DocumentEntry folder = (DocumentEntry)feed.Entries[0];

      service.Delete(folder, true);
    }
  }
}

If the collection is deleted successfully, the server responds with an HTTP 200 OK.

Managing sharing permissions of resources via Access Control Lists (ACLs)

Overview of sharing with ACLs

Document and collection sharing is controlled via the access control list feed. Access control lists are just basic lists that show who has access to a given resource. In the ACL feed, the following roles are available for a given document or folder:

owner
the owner of the document. As an owner you have the ability to modify the ACL feed, delete the document, etc.
writer
a collaborator.
reader
a viewer (equivalent to read-only access).

The API supports sharing permissions on multiple levels. These values correspond to the type attribute:

user
a user's email address.
group
a Google Group email address.
domain
a Google Apps domain.
default
publicly shared with all users.

Additional roles are also supported. A list of potential roles for each resource type is provided in the metadata feed. One example of an additional role is the commenter role, which indicates users matching the scope and role of an ACL entry can also comment on a resource, only if the additional role is valid for the generic role as defined in the metadata feed. Additional role values correspond to the value attribute. Additional roles are valid elements in a normal ACL entry, or in a withKey ACL entry.

Retrieving the ACL for a document, file, or collection

The ACL feed can be retrieved by accessing the <gd:feedLink> element of an entry with rel attribute http://schemas.google.com/acl/2007#accessControlList. Please note that you must use the full projection to receive gd specific extension elements in your Documents List feed.

This feed will contain an element for each ACL entry that exists for the given document.

Protocol

GET https://docs.google.com/feeds/default/private/full/resource_id/acl
Authorization: <your authorization header here>

The XML snippet below shows the ACL feed for the example document. Note that the feed contains three ACL entries. The element of each ACL entry ends with the email address of the specific user that the ACL entry corresponds to:

document.owner@example.com
the ACL entry for the document's owner
a.writer@example.com
the ACL entry for a collaborator
a.reader@example.com
the ACL entry for a reader that can also comment
<?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:gAcl='http://schemas.google.com/acl/2007'
    xmlns:gd='http://schemas.google.com/g/2005'
    gd:etag='W/"CUUNSXYyfCp7ImA9WxRVGUo."'>
  <id>https://docs.google.com/feeds/default/private/full/document%3Adocument_id/acl</id>
  <updated>2008-09-03T22:03:04.733Z</updated>
  <category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/acl/2007#accessRule' />
  <title type='text'>Document Permissions</title>
  <link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml'
  href='https://docs.google.com/feeds/default/private/full/document%3Adocument_id/acl' />
  <link rel='http://schemas.google.com/g/2005#post' type='application/atom+xml'
  href='https://docs.google.com/feeds/default/private/full/document%3Adocument_id/acl' />
  <link rel='self' type='application/atom+xml'
  href='https://docs.google.com/feeds/default/private/full/document%3Adocument_id/acl' />
  <openSearch:totalResults>3</openSearch:totalResults>
  <openSearch:startIndex>1</openSearch:startIndex>
  <entry gd:etag='W/"CUUNSXYyfCp7ImA9WxRVGUo."'>
    <id>https://docs.google.com/feeds/default/private/full/document%3Adocument_id/acl/user%3Adocument.owner%40example.com</id>
    <updated>2008-09-03T22:03:04.756Z</updated>
    <category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/acl/2007#accessRule' />
    <title type='text'>Document Permission - document.owner@example.com</title>
    <link rel='self' type='application/atom+xml'
    href='https://docs.google.com/feeds/default/private/full/document%3Adocument_id/acl/user%3Adocument.owner%40example.com' />
    <link rel='edit' type='application/atom+xml'
    href='https://docs.google.com/feeds/default/private/full/document%3Adocument_id/acl/user%3Adocument.owner%40example.com' />
    <gAcl:role value='owner' />
    <gAcl:scope type='user' value='document.owner@example.com' />
  </entry>
  <entry gd:etag='W/"CUMFQnc4fip7ImA9WxRVGUo."'>
    <id>https://docs.google.com/feeds/default/private/full/document%3Adocument_id/acl/user%3Aa.writer%40example.com<>
    <updated>2008-09-03T22:03:04.762Z</updated>
    <category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/acl/2007#accessRule' />
    <title type='text'>Document Permission - a.writer@example.com</title>
    <link rel='self' type='application/atom+xml'
    href='https://docs.google.com/feeds/default/private/full/document%3Adocument_id/acl/user%3Aa.writer%40example.com' />
    <link rel='edit' type='application/atom+xml'
    href='https://docs.google.com/feeds/default/private/full/document%3Adocument_id/acl/user%3Aa.writer%40example.com' />
    <gAcl:role value='writer' />
    <gAcl:scope type='user' value='a.writer@example.com' />
  </entry>
  <entry gd:etag='W/"CUMASXg8fCp7ImA9WxRVGUo."'>
    <id>https://docs.google.com/feeds/default/private/full/document%3Adocument_id/acl/user%3Aa.reader%40example.com</id>
    <updated>2008-09-03T22:03:04.763Z</updated>
    <category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/acl/2007#accessRule' />
    <title type='text'>Document Permission - a.reader@example.com</title>
    <link rel='self' type='application/atom+xml'
    href='https://docs.google.com/feeds/default/private/full/document%3Adocument_id/acl/user%3Aa.reader%40example.com' />
    <link rel='edit' type='application/atom+xml'
    href='https://docs.google.com/feeds/default/private/full/document%3Adocument_id/acl/user%3Aa.reader%40example.com' />
    <gAcl:role value='reader'/>
    <gAcl:additionalRole value='commenter'/>
    <gAcl:scope type='user' value='a.reader@example.com' />
  </entry>
</feed>

.NET

The following code fetches a list of the currently authenticated user's documents, and prints out the ACLs of the first of them.

using System;
using Google.GData.AccessControl;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a DocumentsListQuery object to retrieve documents.
      DocumentsListQuery query = new DocumentsListQuery();

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      if (feed.Entries.Count == 0)
      {
        // TODO: There were no documents, act accordingly.
      }

      // TODO: Choose a resource based on your app's needs.
      DocumentEntry entry = (DocumentEntry)feed.Entries[0];

      // Instantiate a AclQuery object to retrieve ACLs.
      AclQuery aclQuery = new AclQuery(entry.AccessControlList);

      // Make a request to the API and get all ACLs for the document.
      AclFeed aclFeed = service.Query(aclQuery);

      // Iterate through all of the ACLs returned
      foreach (AclEntry acl in aclFeed.Entries)
      {
        // Print the acl Role to the screen
        Console.WriteLine(acl.Role.Value);
        // Print the acl Scope type and value to the screen
        Console.WriteLine(acl.Scope.Type + " - " + acl.Scope.Value);
      }
    }
  }
}

Updating sharing permissions

The ACL feed accepts GET, POST and PUT requests. To insert a new role into the ACL feed, simply issue a POST request.

Protocol

The example below shows how to share a document with a single collaborator:

POST https://docs.google.com/feeds/default/private/full/resource_id/acl
Authorization: <your authorization header here>

<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:role value='writer'/>
  <gAcl:scope type='user' value='new_writer@example.com'/>
</entry>

The new entry is returned on a successful insertion:

201 Created

<entry gd:etag='W/"CUUNSXYyfCp7ImA9WxRVGUo."'>
  <id>https://docs.google.com/feeds/default/private/full/document:1234abcd/acl/user:new_writer@example.com</id>
  <updated>2008-09-11T03:10:00.913Z</updated>
  <category scheme='http://schemas.google.com/g/2005#kind'
        term='http://schemas.google.com/acl/2007#accessRule'/>
  <title type='text'>Document Permission - new_writer@example.com</title>
  <link rel='self' type='application/atom+xml'
        href='https://docs.google.com/feeds/acl/private/full/document:1234abcd/acl/user:new_writer@example.com'/>
  <link rel='edit' type='application/atom+xml'
        href='https://docs.google.com/feeds/acl/private/full/document:1234abcd/acl/user:new_writer@example.com'/>
  <gAcl:role value='writer'/>
  <gAcl:scope type='user' value='new_writer@example.com'/>
</entry>

.NET

The following code shares the first document in the feed with a single collaborator.

using System;
using Google.GData.AccessControl;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a DocumentsListQuery object to retrieve documents.
      DocumentsListQuery query = new DocumentsListQuery();

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      if (feed.Entries.Count == 0)
      {
        // TODO: There were no documents, act accordingly.
      }

      // TODO: Choose a resource based on your app's needs.
      DocumentEntry entry = (DocumentEntry)feed.Entries[0];

      // Instantiate a AclEntry object to update sharing permissions.
      AclEntry acl = new AclEntry();

      // Set the ACL scope.
      acl.Scope = new AclScope("new_writer@example.com", "user");

      // Set the ACL role.
      acl.Role = new AclRole("writer");

      // Insert the new role into the ACL feed.
      service.Insert(new Uri(entry.AccessControlList), acl);
    }
  }
}

To update the entry, we will need to issue an HTTP PUT request to the entry's edit link, which is simply a element, whose rel attribute is set to edit. In our case it is:

<link rel='edit'
      type='application/atom+xml'
      href='https://docs.google.com/feeds/default/private/full/document:1234abcd/acl/user:new_writer@example.com'/>

The snippet below changes the entry's role to that of a 'reader':

Protocol

PUT https://docs.google.com/feeds/default/private/full/document:1234abcd/acl/user:new_writer@example.com

<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/"CUUNSXYyfCp7ImA9WxRVGUo."'>
  <category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/acl/2007#accessRule'/>
  <gAcl:role value='reader'/>
  <gAcl:additionalRole value='commenter'/>
  <gAcl:scope type='user' value='new_writer@gmail.com'/>
</entry>

.NET

The following code fetches a list of the currently authenticated user's documents, and changes the ACL's role of the first of them.

using System;
using Google.GData.AccessControl;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a DocumentsListQuery object to retrieve documents.
      DocumentsListQuery query = new DocumentsListQuery();

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      if (feed.Entries.Count == 0)
      {
        // TODO: There were no documents, act accordingly.
      }

      // TODO: Choose a resource based on your app's needs.
      DocumentEntry entry = (DocumentEntry)feed.Entries[0];

      // Instantiate a AclQuery object to retrieve ACLs.
      AclQuery aclQuery = new AclQuery(entry.AccessControlList);

      // Make a request to the API and get all ACLs for the document.
      AclFeed aclFeed = service.Query(aclQuery);

      // TODO: Choose a ACL based on your app's needs.
      AclEntry acl = (AclEntry)aclFeed.Entries[0];

      // Change the ACL's role.
      acl.Role = new AclRole("reader");

      // Update the ACL entry.
      acl.Update();
    }
  }
}

Email notifications of ACL changes

Creating an ACL entry that shares a document or collection with users will by default notify relevant users via email that they have new access to the document or collection.

However, these emails can be disabled by attaching the send-notification-emails parameter to ACL URIs when modifying an ACL. An example:

POST https://docs.google.com/feeds/default/private/full/document:12345/acl?send-notification-emails=false

Removing sharing permissions

To remove permissions for this user, issue a DELETE request to the same edit link that was used for the PUT request:

Protocol

DELETE https://docs.google.com/feeds/default/private/full/resource_id/acl/user:new_writer@example.com
Authorization: <your authorization header here>

.NET

The following code fetches a list of the currently authenticated user's documents, and deletes the first ACL of the first document.

using System;
using Google.GData.AccessControl;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a DocumentsListQuery object to retrieve documents.
      DocumentsListQuery query = new DocumentsListQuery();

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      if (feed.Entries.Count == 0)
      {
        // TODO: There were no documents, act accordingly.
      }

      // TODO: Choose a resource based on your app's needs.
      DocumentEntry entry = (DocumentEntry)feed.Entries[0];

      // Instantiate a AclQuery object to retrieve ACLs.
      AclQuery aclQuery = new AclQuery(entry.AccessControlList);

      // Make a request to the API and get all ACLs for the document.
      AclFeed aclFeed = service.Query(aclQuery);

      // TODO: Choose a ACL based on your app's needs.
      AclEntry acl = (AclEntry)aclFeed.Entries[0];

      // Delete the ACL entry.
      acl.Delete();
    }
  }
}

Sharing collections

To share a collection, provide a collection resource ID instead of a document ID. This example grants everyone on the domain example.com the ability to read the collection's content:

POST https://docs.google.com/feeds/default/private/full/folder%3Acollection_id/acl
Authorization: <your authorization header here>

<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:role value='reader'/>
<gAcl:scope type='domain' value='example.com'/>
</entry>

Sharing resources with a group or Google Apps domain

Similar to sharing with a single user, you can share resources across a group or domain if you have a Google Apps domain, or with all Google Docs users.

Sharing to a group email address

<gAcl:scope type="group" value="group@example.com"/>

Sharing to an entire domain

<gAcl:scope type="domain" value="example.com"/>

Sharing resources with the public (the rest of the Internet)

Doing this shares a resource to all Google users, e.g. "the public".

<gAcl:scope type="default"/>

Sharing resources with authorization keys

All Google Docs ACLs have a key set by Google Docs. The key is retrievable from a Documents List Entry. The key is used to grant access for users to certain documents, but this is different than sharing documents with users directly, as when using a key, users do not have to be added to an ACL directly.

The granting of reader or writer roles may be conditional based on the user having or not having a key. An example would be that all users in a domain with a certain key will have write permissions to a document. One key is assigned per ACL, even if there are multiple entries in the ACL. This key is generated by Google Docs, and cannot be modified. Keys are specified using elements, as documented below.

Sharing to all domain users who have the specified key, and giving those users write permission.

Protocol

<entry>
  <gAcl:withKey key='[ACL KEY]'><gAcl:role value='writer' /></gAcl:withKey>
  <gAcl:scope type='domain' value='example.com' />
</entry>

.NET

The following code shares the first document in the feed with all domain users who have the specified key, and gives those users write permission.

using System;
using Google.GData.AccessControl;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a DocumentsListQuery object to retrieve documents.
      DocumentsListQuery query = new DocumentsListQuery();

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      if (feed.Entries.Count == 0)
      {
        // TODO: There were no documents, act accordingly.
      }

      // TODO: Choose a resource based on your app's needs.
      DocumentEntry entry = (DocumentEntry)feed.Entries[0];

      // Instantiate a AclEntryWithKey object to share with keys.
      AclEntryWithKey acl = new AclEntryWithKey();

      // Set the ACL scope.
      acl.Scope = new AclScope("example.com", "domain");

      // Instantiate a AclWithKey object to specify a key.
      AclWithKey withKey = new AclWithKey("[ACL KEY]");

      // Set the ACL role.
      withKey.Role = new AclRole("writer");

      // Set the WithKey property of the AclEntryWithKey element.
      acl.WithKey = withKey;

      // Insert the new role into the ACL feed.
      service.Insert(new Uri(entry.AccessControlList), acl);
    }
  }
}

Sharing to all Google Docs users who have the specified key, and giving those users read permission:

Protocol

<entry>
  <gAcl:withKey key='[ACL KEY]'><gAcl:role value='reader' /></gAcl:withKey>
  <gAcl:scope type='default' />
</entry>

.NET

The following code shares the first document in the feed with all Google Docs users who have the specified key, and gives those users read permission.

using System;
using Google.GData.AccessControl;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate a DocumentsListQuery object to retrieve documents.
      DocumentsListQuery query = new DocumentsListQuery();

      // Make a request to the API and get all documents.
      DocumentsFeed feed = service.Query(query);

      if (feed.Entries.Count == 0)
      {
        // TODO: There were no documents, act accordingly.
      }

      // TODO: Choose a resource based on your app's needs.
      DocumentEntry entry = (DocumentEntry)feed.Entries[0];

      // Instantiate a AclEntryWithKey object to share with keys.
      AclEntryWithKey acl = new AclEntryWithKey();

      // Set the ACL scope.
      acl.Scope = new AclScope("", "default");

      // Instantiate a AclWithKey object to specify a key.
      AclWithKey withKey = new AclWithKey("[ACL KEY]");

      // Set the ACL role.
      withKey.Role = new AclRole("reader");

      // Set the WithKey property of the AclEntryWithKey element.
      acl.WithKey = withKey;

      // Insert the new role into the ACL feed.
      service.Insert(new Uri(entry.AccessControlList), acl);
    }
  }
}

Batching ACL requests

Batch processing gives the ability to execute multiple operations in one request, rather than sending a single request per operation.

The server performs as many of the requested changes as possible, and returns status information about the success or failure of each operation. Further information about batch processing is given in Batch Processing with Google Data APIs.

When generating an ACL feed for a batch request, every entry except those being created must have an . This element is provided in each entry when fetching a feed of ACL entries, and is used to identify an entry. For entries being created that do not yet have an , define a string value in a element. This value is returned in the response to the batch request, allowing clients to identify newly created entries.

The following example demonstrates how to query, insert, update and delete ACL entries of a resource.

POST https://docs.google.com/feeds/default/private/full/document:1234abcd/acl/batch
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"
    xmlns:gAcl="http://schemas.google.com/acl/2007"
    xmlns:batch="http://schemas.google.com/gdata/batch">
  <category scheme="http://schemas.google.com/g/2005#kind"
      term="http://schemas.google.com/acl/2007#accessRule"/>
  <entry>
    <id>https://docs.google.com/feeds/default/private/full/document:1234abcd/acl/user:owner@example.com</id>
    <batch:operation type="query"/>
  </entry>
  <entry>
    <batch:id>1</batch:id>
    <batch:operation type="insert"/>
    <gAcl:role value="writer"/>
    <gAcl:scope type="user" value="new_writer@example.com"/>
  </entry>
  <entry>
    <id>https://docs.google.com/feeds/default/private/full/document:1234abcd/acl/user:old_writer@example.com</id>
    <batch:operation type="update"/>
    <gAcl:role value="reader"/>
    <gAcl:scope type="user" value="old_writer@example.com"/>
  </entry>
  <entry>
    <id>https://docs.google.com/feeds/default/private/full/document:1234abcd/acl/user:deprecated_writer@example.com</id>
    <batch:operation type="delete"/>
    <gAcl:role value="writer"/>
    <gAcl:scope type="user" value="deprecated_writer@example.com"/>
  </entry>
</feed>

The returned feed will contain one result entry for each operation.

<?xml version='1.0' encoding='utf-8'?>
<feed xmlns:atom='http://www.w3.org/2005/Atom'
    xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/'
    xmlns:gAcl='http://schemas.google.com/acl/2007'
    xmlns:batch='http://schemas.google.com/gdata/batch'>
  <id>https://docs.google.com/feeds/default/private/full/document:1234abcd/acl</id>
  <updated>2009-03-06T09:13:23.382Z</updated>
  <title type='text'>Batch Feed</title>
  <link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml'
      href='https://docs.google.com/feeds/default/private/full/document:1234abcd/acl'/>
  <link rel='http://schemas.google.com/g/2005#post' type='application/atom+xml'
      href='https://docs.google.com/feeds/default/private/full/document:1234abcd/acl'/>
  <link rel='http://schemas.google.com/g/2005#batch' type='application/atom+xml'
      href='https://docs.google.com/feeds/default/private/full/document:1234abcd/acl/batch'/>
  <entry>
    <id>https://docs.google.com/feeds/default/private/full/document:1234abcd/acl/user:owner@example.com</id>
    <updated>2009-03-06T09:13:23.381Z</updated>
    <category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/acl/2007#accessRule'/>
    <title type='text'>Document Permission - owner@example.com</title>
    <link rel='self' type='application/atom+xml'
        href='https://docs.google.com/feeds/default/private/full/document:1234abcd/acl/user:owner@example.com'/>
    <link rel='edit' type='application/atom+xml'
        href='https://docs.google.com/feeds/default/private/full/document:1234abcd/acl/user:owner@example.com'/>
    <gAcl:role value='owner'/>
    <gAcl:scope type='user' value='owner@example.com'/>
    <batch:status code='200' reason='Success'/>
    <batch:operation type='query'/>
  </entry>
  <entry>
    <id>https://docs.google.com/feeds/default/private/full/document:1234abcd/acl/user:new_writer@example.com</id>
    <updated>2009-03-06T09:13:25.381Z</updated>
    <category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/acl/2007#accessRule'/>
    <title type='text'>Document Permission - new_writer@example.com</title>
    <link rel='self' type='application/atom+xml'
        href='https://docs.google.com/feeds/default/private/full/document:1234abcd/acl/user:new_writer@example.com'/>
    <link rel='edit' type='application/atom+xml'
        href='https://docs.google.com/feeds/default/private/full/document:1234abcd/acl/user:new_writer@example.com'/>
    <gAcl:role value='writer'/>
    <gAcl:scope type='user' value='new_writer@example.com'/>
    <batch:id>1</batch:id>
    <batch:status code='201' reason='Created'/>
    <batch:operation type='insert'/>
  </entry>
  <entry>
    <id>https://docs.google.com/feeds/default/private/full/document:1234abcd/acl/user:old_writer@example.com</id>
    <updated>2009-03-06T09:13:27.737Z</updated>
    <category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/acl/2007#accessRule'/>
    <title type='text'>Document Permission - old_writer@example.com</title>
    <link rel='self' type='application/atom+xml'
        href='https://docs.google.com/feeds/default/private/full/document:1234abcd/acl/user:old_writer@example.com'/>
    <link rel='edit' type='application/atom+xml'
        href='https://docs.google.com/feeds/default/private/full/document:1234abcd/acl/user:old_writer@example.com'/>
    <gAcl:role value='reader'/>
    <gAcl:scope type='user' value='old_writer@example.com'/>
    <batch:status code='200' reason='Success'/>
    <batch:operation type='update'/>
  </entry>
  <entry>
    <id>https://docs.google.com/feeds/default/private/full/document:1234abcd/acl/user:deprecated_writer@example.com</id>
    <updated>2009-03-06T09:13:29.743Z</updated>
    <title type='text'>Deleted</title>
    <content type='text'>Deleted</content>
    <batch:status code='200' reason='Success'/>
    <batch:operation type='delete'/>
  </entry>
</feed>

Managing archives of documents and files

The archive feed can be used to export resources as a .zip file. Your client determines the desired export format for each type of resource and downloads the archive once the process has finished.

Creating archives of documents and files

To initiate an archive request, send an authenticated POST request to the archive feed's URI:

https://docs.google.com/feeds/default/private/archive

The body of the request contains data which controls the archive operation and, optionally, a list of resource IDs to archive. If no resource IDs are contained in the request body, query parameters from the URL (if any) is used to select the items to include in the archive. If the request body contains one or more resource IDs, query parameters from the URL are ignored.

The following example archives three documents, a PDF, and a collection's contents, selects their export format, and emails 'user@gmail.com' when the archive operation has finished.

Protocol

POST https://docs.google.com/feeds/default/private/archive
Authorization: <your authorization header here>
Content-Length: 457
Content-Type: application/atom+xml

<entry xmlns="http://www.w3.org/2005/Atom" xmlns:docs="http://schemas.google.com/docs/2007">
  <docs:archiveResourceId>document:0A1234567890</docs:archiveResourceId>
  <docs:archiveResourceId>spreadsheet:0A1234567890</docs:archiveResourceId>
  <docs:archiveResourceId>presentation:0A1234567890</docs:archiveResourceId>
  <docs:archiveResourceId>pdf:0A12sdf</docs:archiveResourceId>
  <docs:archiveResourceId>folder:0A1234567890</docs:archiveResourceId>
  <docs:archiveConversion source='application/vnd.google-apps.document' target='application/msword'/>
  <docs:archiveConversion source='application/vnd.google-apps.spreadsheet' target='text/csv'/>
  <docs:archiveConversion source='application/pdf' target='application/pdf'/>
  <docs:archiveNotify>user@gmail.com</docs:archiveNotify>
</entry>

The response contains information about the archive.

<?xml version='1.0' encoding='utf-8'?>
<entry xmlns='http://www.w3.org/2005/Atom'
xmlns:docs='http://schemas.google.com/docs/2007'
xmlns:gd='http://schemas.google.com/g/2005'>
  <id>
  https://docs.google.com/feeds/archive/-228SJEnnmwemsiDLLxmGeGygWrvW1tMZHHg6ARCy3Uj3SMH1GHlJ2scb8BcHSDDDUosQAocwBQOAKHOq3-0gmKA</id>
  <published>2010-11-18T18:34:06.981Z</published>
  <updated>2010-11-18T18:34:07.763Z</updated>
  <app:edited xmlns:app='http://www.w3.org/2007/app'>
  2010-11-18T18:34:07.763Z</app:edited>
  <category scheme='http://schemas.google.com/g/2005#kind'
  term='http://schemas.google.com/docs/2007#archive'
  label='archive' />
  <title>Document Archive - someuser@somedomain.com</title>
  <link rel='self' type='application/atom+xml'
  href='https://docs.google.com/feeds/default/private/archive/-228SJEnnmwemsiDLLxmGeGygWrvW1tMZHHg6ARCy3Uj3SMH1GHlJ2scb8BcHSDDDUosQAocwBQOAKHOq3-0gmKA' />
  <link rel='edit' type='application/atom+xml'
  href='https://docs.google.com/feeds/default/private/archive/-228SJEnnmwemsiDLLxmGeGygWrvW1tMZHHg6ARCy3Uj3SMH1GHlJ2scb8BcHSDDDUosQAocwBQOAKHOq3-0gmKA' />
  <author>
    <name>someuser</name>
    <email>someuser@somedomain.com</email>
  </author>
  <docs:archiveNotify>someuser@somedomain.com</docs:archiveNotify>
  <docs:archiveStatus>flattening</docs:archiveStatus>
  <docs:archiveResourceId>
  0Adj-hQNOVsTFSNDEkdk2221OTJfMWpxOGI5OWZu</docs:archiveResourceId>
  <docs:archiveResourceId>
  0Adj-hQNOVsTFZGZodGs2O72NFMllMQDN3a2Rq</docs:archiveResourceId>
  <docs:archiveConversion source='application/vnd.google-apps.document'
  target='text/plain' />
</entry>

.NET

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate an ArchiveEntry object to initiate an archive request.
      ArchiveEntry entry = new ArchiveEntry();

      // Add the IDs of the resources to be included in the archive.
      entry.ArchiveResourceIds.Add(new ArchiveResourceId("document:0A1234567890"));
      entry.ArchiveResourceIds.Add(new ArchiveResourceId("spreadsheet:0A1234567890"));
      entry.ArchiveResourceIds.Add(new ArchiveResourceId("presentation:0A1234567890"));
      entry.ArchiveResourceIds.Add(new ArchiveResourceId("pdf:0A12sdf"));
      entry.ArchiveResourceIds.Add(new ArchiveResourceId("folder:0A1234567890"));

      // Specify the conversion formats for each entry.
      entry.ArchiveConversions.Add(new ArchiveConversion("application/vnd.google-apps.document", "application/msword"));
      entry.ArchiveConversions.Add(new ArchiveConversion("application/vnd.google-apps.spreadsheet", "text/csv"));
      entry.ArchiveConversions.Add(new ArchiveConversion("application/pdf", "application/pdf"));

      // Set the email address of the user to be notified.
      entry.ArchiveNotify = "user@gmail.com";

      // Send the archive request to the API.
      service.Insert(DocumentsListQuery.archiveUri, entry);
    }
  }
}

The response entry from the POST request will reflect the user provided elements as well as standard elements added by the server.

The following is an example of how to use query parameters to archive all resources matching the query. Note that although no resource IDs are specified in the request, they will come back in the response, so that you know exactly which items are in the archive.

POST https://docs.google.com/feeds/default/private/archive?q=title:test
Authorization: <your authorization header here>
Content-Length: 457
Content-Type: application/atom+xml

<entry xmlns="http://www.w3.org/2005/Atom" xmlns:docs="http://schemas.google.com/docs/2007">
  <docs:archiveConversion source='application/vnd.google-apps.document' target='application/msword'/>
  <docs:archiveConversion source='application/vnd.google-apps.spreadsheet' target='text/csv'/>
  <docs:archiveConversion source='application/pdf' target='application/pdf'/>
  <docs:archiveNotify>user@gmail.com</docs:archiveNotify>
</entry>

The response is:

<?xml version='1.0' encoding='utf-8'?>
<entry xmlns='http://www.w3.org/2005/Atom'
xmlns:docs='http://schemas.google.com/docs/2007'
xmlns:gd='http://schemas.google.com/g/2005'>
  <id>
  https://docs.google.com/feeds/archive/-228SJEnnmwemsiDLLxmGeGygWrvW1tMZHHg6ARCy3Uj3SMH1GHlJ2scb8BcHSDDDUosQAocwBQOAKHOq3-0gmKA</id>
  <published>2010-11-18T18:34:06.981Z</published>
  <updated>2010-11-18T18:34:07.763Z</updated>
  <app:edited xmlns:app='http://www.w3.org/2007/app'>
  2010-11-18T18:34:07.763Z</app:edited>
  <category scheme='http://schemas.google.com/g/2005#kind'
  term='http://schemas.google.com/docs/2007#archive'
  label='archive' />
  <title>Document Archive - someuser@somedomain.com</title>
  <link rel='self' type='application/atom+xml'
  href='https://docs.google.com/feeds/default/private/archive/-228SJEnnmwemsiDLLxmGeGygWrvW1tMZHHg6ARCy3Uj3SMH1GHlJ2scb8BcHSDDDUosQAocwBQOAKHOq3-0gmKA' />
  <link rel='edit' type='application/atom+xml'
  href='https://docs.google.com/feeds/default/private/archive/-228SJEnnmwemsiDLLxmGeGygWrvW1tMZHHg6ARCy3Uj3SMH1GHlJ2scb8BcHSDDDUosQAocwBQOAKHOq3-0gmKA' />
  <author>
    <name>someuser</name>
    <email>someuser@somedomain.com</email>
  </author>
  <docs:archiveNotify>someuser@somedomain.com</docs:archiveNotify>
  <docs:archiveStatus>flattening</docs:archiveStatus>
  <docs:archiveResourceId>
  0Adj-hQNOVsTFSNDEkdk2221OTJfMWpxOGI5OWZu</docs:archiveResourceId>
  <docs:archiveResourceId>
  0Adj-hQNOVsTFZGZodGs2O72NFMllMQDN3a2Rq</docs:archiveResourceId>
  <docs:archiveConversion source='application/vnd.google-apps.document'
  target='text/plain' />
</entry>

Explanation of archive feed elements

ElementExampleDescription
id https://docs.google.com/feeds/archive/228jZrUfn0... The unique URL used to identify this archive and to retrieve this archive entry again. The bold portion of the above example is the archive-id used throughout this documentation.
docs:archiveResourceId document:0A1234567890 The resource ID of an item in the user's doclist, repeated for each document to archive. The server will accept both typed and untyped resource IDs, but will return only untyped resource IDs in the response feed. Tip: Collection resource IDs (e.g. folder:id) will cause the contents of the collection to be included in the archive.
docs:archiveConversion source="text/plain" target="application/pdf" A map of desired export formats. If a MIME type is not recognized, it will not be used in generating the archive. If an element does not give a target format for a `docs:archiveConversion` element, the element will not be used in generating the archive. Default target MIME types are used if you don't specify a target MIME type for an item that is added to the archive. This parameter is repeated for each for each unique MIME type of an item to be included in the archive. Use source="*" for a default archiveConversion specification.
docs:archiveNotifyuser@gmail.comOptional. An email address to notify when an archive operation is complete and the archive is ready for download.

MIME types for native Google document formats

Google Doc
application/vnd.google-apps.document
Google Spreadsheet
application/vnd.google-apps.spreadsheet
Google Form
application/vnd.google-apps.form
Google Presentation
application/vnd.google-apps.presentation
Google Drawing
application/vnd.google-apps.drawing

Getting the status of an archive

A GET request returns the status of an archive. The resulting entry contains elements which provide information (including completion status) about the archive operation.

The entry returned contains these elements:

ElementExampleDescription
docs:archiveResourceId document:0A1234567890 The resource ID of an item, repeated for each resource to archive. The server accepts both typed and untyped resource IDs, but only returns untyped resource IDs in the response feed. Tip: Collection resource IDs (e.g. folder:id) cause the contents of the collection to be included in the archive.
published 2009-11-05T05:59:58.615Z Time the archive was started
content type="application/zip" src="http://docs.google.com/download/xyz" URL where the archive can be downloaded
docs:archiveStatus queued, flattening, archiving, finished, aborted, expired Status of the archive
docs:archiveComplete 2009-11-05T05:59:58.615Z Time the archive is estimated to complete or was completed
gd:quotaBytesUsed 50000000 Size of the completed archive in bytes
docs:archiveTotal 10 Number of resources in the archive
docs:archiveTotalComplete 5 Number of resources processed so far
docs:archiveTotalFailure 1 Number of resources processed which failed to be archived
docs:archiveFailure document:12345 ID of failed resource. Repeated for each failure.
docs:archiveNotifyStatus none, sent, failed Status of the email notification
docs:archiveConversion source="text/plain" target="application/pdf" See the previous section about docs:archiveConversion under Creating archives of documents and files.
docs:archiveNotifyuser@gmail.comOptional. An email address to notify when an archive operation is complete.

Protocol

When the archive operation is not complete:

GET https://docs.google.com/feeds/default/private/archive/<archive-id>
Authorization: <your authorization header here>

The response is:

200 OK

<?xml version='1.0' encoding='utf-8'?>
<entry xmlns='http://www.w3.org/2005/Atom'
xmlns:docs='http://schemas.google.com/docs/2007'
xmlns:gd='http://schemas.google.com/g/2005'>
  <id>
  https://docs.google.com/feeds/archive/-228SJEnnmwemsiDLLxmGeGygWrvW1tMZHHg6ARCy3Uj3SMH1GHlJ2scb8BcHSDDDUosQAocwBQOAKHOq3-0gmKA</id>
  <published>2010-11-18T18:34:06.981Z</published>
  <updated>2010-11-18T19:13:31.266Z</updated>
  <app:edited xmlns:app='http://www.w3.org/2007/app'>
  2010-11-18T19:13:31.266Z</app:edited>
  <category scheme='http://schemas.google.com/g/2005#kind'
  term='http://schemas.google.com/docs/2007#archive'
  label='archive' />
  <title>Document Archive - someuser@somedomain.com</title>
  <link rel='self' type='application/atom+xml'
  href='https://docs.google.com/feeds/default/private/archive/-228SJEnnmwemsiDLLxmGeGygWrvW1tMZHHg6ARCy3Uj3SMH1GHlJ2scb8BcHSDDDUosQAocwBQOAKHOq3-0gmKA' />
  <link rel='edit' type='application/atom+xml'
  href='https://docs.google.com/feeds/default/private/archive/-228SJEnnmwemsiDLLxmGeGygWrvW1tMZHHg6ARCy3Uj3SMH1GHlJ2scb8BcHSDDDUosQAocwBQOAKHOq3-0gmKA' />
  <author>
    <name>someuser</name>
    <email>someuser@somedomain.com</email>
  </author>
  <docs:archiveNotify>someuser@somedomain.com</docs:archiveNotify>
  <docs:archiveStatus>archiving</docs:archiveStatus>
  <docs:archiveResourceId>0Adj-hQNOVsTFSNDEkdk2221OTJfMWpxOGI5OWZu</docs:archiveResourceId>
  <docs:archiveResourceId>0Adj-hQNOVsTFZGZodGs2O72NFMllMQDN3a2Rq</docs:archiveResourceId>
  <docs:archiveConversion source='application/vnd.google-apps.document' target='text/plain' />
</entry>

When the archive operation is complete:

GET https://docs.google.com/feeds/default/private/archive/<archive-id>
Authorization: <your authorization header here>
The response will be:
<?xml version='1.0' encoding='utf-8'?>
<entry xmlns='http://www.w3.org/2005/Atom'
xmlns:docs='http://schemas.google.com/docs/2007'
xmlns:gd='http://schemas.google.com/g/2005'>
  <id>
  https://docs.google.com/feeds/archive/-228SJEnnmwemsiDLLxmGeGygWrvW1tMZHHg6ARCy3Uj3SMH1GHlJ2scb8BcHSDDDUosQAocwBQOAKHOq3-0gmKA</id>
  <published>2010-11-18T18:34:06.981Z</published>
  <updated>2010-11-18T19:13:31.266Z</updated>
  <app:edited xmlns:app='http://www.w3.org/2007/app'>
  2010-11-18T19:13:31.266Z</app:edited>
  <category scheme='http://schemas.google.com/g/2005#kind'
  term='http://schemas.google.com/docs/2007#archive'
  label='archive' />
  <title>Document Archive - someuser@somedomain.com</title>
  <content type='application/zip'      src='https://doc-00-90-docs.googleusercontent.com/docs/secure/he0nmogeutv9f47fuhdm5052r4methcr/82t504tsh5roodr6f8qr4lpdlng1hkjk/1290103200000/15266010465028272046/15266010465028272046/-228SJEnnmwemsiDLLxmGeGygWrvW1tMZHHg6ARCy3Uj3SMH1GHlJ2scb8BcHSDDDUosQAocwBQOAKHOq3-0gmKA?a=docs-archive-2010-11-18.zip&ai=-228SJEnnmwemsiDLLxmGeGygWrvW1tMZHHg6ARCy3Uj3SMH1GHlJ2scb8BcHSDDDUosQAocwBQOAKHOq3-0gmKA&ap=grOCTZLfQ5X0EArImf6Qfdg4ZlilxR6JNmObNJCbc6Q&h=18423295174435396830&gd=true' />
  <link rel='self' type='application/atom+xml'
  href='https://docs.google.com/feeds/default/private/archive/-228SJEnnmwemsiDLLxmGeGygWrvW1tMZHHg6ARCy3Uj3SMH1GHlJ2scb8BcHSDDDUosQAocwBQOAKHOq3-0gmKA' />
  <link rel='edit' type='application/atom+xml'
  href='https://docs.google.com/feeds/default/private/archive/-228SJEnnmwemsiDLLxmGeGygWrvW1tMZHHg6ARCy3Uj3SMH1GHlJ2scb8BcHSDDDUosQAocwBQOAKHOq3-0gmKA' />
  <author>
    <name>someuser</name>
    <email>someuser@somedomain.com</email>
  </author>
  <docs:archiveNotify>someuser@somedomain.com</docs:archiveNotify>
  <docs:archiveStatus>finished</docs:archiveStatus>
  <gd:quotaBytesUsed>308</gd:quotaBytesUsed>
  <docs:archiveNotifyStatus>sent</docs:archiveNotifyStatus>
  <docs:archiveComplete>2010-11-18T18:34:09.679Z</docs:archiveComplete>
  <docs:archiveTotal>2</docs:archiveTotal>
  <docs:archiveTotalComplete>2</docs:archiveTotalComplete>
  <docs:archiveTotalFailure>0</docs:archiveTotalFailure>
  <docs:archiveResourceId>0Adj-hQNOVsTFSNDEkdk2221OTJfMWpxOGI5OWZu</docs:archiveResourceId>
  <docs:archiveResourceId>0Adj-hQNOVsTFZGZodGs2O72NFMllMQDN3a2Rq</docs:archiveResourceId>
  <docs:archiveConversion source='application/vnd.google-apps.document' target='text/plain' />
</entry>

.NET

The following code sends an archive request, then fetches its status and prints the value of the archiveStatus property.

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate an ArchiveEntry object to initiate an archive request.
      ArchiveEntry entry = new ArchiveEntry();

      // Add the IDs of the resources to be included in the archive.
      entry.ArchiveResourceIds.Add(new ArchiveResourceId("document:0A1234567890"));
      entry.ArchiveResourceIds.Add(new ArchiveResourceId("spreadsheet:0A1234567890"));
      entry.ArchiveResourceIds.Add(new ArchiveResourceId("presentation:0A1234567890"));
      entry.ArchiveResourceIds.Add(new ArchiveResourceId("pdf:0A12sdf"));
      entry.ArchiveResourceIds.Add(new ArchiveResourceId("folder:0A1234567890"));

      // Specify the conversion formats for each entry.
      entry.ArchiveConversions.Add(new ArchiveConversion("application/vnd.google-apps.document", "application/msword"));
      entry.ArchiveConversions.Add(new ArchiveConversion("application/vnd.google-apps.spreadsheet", "text/csv"));
      entry.ArchiveConversions.Add(new ArchiveConversion("application/pdf", "application/pdf"));

      // Set the email address of the user to be notified.
      entry.ArchiveNotify = "user@gmail.com";

      // Send the archive request to the API.
      entry = service.Insert(DocumentsListQuery.archiveUri, entry);

      // Instantiate an ArchiveQuery object to retrieve archives.
      ArchiveQuery query = new ArchiveQuery(archiveId);

      // Make a request to the API and get the archive feed.
      ArchiveFeed feed = service.Query(query);

      if (feed.Entries.Count == 0)
      {
        throw new Exception("The archive feed should always contain an entry");
      }

      // The archive feed contains a single entry.
      entry = (ArchiveEntry)feed.Entries[0];

      // Print the status of the archive operation.
      Console.WriteLine(entry.ArchiveStatus);
    }
  }
}

Generated archives, although they are ZIP files, will not show up in a user's documents list.

Generated archives are periodically purged, and should be fetched as soon as possible after they are created. If you request an archive that has been purged, a 410 Gone response is given, and the archive must be created again.

Updating the notification email address of an archive

A PUT request changes the archive notification email address. All elements returned in a GET may be sent to the server, however only the notification email address is examined and changed. A PUT request on an archive in one of the completed states (finished, aborted, expired) results in a 410 Gone response.

Example of changing an archive's notification email:

Protocol

PUT https://docs.google.com/feeds/default/private/archive/ Authorization:

<entry xmlns="http://www.w3.org/2005/Atom" xmlns:docs="http://schemas.google.com/docs/2007"
       xmlns:gd="http://schemas.google.com/g/2005">
  ...
  <docs:archiveNotify>different_user@example.com</docs:archiveNotify>
</entry>

.NET

The following code sends an archive request, then updates its notification email address.

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate an ArchiveEntry object to initiate an archive request.
      ArchiveEntry entry = new ArchiveEntry();

      // Add the IDs of the resources to be included in the archive.
      entry.ArchiveResourceIds.Add(new ArchiveResourceId("document:0A1234567890"));
      entry.ArchiveResourceIds.Add(new ArchiveResourceId("spreadsheet:0A1234567890"));
      entry.ArchiveResourceIds.Add(new ArchiveResourceId("presentation:0A1234567890"));
      entry.ArchiveResourceIds.Add(new ArchiveResourceId("pdf:0A12sdf"));
      entry.ArchiveResourceIds.Add(new ArchiveResourceId("folder:0A1234567890"));

      // Specify the conversion formats for each entry.
      entry.ArchiveConversions.Add(new ArchiveConversion("application/vnd.google-apps.document", "application/msword"));
      entry.ArchiveConversions.Add(new ArchiveConversion("application/vnd.google-apps.spreadsheet", "text/csv"));
      entry.ArchiveConversions.Add(new ArchiveConversion("application/pdf", "application/pdf"));

      // Set the email address of the user to be notified.
      entry.ArchiveNotify = "user@gmail.com";

      // Send the archive request to the API.
      entry = service.Insert(DocumentsListQuery.archiveUri, entry);

      // Set the new notification email address.
      entry.ArchiveNotify = "different_user@example.com";

      // Make a request to the API and update the archive.
      entry.Update();
  }
}

Aborting an archive in the process of being generated

A DELETE request aborts an archive operation. A DELETE request on an archive in one of the completed states (finished, aborted, expired) results in a 410 Gone response.

Example of aborting an in-progress archive request:

Protocol

DELETE https://docs.google.com/feeds/default/private/archive/

.NET

The following code sends an archive request, then aborts the operation.

using System;
using Google.GData.Client;
using Google.GData.Documents;

namespace MyDocumentsListIntegration
{
  class Program
  {
    static void Main(string[] args)
    {
      DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");

      // TODO: Authorize the service object for a specific user (see Authorizing requests)

      // Instantiate an ArchiveEntry object to initiate an archive request.
      ArchiveEntry entry = new ArchiveEntry();

      // Add the IDs of the resources to be included in the archive.
      entry.ArchiveResourceIds.Add(new ArchiveResourceId("document:0A1234567890"));
      entry.ArchiveResourceIds.Add(new ArchiveResourceId("spreadsheet:0A1234567890"));
      entry.ArchiveResourceIds.Add(new ArchiveResourceId("presentation:0A1234567890"));
      entry.ArchiveResourceIds.Add(new ArchiveResourceId("pdf:0A12sdf"));
      entry.ArchiveResourceIds.Add(new ArchiveResourceId("folder:0A1234567890"));

      // Specify the conversion formats for each entry.
      entry.ArchiveConversions.Add(new ArchiveConversion("application/vnd.google-apps.document", "application/msword"));
      entry.ArchiveConversions.Add(new ArchiveConversion("application/vnd.google-apps.spreadsheet", "text/csv"));
      entry.ArchiveConversions.Add(new ArchiveConversion("application/pdf", "application/pdf"));

      // Set the email address of the user to be notified.
      entry.ArchiveNotify = "user@gmail.com";

      // Send the archive request to the API.
      entry = service.Insert(DocumentsListQuery.archiveUri, entry);

      // Make a request to the API and abort the operation.
      entry.Delete();
  }
}

Authentication required

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

Signing you in...

Google Developers needs your permission to do that.