AI & Agents

How to Upload Files to OneDrive via API: Simple PUT vs Upload Sessions

Uploading files to OneDrive through the Microsoft Graph API requires selecting between simple PUT requests and multi-part upload sessions. Small files under four megabytes can transfer in a single call, while larger files demand chunked byte ranges aligned to 320 KiB increments with automated retry logic.

Tom Langridge 11 min read Updated
Choosing between simple PUT requests and multi-part upload sessions ensures reliable file ingestion without connection dropouts.

How Microsoft Graph Structures OneDrive File Uploads

A naive file upload script pointed at Microsoft Graph works reliably during local testing with small sample documents, then fails without explanation the moment an automated pipeline sends a large payload. The failure rarely stems from authentication; it happens because Microsoft Graph splits file uploads across two incompatible API pathways with strict byte-alignment constraints.

The OneDrive upload API is a set of Microsoft Graph endpoints that allows programs to send files to OneDrive using simple PUT requests for small files or multi-part upload sessions for larger files. Microsoft structures cloud storage around two foundational resources: drive, representing a logical container such as a personal drive or a SharePoint document library, and driveItem, representing an individual file or directory.

Addressing these resources follows two distinct conventions:

  • Unique identifier addressing: /drives/{driveId}/items/{itemId}/content targets an existing item directly.
  • Path-based addressing: /me/drive/root:/{path-to-file}:/content addresses an item by its human-readable directory hierarchy.

For enterprise environments running unattended automations or agent pipelines, your Microsoft Entra ID application registration requires specific permission scopes:

  • Delegated access: Files.ReadWrite provides least-privileged read and write access on behalf of the signed-in user. Files.ReadWrite.All broadens this access across all drives the user can reach.
  • Application access: Files.ReadWrite.All allows background services and automated daemons to read and write files across all tenant drives without interactive user sign-in.

Understanding the architectural distinction between simple PUT and upload sessions determines whether your integration handles production workloads or encounters frequent connection failures. Simple PUT transmits the entire binary payload inside a single HTTP request body. An upload session creates an ephemeral staging allocation on Microsoft ingestion servers, generating a preauthenticated upload URL that accepts sequential byte ranges.

When to Use Simple PUT Uploads for Small Payloads

For lightweight documents, JSON configuration payloads, and small text logs, simple PUT requests provide a straightforward ingestion route. The client issues a single HTTP PUT request directly to the drive item content endpoint.

The endpoint for path-based creation in the signed-in user's drive is:

PUT https://graph.microsoft.com/v1.0/me/drive/root:/Documents/report.pdf:/content
Authorization: Bearer {token}
Content-Type: application/pdf

<binary file content>

When the transfer succeeds, Microsoft Graph returns an HTTP 201 Created status code for new files or HTTP 200 OK when updating an existing item. The response payload returns the complete driveItem resource containing unique item IDs, file size, web URLs, and cryptographic hashes such as SHA1 and QuickXorHash.

Production Constraints and Failure Modes

Microsoft Graph simple PUT content endpoint accepts file uploads up to 250 MB in a single call. However, relying on a single HTTP call for payloads exceeding four megabytes introduces severe reliability problems:

  1. Socket Drops and Lack of Resumability: Single PUT transfers cannot resume if interrupted. If a network dropout occurs midway through a monolithic transfer, the entire progress is discarded, forcing the client to retransmit from the beginning.
  2. Proxy and Gateway Timeouts: Enterprise reverse proxies, API gateways, and web application firewalls frequently enforce body size limits or terminate idle connections with 504 Gateway Timeout or 413 Request Entity Too Large.
  3. Resource Locks: If an Office desktop application or concurrent process holds a write lease on the target file, Microsoft Graph returns HTTP 423 Locked.

Python Implementation for Simple PUT Upload

The following script demonstrates uploading small files using Python and the requests library:

import os
import requests

def upload_small_file(access_token: str, local_path: str, remote_path: str) -> dict:
    file_size = os.path.getsize(local_path)
    if file_size > 4 * 1024 * 1024:
        raise ValueError("Files 4 MB and larger should use createUploadSession instead.")
    url = f"https://graph.microsoft.com/v1.0/me/drive/root:/{remote_path}:/content"
    headers = {
        "Authorization": f"Bearer {access_token}",
        "Content-Type": "application/octet-stream"
    }
    with open(local_path, "rb") as f:
        response = requests.put(url, headers=headers, data=f)
    if response.status_code in (200, 201):
        return response.json()
    response.raise_for_status()

Steps to Execute Multi-Part Upload Sessions for Large Datasets

When transferring large files, multi-part upload sessions provide fault-tolerant chunking. Instead of sending one massive payload, the client creates a temporary upload session and streams the file in smaller byte fragments.

Step-by-Step Workflow Outline

Initiating and completing a OneDrive upload session follows a six-step lifecycle:

  1. Create the session: Send a POST request to createUploadSession at the target item path.
  2. Extract session metadata: Parse the returned uploadUrl and expirationDateTime.
  3. Partition the file: Slice the local file into byte chunks that conform to Graph alignment rules.
  4. Upload byte ranges: Issue sequential PUT calls to the uploadUrl with Content-Range headers.
  5. Process intermediate responses: Confirm HTTP 202 Accepted after each slice and verify nextExpectedRanges.
  6. Finalize the transfer: Transmit the final byte slice, receiving HTTP 201 Created or HTTP 200 OK with the finished driveItem.

Creating the Upload Session

To begin, the application sends a POST request specifying conflict behavior:

POST https://graph.microsoft.com/v1.0/me/drive/root:/Archives/backup.zip:/createUploadSession
Authorization: Bearer {token}
Content-Type: application/json

{
  "item": {
    "@microsoft.graph.conflictBehavior": "replace",
    "name": "backup.zip"
  }
}

The @microsoft.graph.conflictBehavior property accepts three options: fail (the default, which halts the request if a file with that name already exists), replace (which overwrites the existing item and updates its version history), or rename (which appends an incremented number to the file name).

Microsoft Graph responds with HTTP 200 OK containing the temporary session details:

{
  "uploadUrl": "https://sn3302.up.1drv.com/up/fe6987415ace7X4e1eF866337",
  "expirationDateTime": "2026-10-05T09:21:55.523Z"
}

Two critical rules govern this uploadUrl:

  • Preauthentication: The URL contains an embedded authorization signature. Do not send the standard Authorization: Bearer header during chunk PUT calls; passing token headers to the upload URL can cause HTTP 401 Unauthorized responses.
  • Expiration: Sessions remain valid for a finite window, typically 24 hours. Each successfully accepted fragment extends the expiration timestamp.
Fastio features

Connect OneDrive Storage to Agent Workspaces

Sync your existing OneDrive directories into a Fastio workspace on a schedule or on demand, giving your AI agents indexed semantic search over remote files without local chunking. Starts with a 30-day free trial.

Why the 320 KiB Alignment Rule Governs Byte Ranges

The single most common defect in custom OneDrive upload implementations is ignoring chunk alignment requirements. While general HTTP chunked uploads permit arbitrary partition sizes, Microsoft Graph enforces a strict mathematical rule on byte ranges.

The 320 KiB Requirement

Microsoft Graph upload sessions require fragment sizes to be multiples of 320 KiB. Specifically, 320 KiB corresponds to exactly 327,680 bytes. Every byte fragment uploaded to the session URL must contain a length that divides evenly by 327,680, with exactly one exception: the final fragment representing the end of the file.

Why does Microsoft enforce this constraint? Microsoft Graph routes upload streams directly into Azure storage backend blocks. These storage nodes process block allocations structured in 320 KiB increments. If a client transmits an unaligned middle slice (for example, a 500,000-byte chunk), the ingestion cluster accepts the intermediate chunk with a 202 Accepted status, but the final commit fails with 400 Bad Request or causes silent file corruption.

Valid Chunk Multiples

When designing your chunking logic, select a multiple of 320 KiB based on network throughput and stability:

  • 1 multiple: 320 KiB (327,680 bytes), useful for unstable links.
  • 10 multiples: 3,200 KiB (3,276,800 bytes, approximately 3.125 MiB).
  • 32 multiples: 10,240 KiB (10,485,760 bytes, exactly 10 MiB), which Microsoft recommends as the optimal balance between request overhead and retry cost for high-speed connections.
  • Maximum slice size: Individual PUT requests to the upload session must remain under 60 MiB (62,914,560 bytes).

Constructing Content-Range Headers

HTTP byte ranges use zero-based inclusive index bounds: bytes START-END/TOTAL. For example, consider a file with a total length of 1,000,000 bytes uploaded in 327,680-byte slices:

  • Slice 0: bytes 0 through 327,679 (Content-Length: 327680, Content-Range: bytes 0-327679/1000000).
  • Slice 1: bytes 327,680 through 655,359 (Content-Length: 327680, Content-Range: bytes 327680-655359/1000000).
  • Slice 2: bytes 655,360 through 983,039 (Content-Length: 327680, Content-Range: bytes 655360-983039/1000000).
  • Slice 3 (final remainder): bytes 983,040 through 999,999 (Content-Length: 16960, Content-Range: bytes 983040-999999/1000000).

Notice that the final slice is only 16,960 bytes. Because it terminates at the total file boundary (byte index 999,999 of 1,000,000 bytes), Microsoft Graph accepts the non-aligned remainder.

How to Handle Session Recovery, Network Drops, and Retries

Production file transfers must survive network drops, server throttling, and process interruptions. The strength of upload sessions lies in their resumability. When a transfer encounters an unexpected error, your client does not need to restart from scratch.

Querying Session Status

If a socket disconnects mid-upload, the client may be uncertain which bytes the server committed. To inspect session state, issue a GET request to the uploadUrl with no request body and no authorization header:

GET https://sn3302.up.1drv.com/up/fe6987415ace7X4e1eF866337

The server returns HTTP 200 OK with the current session state:

{
  "expirationDateTime": "2026-10-05T09:21:55.523Z",
  "nextExpectedRanges": ["655360-"]
}

The nextExpectedRanges array indicates the starting byte index expected by the server. In this example, the server has received all bytes up through 655,359, allowing the client to resume transmission directly at byte 655,360.

Handling HTTP Response Status Codes

An automated client must handle several specific status codes:

  • HTTP 202 Accepted: The byte fragment was saved successfully. The response body includes an updated expirationDateTime and the next expected byte range.
  • HTTP 201 Created or HTTP 200 OK: Returned when the final byte slice completes the file. The response contains the completed driveItem.
  • HTTP 416 Requested Range Not Satisfiable: The transmitted byte range was rejected, typically because the server already holds those bytes or received slices out of order. Query the session status to re-align your file pointer.
  • HTTP 404 Not Found: The upload session expired, was cleaned up, or was deleted. The client must start a brand-new upload session from byte zero.
  • HTTP 409 Conflict: If an item with the same name was created during the upload window, the final commit fails. Resolve this by issuing a PUT commit request with @microsoft.graph.conflictBehavior set to rename or specifying @microsoft.graph.sourceUrl.
  • HTTP 429 Too Many Requests and 5xx Server Errors: When Microsoft Graph encounters throttling or temporary server faults (500 Internal Server Error, 502 Bad Gateway, 503 Service Unavailable, 504 Gateway Timeout), apply exponential backoff. Inspect the Retry-After response header if present, or wait with jittered intervals before retrying the failed fragment.

Canceling an Incomplete Session

If a user aborts an upload, or an unrecoverable local error occurs, clean up server storage by sending a DELETE request to the uploadUrl:

DELETE https://sn3302.up.1drv.com/up/fe6987415ace7X4e1eF866337

Microsoft Graph returns HTTP 204 No Content and purges the temporary byte buffers immediately.

Resilient Chunked Upload Implementation

The following Python script implements 320 KiB chunk alignment, status inspection, and automated retries:

import os
import time
import requests

CHUNK_SIZE = 10 * 320 * 1024  # 3,276,800 bytes (10 multiples of 320 KiB)

def upload_large_file(upload_url: str, file_path: str, max_retries: int = 5) -> dict:
    total_size = os.path.getsize(file_path)
    with open(file_path, "rb") as f:
        start_byte = 0
        while start_byte < total_size:
            end_byte = min(start_byte + CHUNK_SIZE, total_size) - 1
            chunk_length = end_byte - start_byte + 1
            f.seek(start_byte)
            chunk_data = f.read(chunk_length)
            headers = {
                "Content-Length": str(chunk_length),
                "Content-Range": f"bytes {start_byte}-{end_byte}/{total_size}"
            }
            retries = 0
            while retries < max_retries:
                try:
                    response = requests.put(upload_url, headers=headers, data=chunk_data, timeout=60)
                    if response.status_code in (200, 201):
                        return response.json()
                    elif response.status_code == 202:
                        start_byte = end_byte + 1
                        break
                    elif response.status_code == 416:
                        status_res = requests.get(upload_url)
                        if status_res.status_code == 200:
                            next_range = status_res.json().get("nextExpectedRanges", ["0-"])[0]
                            start_byte = int(next_range.split("-")[0])
                            break
                        raise RuntimeError("Failed to resynchronize upload session state.")
                    elif response.status_code in (429, 500, 502, 503, 504):
                        retry_after = int(response.headers.get("Retry-After", 2 ** retries))
                        time.sleep(retry_after)
                        retries += 1
                    else:
                        response.raise_for_status()
                except (requests.RequestException, IOError) as exc:
                    retries += 1
                    if retries >= max_retries:
                        raise RuntimeError(f"Upload failed after {max_retries} attempts.") from exc
                    time.sleep(2 ** retries)
    raise RuntimeError("Upload completed loop without receiving completion response.")

How Intelligent Workspaces Connect OneDrive Storage to AI Agents

Autonomous AI agents, coding assistants, and operational pipelines such as Claude Code, Cursor, and Codex increasingly depend on enterprise knowledge stored in Microsoft OneDrive and SharePoint. However, connecting AI agents directly to raw Microsoft Graph upload and download endpoints creates substantial architecture overhead.

The Cost of Raw API Integrations in Agent Loops

When an agent interacts directly with Microsoft Graph, it must maintain refresh tokens, traverse complex directory trees, partition outgoing files into 320 KiB chunks, and repeatedly download multi-megabyte source files into prompt context. This consumes thousands of tokens, introduces latency into agent execution loops, and exposes workflows to Graph rate limiting.

The Fastio Workspace Architecture

The Fastio path eliminates this overhead while preserving your team's existing cloud storage:

  1. Retain existing storage: Your organization keeps its files in Microsoft OneDrive or SharePoint document libraries.
  2. Cloud sync into workspaces: Folders sync into a Fast.io workspace (one-way or two-way, on a schedule or on demand; never continuous, live, or real-time).
  3. Connect agents via remote MCP: The agent connects to the Fast.io Model Context Protocol server over Streamable HTTP at https://mcp.fast.io/mcp/code for coding agents (or https://mcp.fast.io/mcp/tools for general MCP clients), signing in with OAuth in the browser or sending an Authorization: Bearer <api key> header on the connection for headless pipelines, with setup instructions at Fast.io MCP documentation, agent instructions at https://mcp.fast.io/skill.md, and the agent onboarding reference.
  4. Search indexed knowledge: Rather than pulling entire folders across Microsoft Graph, agents query files through Fast.io AI Intelligence Mode, which indexes documents for hybrid search combining full-text search and semantic vector embeddings. Agents retrieve relevant excerpts with exact citations.

In cross-provider connector benchmarks published at Fast.io connector benchmarks, Fastio was measured the fastest and the lowest cost of the providers tested.

When agents generate deliverables, reports, or updated codebases, they write directly into shared workspaces or branded shares configured for storage for agents. Per-file version history tracks every modification, and the append-only audit log records who edited what and when. Monthly plans start with a 30-day free trial on Fast.io pricing. Teams maintain centralized visibility over agent activity without managing low-level byte fragmentation or socket timeouts.

Sources

References used to verify factual claims in this guide.

  1. Microsoft Graph upload sessions require fragment sizes to be multiples of 320 KiB.

  2. Microsoft Graph simple PUT content endpoint accepts file uploads up to 250 MB in a single call.

Frequently Asked Questions

How do I upload a file to OneDrive using API?

Upload small files under four megabytes by issuing an HTTP PUT request with the binary payload directly to `/me/drive/root:/{path}:/content`. For files four megabytes and larger, send a POST request to `/me/drive/root:/{path}:/createUploadSession` to obtain a preauthenticated upload URL, then stream byte fragments sequentially in multiples of 320 KiB using HTTP PUT calls with Content-Range headers.

What is the file size limit for OneDrive simple upload API?

Microsoft Graph simple PUT content endpoint accepts file uploads up to 250 MB in a single call. However, production workflows should limit simple PUT requests to smaller payloads under four megabytes. Larger files lack pause and resume capabilities, making them vulnerable to network interruptions, reverse proxy timeouts, and socket drops.

How do I resume an interrupted OneDrive upload session?

Issue an HTTP GET request to the session upload URL without an authorization header. Microsoft Graph responds with HTTP 200 OK and a nextExpectedRanges array indicating the missing byte positions. Use the first range offset to seek your local file pointer and resume sequential chunk PUT requests.

Why must OneDrive upload session chunks be multiples of 320 KiB?

Microsoft Graph upload sessions require fragment sizes to be multiples of 320 KiB because backend Azure storage clusters allocate data in 320 KiB (327,680 bytes) blocks. Slices that do not divide evenly by 320 KiB cause commit errors or silent file corruption, except for the final remainder slice that terminates at the end of the file.

How long does a OneDrive upload session remain active before expiring?

Upload sessions typically remain active for 24 hours from creation. Every successfully accepted byte fragment extends the session expiration timestamp, which is returned in the expirationDateTime field of each HTTP 202 Accepted response. Inactive sessions are purged automatically.

Related Resources

Fastio features

Connect OneDrive Storage to Agent Workspaces

Sync your existing OneDrive directories into a Fastio workspace on a schedule or on demand, giving your AI agents indexed semantic search over remote files without local chunking. Starts with a 30-day free trial.