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

# OneDrive Indexing API

> Index a user's OneDrive for Business (a single file, a folder recursively, or the whole drive) with no OAuth pop-up. Captain reads via a Microsoft Entra ID app your IT admin authorizes once.

## Agent Quick Reference: OneDrive headless indexing

* Auth = Microsoft Graph **app-only client credentials** (an Entra ID App Registration). No per-user OAuth, no API keys, no user accounts. Captain mints app-only tokens from the tenant_id + client_id + client_secret you pass on each request.
* One-time setup, done by a Microsoft 365 admin in **Microsoft Entra ID** (entra.microsoft.com): create an **App Registration**, add a **client secret**, grant these **application** permissions (not delegated) and click **Grant admin consent** in the portal: `Files.Read.All` (read the files) and `User.Read.All` (resolve `user_email` to the user's drive — required). (`Sites.Selected` does not cover user OneDrives.)
* Request fields (all endpoints): `tenant_id`, `client_id`, `client_secret`, `user_email` (the OneDrive owner's user principal name), `processing_type` ("advanced" | "basic" | "auto").
* Endpoints:
  * `POST /v2/collections/{name}/index/onedrive`: the user's whole OneDrive
  * `POST /v2/collections/{name}/index/onedrive/directory`: one folder (recursive), field `folder_id`
  * `POST /v2/collections/{name}/index/onedrive/file`: one file, field `item_id`
* Files are already native formats (docx/xlsx/pdf), so there is no export step. OneNote notebooks are skipped.
* For SharePoint sites, see the separate SharePoint Indexing API guide (`/index/sharepoint`, permission `Sites.Selected` or `Sites.Read.All`).
* Common error `AADSTS7000215` = invalid client secret. `AADSTS500011` / consent errors = admin consent not granted. A 403 resolving the drive = `Files.Read.All` or `User.Read.All` (Application) is missing, or consent wasn't granted.

Captain indexes OneDrive for Business through Microsoft's Graph API. There
is no per-user OAuth flow and no user passwords involved: your Microsoft 365
admin registers an app once, and Captain uses that app's credentials to read
a single file, a folder (recursively), or a user's whole drive. You name the
user on each request.

To index SharePoint sites instead, see the
[SharePoint Indexing API](/guides/sharepoint-indexing) guide.
The endpoints and permissions are separate by design: OneDrive access
requires the broader
`Files.Read.All` permission, so a tenant that only wants to expose one
SharePoint site never has to grant it.

## What your IT admin provides

Three values, all from a one-time App Registration in Microsoft Entra ID:

| Value           | What it is                                                                                               |
| --------------- | -------------------------------------------------------------------------------------------------------- |
| `tenant_id`     | Your Microsoft 365 directory (tenant) ID: a GUID, or the domain like `yourco.onmicrosoft.com`.           |
| `client_id`     | The Application (client) ID of the App Registration created for Captain.                                 |
| `client_secret` | A secret generated for that app. Captain uses it per job to mint short-lived tokens; it is never stored. |

Plus the **email (user principal name) of the OneDrive user** to index, e.g.
`analyst@yourco.com`.

## One-time setup

> **Info**
>
> Every step below is done by someone with admin rights in your Microsoft 365
> tenant. It takes about 10 minutes and is done once. After that, indexing is
> a plain API call. If you already created an App Registration for SharePoint
> indexing, reuse it and just add the permission in Step 2.

### Step 1: Create an App Registration and client secret

1. Sign in at [entra.microsoft.com](https://entra.microsoft.com) (or the
   Azure portal) and go to **Identity → Applications → App registrations**.
2. Click **New registration**. Name the app (for example
   `captain-indexing`), leave every default as is, and click **Register**.
3. On the app's **Overview** page, copy two values: the **Application
   (client) ID** and the **Directory (tenant) ID**.
4. Go to **Certificates & secrets** and click **New client secret**. Pick an
   expiry and click **Add**.
5. Copy the secret's **Value** right away; it is shown only once. This is
   the `client_secret` you'll send to Captain. Keep it secret.

### Step 2: Grant application permissions and admin consent

1. On the app's **API permissions** page, click **Add a permission** and
   choose **Microsoft Graph**.
2. Choose **Application permissions**, not Delegated. Application permissions
   are what let Captain run headlessly, with no signed-in user — the delegated
   versions are not sufficient.
3. Add both of these application permissions:
   * `Files.Read.All` — read the user's OneDrive files. (The site-scoped
     `Sites.Selected` permission does not cover user OneDrives.)
   * `User.Read.All` — lets the app resolve the `user_email` you send into that
     user's OneDrive. Without it, resolving the drive fails with a `403`.
4. Click **Grant admin consent for \<your org>** on the same page, then
   confirm. Each permission's **Status** should show a green "Granted" check.
   This is all done from the Azure portal — no command line or Graph call is
   needed.

## Indexing

All three endpoints take the same auth fields plus the user's email, and
differ only in scope.

### A user's whole OneDrive

```bash
curl -X POST "https://api.filesearch.dev/v2/collections/{collection_name}/index/onedrive" \
  -H "Authorization: Bearer $CAPTAIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "tenant_id": "00000000-1111-2222-3333-444444444444",
    "client_id": "<application (client) id>",
    "client_secret": "<client secret value>",
    "user_email": "analyst@yourco.com",
    "processing_type": "advanced"
  }'
```

### A folder (recursively)

```bash
curl -X POST "https://api.filesearch.dev/v2/collections/{collection_name}/index/onedrive/directory" \
  -H "Authorization: Bearer $CAPTAIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "tenant_id": "00000000-1111-2222-3333-444444444444",
    "client_id": "<application (client) id>",
    "client_secret": "<client secret value>",
    "user_email": "analyst@yourco.com",
    "folder_id": "01ABCDEF...",
    "processing_type": "advanced"
  }'
```

`folder_id` is the folder's Graph driveItem ID. Subfolders are indexed too.

### A single file

```bash
curl -X POST "https://api.filesearch.dev/v2/collections/{collection_name}/index/onedrive/file" \
  -H "Authorization: Bearer $CAPTAIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "tenant_id": "00000000-1111-2222-3333-444444444444",
    "client_id": "<application (client) id>",
    "client_secret": "<client secret value>",
    "user_email": "analyst@yourco.com",
    "item_id": "01GHIJKL...",
    "processing_type": "advanced"
  }'
```

`item_id` is the file's Graph driveItem ID.

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`.

## What gets indexed

* **Documents** (PDF, DOCX, XLSX, CSV, TXT, images, etc.): OneDrive
  stores files in their native formats, so everything downloads and processes
  directly. No export step.
* **Skipped:** OneNote notebooks and any file the app can't access (logged
  and skipped; the job continues).

## Troubleshooting

| Symptom                                                    | Cause & fix                                                                                                                                                                                                                           |
| ---------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `AADSTS7000215: Invalid client secret`                     | The secret is wrong or expired. Generate a new one under **Certificates & secrets** (copy the **Value**, not the Secret ID).                                                                                                          |
| Consent errors (`AADSTS500011`, "insufficient privileges") | Admin consent wasn't granted. On the app's **API permissions** page, click **Grant admin consent**.                                                                                                                                   |
| `403` resolving the user's drive                           | The app is missing `Files.Read.All` or `User.Read.All` (Application), or admin consent wasn't granted. Add both application permissions and click **Grant admin consent**. (Site-scoped `Sites.Selected` is not enough for OneDrive.) |
| A folder job finishes with some files failed               | Those items are restricted beyond the app's grant. Captain skips them and indexes the rest.                                                                                                                                           |

## Security notes

* Grants are **read-only**. Captain never writes to or deletes from OneDrive.
* `Files.Read.All` covers files tenant-wide, so treat the app's credentials
  accordingly. If you only need SharePoint content, use the SharePoint guide
  with `Sites.Selected` instead and skip this permission entirely.
* The **client secret is a credential**: treat it like a password. Revoke it
  any time under **Certificates & secrets**, or kill all access by deleting
  the App Registration.
* Captain uses the secret only to mint short-lived tokens per job; nothing
  durable is stored beyond the request.
* Every read appears in your Microsoft 365 audit logs, attributed to the app.