> For a complete page index of the Captain API documentation, fetch https://docs.captain.dev/llms.txt?excludeSpec=true

# Google Drive Indexing API

> Index a Google Workspace user's Drive (a single file, a folder recursively, or their entire Drive) with no OAuth pop-up. Captain reads Drive as the user via a service account your Workspace admin authorizes once.

## Agent Quick Reference: Google Drive headless indexing

* Auth = Google **service-account domain-wide delegation**. No per-user OAuth. Captain impersonates a Workspace user (`subject_email`) using a service-account key you provide.
* Two one-time setup artifacts, both created by a Google **Workspace super admin**:
  1. A **service account** with a **JSON key**, created in Google Cloud (console.cloud.google.com → IAM & Admin → Service Accounts). Any Google account can create a **free** Cloud project for this; no billing is required.
  2. A **domain-wide delegation** grant in the **Admin console** (admin.google.com → Security → Access and data control → API controls → Manage Domain-Wide Delegation → Add new) authorizing that service account's **numeric Client ID** for scope `https://www.googleapis.com/auth/drive.readonly`.
* The Google **Drive API** must be enabled on the Cloud project (console.cloud.google.com → APIs & Services → Enable APIs → "Google Drive API").
* There is **no Admin-Console-only path** to create a service account; the account itself must be created in Google Cloud. Delegation is granted in the Admin console.
* Request fields: `service_account_json` (the full key JSON as a string), `subject_email` (the Workspace user to read as), `processing_type` ("advanced" | "basic" | "auto").
* Endpoints:
  * `POST /v2/collections/{name}/index/gdrive`: the subject's **entire Drive** (global)
  * `POST /v2/collections/{name}/index/gdrive/directory`: one **folder** (recursive), field `folder_id`
  * `POST /v2/collections/{name}/index/gdrive/file`: one **file**, field `file_id`
* Native Google Docs/Sheets/Slides are exported automatically (Docs/Slides → PDF, Sheets → XLSX). Forms/Sites are skipped. Shared Drives are included.
* Common error `unauthorized_client` = the delegation grant is missing, still propagating (allow a few minutes, up to \~30), the scope doesn't match exactly, or the Client **email** was entered instead of the numeric **Client ID**.
* Per-file `403` during a folder/global index = that file isn't shared with `subject_email`; Captain logs and skips it, the rest of the job continues.

Captain indexes Google Drive without a per-user OAuth flow. Your Google
Workspace admin authorizes a single service account once, and Captain reads
Drive as a specific user you name on each request: a single file, a folder
(recursively), or that user's entire Drive.

Use this when you want to index Drive content at scale, on a schedule, or on
behalf of many users, with no login step in the loop.

## How it works

1. You create a **service account** in Google Cloud and download its **JSON
   key**.
2. Your **Workspace super admin** authorizes that service account for
   read-only Drive access, domain-wide (a one-time grant in the Admin
   console).
3. On each indexing request you send the service-account key plus a
   `subject_email`, the Workspace user whose Drive Captain should read.
   Captain mints a short-lived token *as that user* and reads only what that
   user can see.

Nothing durable is stored on Captain's side beyond the request; the token is
minted per job and discarded.

## One-time setup

> **Info**
>
> Every step below is done by someone with **Google Workspace super
> administrator** rights on your domain. It takes about 15 minutes and is done
> once. After that, indexing is a plain API call.

### Step 1: Create a service account and key

You need a Google Cloud project to hold the service account. **If your
organization doesn't use Google Cloud, that's fine.** Any Google account can
create a project for free, and this use case requires **no billing**.

1. Go to [console.cloud.google.com](https://console.cloud.google.com).
2. Create a project (or pick an existing one): open the project picker in the
   top bar, click **New Project**, name it (for example
   `captain-drive-indexing`), and click **Create**.
3. Enable the Drive API: go to **APIs & Services → Enable APIs and
   services**, search for **"Google Drive API"**, and click **Enable**.
4. Create the service account: go to **IAM & Admin → Service Accounts**,
   click **Create service account**, give it a name (for example
   `captain-indexing`), and click **Create and continue**. Skip the optional
   roles and click **Done**. No project roles are needed; this account's
   access comes entirely from the Workspace delegation grant in Step 2.
5. Create a key: open the service account, go to the **Keys** tab, and click
   **Add key → Create new key → JSON → Create**. A `.json` file downloads.
   **This is the `service_account_json` you'll send to Captain. Keep it
   secret.**
6. Note the service account's **numeric Client ID** (also called the "Unique
   ID" or "OAuth2 Client ID"). You'll need it in Step 2. Find it on the
   service account's **Details** tab, or in the "OAuth 2 Client ID" column
   under **IAM & Admin → Service Accounts**.

> **Warning**
>
> Google does **not** offer a way to create a service account entirely inside
> the Admin console. The account itself must be created in Google Cloud, as
> above. Only the **delegation grant** (Step 2) lives in the Admin console.

### Step 2: Authorize the service account (domain-wide delegation)

This is the grant that lets Captain read Drive as your users. It's done in
the **Admin console** (`admin.google.com`), which is a different console from
the Cloud one in Step 1.

1. Go to [admin.google.com](https://admin.google.com), then **Security →
   Access and data control → API controls**.
2. In the **Domain-wide delegation** panel, click **Manage Domain-Wide
   Delegation**.
3. Click **Add new** and enter:
   * **Client ID**: the **numeric Client ID** from Step 1 (not the service
     account's email address).
   * **OAuth scopes**: exactly
     ```
     https://www.googleapis.com/auth/drive.readonly
     ```
4. Click **Authorize**.

> **Note**
>
> Grant only `drive.readonly`. Captain never writes to or deletes from Drive.
> Scoping to read-only keeps the grant safe and speeds any internal security
> review.

The grant can take a few minutes to propagate (occasionally up to \~30). If
your first indexing call returns `unauthorized_client`, wait and retry.

### Choosing which user to index (`subject_email`)

Captain reads Drive **as** the `subject_email` you pass, so pick the user
whose content you want:

* **A specific person's Drive**: their email (e.g. `analyst@yourco.com`).
* **A Shared Drive / team content**: any user who is a **member** of that
  Shared Drive. Files that user can't see are simply skipped.
* **An org-wide "service" identity**: many teams create a dedicated
  Workspace user (e.g. `indexing@yourco.com`), share the relevant Drives and
  folders with it, and always impersonate that one account. This keeps the
  indexed scope explicit and easy to audit.

## Indexing

All three endpoints take the same auth fields (the service-account key and
the user to impersonate) and differ only in scope.

### A single file

```bash
curl -X POST "https://api.filesearch.dev/v2/collections/{collection_name}/index/gdrive/file" \
  -H "Authorization: Bearer $CAPTAIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "service_account_json": "<full contents of the JSON key file, as a string>",
    "subject_email": "analyst@yourco.com",
    "file_id": "1AbC...",
    "processing_type": "advanced"
  }'
```

`file_id` is the `/d/<id>/` segment of a Drive file URL.

### A folder (recursively)

```bash
curl -X POST "https://api.filesearch.dev/v2/collections/{collection_name}/index/gdrive/directory" \
  -H "Authorization: Bearer $CAPTAIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "service_account_json": "<JSON key as a string>",
    "subject_email": "analyst@yourco.com",
    "folder_id": "1MHp...",
    "processing_type": "advanced"
  }'
```

`folder_id` is the trailing segment of a folder URL
(`drive.google.com/drive/folders/<folder_id>`). Subfolders are indexed too.

### An entire Drive

```bash
curl -X POST "https://api.filesearch.dev/v2/collections/{collection_name}/index/gdrive" \
  -H "Authorization: Bearer $CAPTAIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "service_account_json": "<JSON key as a string>",
    "subject_email": "analyst@yourco.com",
    "processing_type": "advanced"
  }'
```

Every response is `{ "job_id": "...", "status": "pending" }`. Poll
`GET /v2/jobs/{job_id}` for progress, then query the
collection with `POST /v2/collections/{name}/query`.

> **Info**
>
> **Passing the key JSON.** `service_account_json` is the entire contents of
> the `.json` key file, as a single JSON string. In most languages,
> read the file and JSON-encode its text before putting it in the request body.

## What gets indexed

* **Regular files** (PDF, DOCX, XLSX, CSV, TXT, images, etc.): downloaded and
  processed normally.
* **Native Google Docs, Sheets, and Slides**: exported automatically before
  indexing. **Docs and Slides → PDF**, **Sheets → XLSX**. You don't do
  anything; the exported file is what gets indexed.
* **Shared Drives**: included, as long as `subject_email` is a member.
* **Skipped:** Google Forms and Sites (no exportable document body), and any
  file the `subject_email` user can't access (logged and skipped; the job
  continues).

## Troubleshooting

| Symptom                                                     | Cause & fix                                                                                                                                                                                                                                                     |
| ----------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `unauthorized_client`                                       | The delegation grant (Step 2) is missing, still propagating, or the scope doesn't match. Confirm you entered the **numeric Client ID** (not the email) and the exact scope `https://www.googleapis.com/auth/drive.readonly`, then wait a few minutes and retry. |
| `Google Drive delegation failed for <email>`                | Same as above, surfaced per request. Also check the Drive API is **enabled** on the Cloud project.                                                                                                                                                              |
| A folder/global job finishes with some files failed (`403`) | Those files aren't shared with `subject_email`. Share them with that user, or impersonate a user who can see them. Captain skips them and indexes the rest.                                                                                                     |
| Job `completed`, but a Google Sheet indexed 0 chunks        | The sheet is empty (no tabular data). Nothing to index; expected.                                                                                                                                                                                               |

## Security notes

* The grant is **read-only** (`drive.readonly`). Captain can never modify or
  delete Drive content.
* Captain reads only what the impersonated `subject_email` can see. To limit
  scope, impersonate a dedicated user and share only the intended Drives with
  it.
* The service-account **JSON key is a credential**: treat it like a password.
  You can revoke it any time in Google Cloud (delete the key), or revoke all
  access by removing the delegation grant in the Admin console.
* Every read is attributable to the `subject_email` in your Google audit logs.