SharePoint Indexing API

Captain indexes SharePoint document libraries 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 whole document library.

The app reads only through Microsoft Graph with the permissions your admin grants, and every access is read-only and audit-logged. To scope access to specific sites rather than the whole tenant, an admin can use the Sites.Selected application permission plus a per-site grant instead of Sites.Read.All; that advanced option is outside this standard setup.

To index individual users’ OneDrive for Business drives instead, see the OneDrive Indexing API guide. The endpoints and permissions are separate by design.

What your IT admin provides

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

ValueWhat it is
tenant_idYour Microsoft 365 directory (tenant) ID: a GUID, or the domain like yourco.onmicrosoft.com.
client_idThe Application (client) ID of the App Registration created for Captain.
client_secretA secret generated for that app. Captain uses it per job to mint short-lived tokens; it is never stored.

Plus the URL of the SharePoint site to index, e.g. https://yourco.sharepoint.com/sites/Sales.

One-time setup

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.

Step 1: Create an App Registration and client secret

  1. Sign in at 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.
  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 of these permissions are not sufficient.

  3. Add both of these application permissions:

    • Sites.Read.All — read access to SharePoint site content.
    • User.Read.All — lets the app resolve users and site/drive identities (required; without it, resolving a site or its drive fails).

    If the same app registration will also index OneDrive, add Files.Read.All as well (see the OneDrive guide).

  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 site URL, and differ only in scope.

A site’s whole document library

$curl -X POST "https://api.runcaptain.com/v2/collections/{collection_name}/index/sharepoint" \
> -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>",
> "site_url": "https://yourco.sharepoint.com/sites/Sales",
> "processing_type": "advanced"
> }'

This indexes the site’s default document library (“Documents”). If the site has additional libraries, pass the optional drive_id of the library to index instead.

A folder (recursively)

$curl -X POST "https://api.runcaptain.com/v2/collections/{collection_name}/index/sharepoint/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>",
> "site_url": "https://yourco.sharepoint.com/sites/Sales",
> "folder_id": "01ABCDEF...",
> "processing_type": "advanced"
> }'

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

A single file

$curl -X POST "https://api.runcaptain.com/v2/collections/{collection_name}/index/sharepoint/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>",
> "site_url": "https://yourco.sharepoint.com/sites/Sales",
> "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/collections/{name}/jobs/{job_id} for progress, then query the collection with POST /v2/collections/{name}/query.

What gets indexed

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

Troubleshooting

SymptomCause & fix
AADSTS7000215: Invalid client secretThe 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 siteThe app is missing Sites.Read.All or User.Read.All (Application), or admin consent wasn’t granted. Add both application permissions and click Grant admin consent. (If you scoped with Sites.Selected instead, the per-site grant may be missing.)
A folder job finishes with some files failedThose 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 SharePoint. The permissions above (Sites.Read.All, User.Read.All) are all read scopes.
  • To narrow access to specific sites, an admin can swap Sites.Read.All for the Sites.Selected application permission and grant the app only the sites to be indexed; everything else in the tenant then stays invisible.
  • 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.
© 2026 Captain