# OneDrive Delta Sync: Tracking Changes with Microsoft Graph Delta Query

OneDrive delta sync uses Microsoft Graph delta queries to track additions, modifications, and deletions in OneDrive or SharePoint libraries without re-scanning unchanged folders. By following nextLink pagination and persisting the deltaLink cursor, applications detect file updates in a single incremental request. Handling HTTP 410 Gone token expiration and SharePoint permission gaps enables reliable storage synchronization for AI agents.

Source: https://fast.io/resources/onedrive-delta-sync/
Author: [Derek Labian](https://fast.io/authors/derek-labian/)
Last reviewed: 2026-10-15

## How OneDrive Delta Sync Works with Microsoft Graph

Traversing an entire cloud storage hierarchy to detect modified files is an operational bottleneck that rapidly triggers API throttling and exhausts request quotas. In a OneDrive or SharePoint document library holding 50,000 files, recursive folder enumeration requires dozens of sequential API calls even before inspecting file timestamps or downloading modified contents. For autonomous AI agents that require current file context to execute tasks, running full folder crawls introduces minute-long latency spikes and leaves background workers vulnerable to rate limiting.

OneDrive delta sync uses Microsoft Graph delta queries to track additions, modifications, and deletions in OneDrive or SharePoint libraries without re-scanning unchanged folders. Instead of walking directory trees on every synchronization cycle, your application reads an incremental change feed maintained by Microsoft Graph.

### The Mechanics of Microsoft Graph Delta Queries

The Microsoft Graph API exposes change tracking directly on the `driveItem` resource through the `delta` function. Rather than inspecting individual folder contents, you query the root of a drive or a specific subfolder hierarchy:

* **Personal or Business OneDrive**: `GET https://graph.microsoft.com/v1.0/me/drive/root/delta`
* **Specific Drive or SharePoint Library**: `GET https://graph.microsoft.com/v1.0/drives/{drive-id}/root/delta`
* **Targeted Subfolder Hierarchy**: `GET https://graph.microsoft.com/v1.0/drives/{drive-id}/items/{folder-id}/delta`

When an application issues an initial call to the `delta` endpoint without parameters, Microsoft Graph starts enumerating the entire target hierarchy. The service returns a page of `driveItem` objects alongside a pagination URL labeled `@odata.nextLink`. The application follows these `@odata.nextLink` URLs sequentially until all current items have been delivered.

On the final page of the enumeration sequence, Microsoft Graph returns an `@odata.deltaLink` URL instead of a `@odata.nextLink`. This `@odata.deltaLink` URL contains an opaque state token that encapsulates the exact point-in-time synchronization marker for the drive.

When your background worker runs its next synchronization check, it sends a GET request directly to that saved `@odata.deltaLink` URL. Microsoft Graph inspects the embedded token and returns only the drive items that were added, edited, moved, or deleted since that marker was minted. Once the incremental batch finishes, the response provides a fresh `@odata.deltaLink` to store for future checks.

### Directory Crawling vs. Delta Query Synchronization

Evaluating traditional folder tree crawling against token-based delta synchronization highlights why delta queries are necessary for production applications:

| Synchronization Dimension | Full Directory Crawl (`children`) | Delta Query Sync (`delta`) |
|---|---|---|
| Request Target | Present snapshot of each folder | Incremental log of recent mutations |
| Request Volume (50k items) | 50 to 500+ requests per pass | 1 request during low-activity intervals |
| Discovery of Deletions | Requires diffing current inventory against cache | Explicit deletion records with `deleted` facet |
| Discovery of File Renames | Detected by tracking path changes across scans | Immediate update with unchanged `id` |
| Discovery of Folder Moves | Requires reconciliation of parent relationships | Direct update showing new `parentReference` |
| Rate Limit Sensitivity | High risk of HTTP 429 throttling | Low consumption of tenant query quota |
| Processing Overhead | High memory consumption for tree traversal | Processing bounded to modified resources |

By replacing recursive directory walks with delta queries, sync services reduce operational latency and prevent quota exhaustion across large enterprise document libraries.

## Step-by-Step Delta Sync Implementation in Python

Building a production-ready OneDrive delta sync worker in Python requires four steps: establishing the initial baseline query, traversing pagination pages, processing item changes and deletions, and persisting the updated delta cursor.

### 1. Initializing the Delta Query

Before an application can track incremental changes, it must choose how to establish its baseline. Microsoft Graph supports two bootstrapping modes:

* **Full Initial Enumeration**: Calling `GET /drives/{drive-id}/root/delta` without query parameters returns every file and folder in the drive across a series of paginated responses. Use this mode when your application must build a complete local mirror or populate a vector index from scratch.
* **Current Snapshot Baseline**: Appending `?token=latest` to the delta endpoint tells Microsoft Graph to skip historical items and return an immediate `@odata.deltaLink` representing the present moment. Use this mode when your application only cares about changes that occur after the connection is established.

```python
import requests

def get_initial_delta_url(drive_id, access_token, track_from_now=False):
    base_url = f"https://graph.microsoft.com/v1.0/drives/{drive_id}/root/delta"
    if track_from_now:
        base_url += "?token=latest"
    headers = {
        "Authorization": f"Bearer {access_token}",
        "Prefer": "deltashowremovedasdeleted, deltatraversepermissiongaps"
    }
    return base_url, headers
```

### 2. Following Pagination via `@odata.nextLink`

Because document libraries can contain thousands of items, Microsoft Graph partitions results into pages. If a response contains an `@odata.nextLink` property, additional changes remain in the current batch. Your worker must continue requesting each `@odata.nextLink` until the response omits `@odata.nextLink` and returns `@odata.deltaLink`.

### 3. Detecting Additions, Modifications, and Deletions

Each object in the returned `value` list represents a file or folder state. An application must inspect specific facets to determine how to process the record:

* **Additions and Modifications**: If the item contains a `file` or `folder` property without a deletion marker, it represents a newly created or modified resource. The object supplies current metadata, including `id`, `name`, `size`, `lastModifiedDateTime`, and `parentReference`.
* **Deletions and Access Revocations**: If the item contains a `deleted` facet (such as `{"deleted": {"state": "deleted"}}`) or an `@removed` facet, the file was permanently deleted, moved to the recycle bin, or removed from the caller's permission scope.
* **Item Identity Rule**: On OneDrive for Business and SharePoint, deletion records omit the `name` property. They provide only the item `id` and the `deleted` facet. Applications must index files by their unique Microsoft Graph `id` rather than their folder path or file name.

### 4. Persisting the `@odata.deltaLink` Cursor

The `@odata.deltaLink` returned on the final page of a delta sequence contains the cursor for subsequent runs. Store this complete URL string in your database alongside your tenant and drive identifiers. During the next sync interval, query this exact URL to fetch subsequent changes.

```python
import requests

class OneDriveDeltaSync:
    def __init__(self, drive_id, access_token, state_store):
        self.drive_id = drive_id
        self.access_token = access_token
        self.state_store = state_store
        self.headers = {
            "Authorization": f"Bearer {self.access_token}",
            "Prefer": "deltashowremovedasdeleted, deltatraversepermissiongaps"
        }
        ### Synchronize pending drive changes
    def execute_sync(self):
        current_url = self.state_store.get_delta_url(self.drive_id)
        if not current_url:
            current_url = f"https://graph.microsoft.com/v1.0/drives/{self.drive_id}/root/delta"
        while current_url:
            response = requests.get(current_url, headers=self.headers, timeout=30)
            if response.status_code == 410:
                self.handle_resync_required()
                return
            response.raise_for_status()
            payload = response.json()
            items = payload.get("value", [])
            for item in items:
                self.process_item(item)
            if "@odata.nextLink" in payload:
                current_url = payload["@odata.nextLink"]
            elif "@odata.deltaLink" in payload:
                new_delta_link = payload["@odata.deltaLink"]
                self.state_store.save_delta_url(self.drive_id, new_delta_link)
                current_url = None
            else:
                current_url = None
        ### Process individual drive item
    def process_item(self, item):
        item_id = item.get("id")
        is_deleted = "deleted" in item or "@removed" in item
        if is_deleted:
            self.state_store.remove_file(item_id)
        else:
            self.state_store.upsert_file(item_id, item)
        ### Handle resync on token expiration
    def handle_resync_required(self):
        self.state_store.clear_delta_url(self.drive_id)
        self.state_store.reset_index(self.drive_id)
        self.execute_sync()
```

This loop processes intermediate pages to completion before committing the new delta cursor, preventing partial state updates if a network interruption occurs mid-sync.

## Handling Token Expiration, HTTP 410 Gone, and SharePoint Permission Gaps

Production implementations must handle two failure modes that competitor tutorials consistently omit: delta token invalidation triggering HTTP 410 Gone errors, and transient permission adjustments in SharePoint document libraries.

### Handling Expired Delta Tokens and HTTP 410 Gone

Microsoft Graph delta tokens do not last indefinitely. If an application stops polling for an extended period, if massive directory reorganizations occur, or if Microsoft performs internal partition rebalancing, the stored delta token becomes invalid.

When a client presents an obsolete or expired token, Microsoft Graph responds with an `HTTP 410 Gone` status code. The JSON error payload specifies an error code explaining the invalidation:

* `resyncChangesApplyDifferences`: The service cannot replay changes from the requested checkpoint. The client must re-enumerate the drive and update its local records to match the server state, applying server-side deletions and edits.
* `resyncChangesUploadDifferences`: The server state has drifted significantly. The client must re-enumerate and upload local modifications that the server does not hold.
* `resyncRequired`: A generic desynchronization error indicating that the incremental change log relative to your cursor has been pruned.

When encountering an HTTP 410 response, incremental tracking cannot continue. Your application must execute an automated recovery sequence:

1. Discard the expired delta token from persistent storage.
2. Check for a `Location` header in the 410 response. If present, it provides a fresh starting URL. If absent, initiate a request to `/drives/{drive-id}/root/delta` without query parameters.
3. Page through the full enumeration to rebuild your local cache, database, or agent vector index.
4. Persist the new `@odata.deltaLink` returned on the final page of the full sync pass.

```python
def safe_delta_request(url, headers):
    response = requests.get(url, headers=headers, timeout=30)
    if response.status_code == 410:
        error_data = response.json().get("error", {})
        error_code = error_data.get("code", "resyncRequired")
        fresh_start_url = response.headers.get("Location")
        return {
            "status": "resync_required",
            "code": error_code,
            "restart_url": fresh_start_url
        }
    response.raise_for_status()
    return {"status": "ok", "payload": response.json()}
```

### Managing SharePoint Document Libraries and Permission Gaps

Synchronizing corporate SharePoint document libraries introduces structural complexities not present in personal OneDrive accounts. Organizations frequently break permission inheritance on specific folders or restrict member access to sensitive project subdirectories.

These permission patterns cause two distinct synchronization issues:

* **Permission Gaps**: When a user or service principal has access to a nested subfolder but lacks read permission on an intermediate parent folder, standard delta queries skip the inaccessible parent and silently omit the accessible child items.
* **Silent Removals**: When an administrator revokes a user's permission to a file or folder, the file is not deleted from the SharePoint server. However, from the user's perspective, the file has vanished. Without explicit configuration, standard delta queries omit access-revoked files entirely, leaving stale files in your local database.

To resolve these edge cases, always include the following request header on all delta calls:

```http
Prefer: deltashowremovedasdeleted, deltatraversepermissiongaps, deltashowsharingchanges
```

* `deltatraversepermissiongaps`: Instructs Microsoft Graph to traverse past inaccessible parent folders and continue enumerating accessible subfolders and files down the hierarchy.
* `deltashowremovedasdeleted`: Causes Microsoft Graph to emit items with the `deleted` facet whenever an item moves out of scope due to revoked permissions. This guarantees that your local index purges files that the user or agent is no longer authorized to inspect.
* `deltashowsharingchanges`: Marks items whose permissions have changed with an `@microsoft.graph.sharedChanged: "True"` annotation, allowing downstream security mappers to refresh access control lists.

### Managing Graph API Throttling and Request Limits

Microsoft Graph enforces strict concurrency and request rate limits. When background delta sync loops make rapid sequential calls across multiple document libraries, the API can return `HTTP 429 Too Many Requests` or `HTTP 503 Service Unavailable`.

Every production sync service must implement throttling safeguards:

* **Honor the `Retry-After` Header**: When Microsoft Graph returns an HTTP 429 response, inspect the `Retry-After` response header. This header specifies the exact number of seconds the worker must pause before retrying.
* **Exponential Backoff with Full Jitter**: For transient 503 or 504 errors where no `Retry-After` header is supplied, implement exponential backoff with randomized jitter. Jitter prevents multiple background workers from retrying simultaneously and re-triggering quota blocks.
* **Centralize Polling Workers**: Never allow independent client sessions or distributed AI agents to query the Microsoft Graph delta endpoint directly. Run a dedicated synchronization service that pulls changes once and writes to a shared workspace, shielding downstream consumers from Graph API limits.

## Delta Query Polling vs. Microsoft Graph Webhook Subscriptions

Developers designing cloud storage synchronization architectures must decide whether to query the delta endpoint on a scheduled interval or listen for real-time push notifications using Microsoft Graph webhooks.

### The Silent Notification Pattern in Graph Subscriptions

On many developer platforms, webhooks deliver rich event payloads containing modified entity data, record identifiers, and change diffs. Microsoft Graph driveItem webhooks operate differently.

When you create a webhook subscription (`POST https://graph.microsoft.com/v1.0/subscriptions`) targeting a drive or folder, Microsoft Graph delivers an event notification whenever a mutation occurs. However, the webhook notification body contains zero file data. The payload includes only the subscription identifier, the tenant ID, the client state validation string, and the resource path that changed.

Because the webhook payload omits file names, item identifiers, and modification types, an application cannot update its internal records from the webhook ping alone. The webhook serves strictly as an operational alarm indicating that an update occurred. To discover which files were created, edited, or removed, your webhook receiver must still execute a delta query using its saved `@odata.deltaLink`.

Consequently, adopting webhooks does not eliminate delta query code. Webhooks simply change the trigger mechanism from a scheduled timer to an event notification.

### Operational Overhead of Webhook Subscriptions

While webhooks offer lower notification latency for interactive user applications, they introduce substantial infrastructure complexity:

| Operational Factor | Scheduled Delta Polling (`delta`) | Graph Webhook Subscriptions (`/subscriptions`) |
|---|---|---|
| Ingress Requirements | Outbound HTTPS only (runs inside private networks) | Publicly accessible HTTPS endpoint with valid SSL |
| Inbound Handshake | None required | Validation handshake responding to validation tokens |
| Notification Content | Batch of updated `driveItem` objects | Silent ping (zero file data, resource path only) |
| Downstream Processing | Executes delta query directly on schedule | Receives ping, then executes delta query |
| Subscription Maintenance | Persistent delta token stored in database | Automated renewal cron required every 48 to 70 hours |
| Resilience to Downtime | Resumes cleanly from stored cursor on next run | Missed notifications require scheduled reconciliation |
| Infrastructure Footprint | Minimal background worker or cron script | Dedicated API gateway, SSL listener, and queue worker |

### Subscription Lifespan Limits

Microsoft Graph imposes strict maximum lifespans on webhook subscriptions. Subscriptions for drive root resources expire after a maximum duration of 4,230 minutes (under three days).

If an application fails to send a `PATCH /v1.0/subscriptions/{id}` request before the expiration window closes, Microsoft Graph permanently drops the subscription. The service provides no grace period or automated recovery. Applications relying on webhooks must maintain a secondary cron service solely to renew subscriptions and must run periodic fallback delta polls to catch events missed during listener outages.

For background data pipelines, scheduled RAG ingestion, and AI agent workspaces, scheduled delta polling provides greater operational reliability with less infrastructure surface area.

## Connecting OneDrive and SharePoint to Agent Workspaces Without Custom Sync Daemons

Engineering a custom OneDrive and SharePoint delta sync daemon requires substantial operational commitment. Development teams must write database schemas to track delta cursors across diverse document libraries, build recovery loops for HTTP 410 Gone errors, configure permission gap traversal headers, manage rate limit queues, and maintain document parsing pipelines to feed downstream vector databases. For teams focused on building intelligent agents, maintaining this synchronization plumbing diverts resources away from core agent reasoning.

When autonomous agents connect directly to raw storage APIs, they often pull whole folders or exhaust request limits. An alternative approach allows teams to keep their primary files in Google Drive, Dropbox, Box, or OneDrive, while connecting those folders into a collaborative workspace built for human-agent teams.

### Automated Workspace Synchronization and Native Intelligence

Using [Fast.io cloud import](/product/cloud-import/), documents from OneDrive import directly into an organization workspace without local input-output bottlenecks. Cloud Sync connects Google Drive, Dropbox, Box and OneDrive folders to a workspace, one-way or two-way, on a schedule or on demand, with SharePoint document libraries accessible through the OneDrive connector. Because synchronization runs on a defined schedule or on demand, teams avoid the fragility of managing continuous real-time webhook listeners. Fastio Cloud Sync handles OneDrive and SharePoint delta syncing on a schedule, shielding agents from Graph API rate limits.

Once files arrive in a [Fast.io workspace](/product/workspaces/), Intelligence Mode indexes document contents automatically for keyword and semantic retrieval. AI agents can query files, search by meaning, and extract relevant passages with citations without requiring engineers to deploy standalone vector databases or custom embedding scripts.

### Accessing Workspace Storage Through MCP

Instead of writing custom Microsoft Graph API wrappers, agents access workspace content through the remote MCP server over Streamable HTTP. Interactive clients sign in with OAuth in the browser, while headless code connects to `https://mcp.fast.io/mcp/tools` (Claude and general agents), `https://mcp.fast.io/mcp/code` (coding agents), or `https://mcp.fast.io/mcp/operations` (ChatGPT and Codex), sending a scoped key as an `Authorization: Bearer <api key>` header (see the [MCP setup documentation](https://mcp.fast.io/docs)).

The agent uses a consolidated MCP toolset (`storage`, `storage_manage`, `search`) to query indexed files and inspect document structure. When an agent updates a document, the workspace preserves full per-file version history, while organizational changes are recorded in a detailed activity log.

When evaluating connector efficiency, the [connector comparison](https://fast.io/benchmarks/) details performance across major cloud storage providers.

For teams processing structured documents such as purchase orders, vendor contracts, or technical specifications, [Metadata Views](/product/document-data-extraction/) extract typed attributes from files into queryable tables using natural language schemas. Agents can query metadata columns directly through MCP actions, providing structured data alongside raw text.

Teams can configure these workflows in [storage for agents](/storage-for-agents/) environments. Monthly plans start with a 14-day free trial that requires a credit card.

## Frequently asked questions

### How do I use Microsoft Graph delta query with OneDrive?

To use Microsoft Graph delta query with OneDrive, send an initial GET request to /me/drive/root/delta or /drives/{drive-id}/root/delta without query parameters. The API returns a page of changed driveItem resources and an @odata.nextLink URL if more pages exist. Follow @odata.nextLink URLs across subsequent pages until the final response returns an @odata.deltaLink URL. Store this @odata.deltaLink in your database and call it during the next synchronization interval to fetch subsequent file additions, edits, and deletions.

### How do you detect deleted files in OneDrive delta sync?

Microsoft Graph represents deleted files and folders by including the deleted facet (such as deleted: { state: deleted }) or the @removed facet in the returned driveItem object. When parsing delta results, applications must check for the presence of this facet and delete the corresponding item from local storage or vector indexes. On OneDrive for Business and SharePoint, delete records omit the file name property, so applications must identify items by their unique id rather than file path.

### What should an application do when an OneDrive delta token expires?

When an OneDrive delta token expires or becomes invalid, Microsoft Graph returns an HTTP 410 Gone status code with an error code such as resyncRequired, resyncChangesApplyDifferences, or resyncChangesUploadDifferences. Because the change gap cannot be bridged incrementally, the application must discard the invalid delta token, query the delta endpoint without a token to start a full re-enumeration, reconcile its local database or vector index against the fresh inventory, and save the newly returned @odata.deltaLink for future polls.

### Why does Microsoft Graph omit file names when reporting deletions?

When a file is deleted in OneDrive for Business or SharePoint, Microsoft Graph strips non-essential metadata from the change record, omitting properties like ctag and name. The record contains only the item id, the parent reference, and the deleted facet. Sync clients must index records by item id rather than file path so that deletions can be processed without requiring the original file name.

### What is the difference between delta polling and Microsoft Graph webhooks?

Microsoft Graph webhooks send real-time push notifications over HTTPS when a drive item changes, but the notification payload contains zero file data. The webhook merely alerts your receiver that a change occurred. The receiver must still execute a delta query using the saved @odata.deltaLink to retrieve modified files. Scheduled delta polling queries the delta endpoint directly on a fixed timer, eliminating the need for public HTTPS ingress and recurring webhook subscription renewals.

### Does Fast.io sync with OneDrive and SharePoint libraries?

Yes. Fast.io Cloud Sync connects Google Drive, Dropbox, Box and OneDrive folders to a workspace, one-way or two-way, on a schedule or on demand, with SharePoint document libraries accessible through the OneDrive connector. Synced files are automatically indexed for hybrid search, allowing AI agents to query content through the remote MCP server without managing custom delta sync tokens, 410 recovery loops, or webhook infrastructure.

## Sources

- [Microsoft Graph Documentation: driveItem: delta](https://learn.microsoft.com/en-us/graph/api/driveitem-delta?view=graph-rest-1.0): Microsoft Graph delta queries track changes in a drive item and its children over time, returning an @odata.deltaLink on the final page to retrieve future changes.

## About Fast.io

Fast.io provides shared workspaces where people and AI agents work on the same files, with built-in semantic search and citation-backed chat over what they hold. Agents reach it through a remote MCP server, a REST API at https://api.fast.io/current/, and a command line client published on npm as @vividengine/fastio-cli. MCP setup is at https://mcp.fast.io/docs: Claude and most MCP clients connect to https://mcp.fast.io/mcp/tools, ChatGPT to https://mcp.fast.io/mcp/operations, and coding agents to https://mcp.fast.io/mcp/code.
