How to Upload Files to SharePoint via API: Graph vs REST Methods
Uploading files to SharePoint via API involves choosing between modern Microsoft Graph endpoints and legacy SharePoint REST methods. While single-call PUT requests handle files up to 250 MB, larger assets require resumable upload sessions with strict 320 KiB chunk alignment. This guide covers simple uploads, chunked transfer implementations, error recovery, and intelligent workspace sync for automated pipelines.
When to Choose Microsoft Graph vs SharePoint REST for File Uploads
Uploading files to SharePoint via API creates an immediate operational split between lightweight single-request endpoints and stateful chunked upload sessions. If an automated script or agent pushes a 300 MB dataset using a standard HTTP PUT request against Microsoft Graph, the transfer fails immediately because single-call endpoints cap out at 250 MB. Conversely, shifting to chunked sessions requires implementing byte-range arithmetic, session persistence, and retry logic to survive transient network drops.
The SharePoint upload API consists of Microsoft Graph and SharePoint REST endpoints that allow applications to upload small binary files directly or stream large files via chunked upload sessions. Engineering teams building enterprise connectors, automated ingestion pipelines, and agent integrations encounter two distinct API surfaces across Microsoft 365: the modern Microsoft Graph REST API and the legacy SharePoint REST interface.
Microsoft Graph represents Microsoft's unified development surface (https://graph.microsoft.com/v1.0/). It accesses SharePoint document libraries through standardized /sites and /drives endpoints, relying on Microsoft Entra ID OAuth 2.0 bearer tokens. In contrast, the legacy SharePoint REST API (/_api/web/...) dates back to SharePoint 2013 and on-premises deployments. Legacy endpoints require managing SharePoint form digests (X-RequestDigest), navigating site-relative server paths, and interacting with legacy Client-Side Object Model (CSOM) methods.
Decision Framework for SharePoint File Uploads
Choosing the correct upload method depends on file size, network stability, and destination architecture:
Modern development on SharePoint Online should standardize on Microsoft Graph. Graph provides unified authentication across Microsoft 365, consistent JSON error responses, higher default payload limits, and active engineering support. Legacy SharePoint REST remains necessary only when maintaining legacy on-premises SharePoint farms or executing legacy CSOM automations that depend on server-relative web contexts.
Related guides
- How to Upload Files to Dropbox via API: Simple vs Upload SessionsChoosing how to use the Dropbox API to upload file contents depends on asset size and network reliability. The Dropbox...
- SharePoint API Download File: REST, Graph API & Agent Storage PatternsDownloading a file via SharePoint API involves requesting the binary stream from a driveItem content endpoint using...
- How to Create Folders with SharePoint API: REST, Graph, and Agent WorkspacesCreating folders across SharePoint environments requires choosing between legacy REST endpoints and modern Microsoft...
- How to Connect Python to SharePoint: Native Graph API vs Intelligent WorkspacesConnecting Python to SharePoint via the Microsoft Graph API requires handling MSAL authentication, tenant permissions,...
- SharePoint Delta Sync: Graph API Delta Queries & AI Agent IndexingSharePoint delta sync uses Microsoft Graph delta queries to track incremental file additions, edits, and deletions...
- How to Connect n8n Workflow Agents to SharePoint FilesAn n8n SharePoint integration links workflow automation pipelines and AI agent nodes with Microsoft SharePoint document...
More on this subject: Agent File and Document Workflows (394 guides)
How to Upload Small Files Using Microsoft Graph and REST
For files under a few megabytes, single-call endpoints offer the simplest implementation. They transmit the entire binary payload in a single HTTP request without creating persistent session state on the server.
Microsoft Graph Simple PUT Upload
Microsoft Graph supports single-call PUT uploads up to 250 MB for SharePoint items. While the API accommodates files up to this ceiling, Microsoft documentation recommends using upload sessions for items larger than 10 MB to prevent socket timeouts on unstable connections.
To upload a new file, construct an HTTP PUT request targeting the target folder DriveItem using its path:
PUT https://graph.microsoft.com/v1.0/sites/{site-id}/drive/items/{parent-id}:/{filename}:/content
Authorization: Bearer {token}
Content-Type: application/octet-stream
<raw file binary bytes>
To implement this upload in Python using the requests library:
pip install requests
import requests
def upload_small_file_graph(
access_token: str,
site_id: str,
parent_folder_id: str,
file_path: str,
target_filename: str,
) -> dict:
"""Upload a file under 250 MB to SharePoint in a single Graph API PUT call."""
url = f"https://graph.microsoft.com/v1.0/sites/{site_id}/drive/items/{parent_folder_id}:/{target_filename}:/content"
headers = {
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/octet-stream",
}
with open(file_path, "rb") as f:
file_bytes = f.read()
response = requests.put(url, headers=headers, data=file_bytes, timeout=60)
response.raise_for_status()
return response.json()
If the file uploads successfully, Microsoft Graph returns HTTP 201 Created for new items or HTTP 200 OK when updating an existing file, accompanied by the DriveItem metadata record.
Legacy SharePoint REST Files/add Method
The legacy SharePoint REST API uploads small files by targeting the folder collection directly:
POST https://{tenant}.sharepoint.com/sites/{site}/_api/web/GetFolderByServerRelativeUrl('{folder_url}')/Files/add(url='{filename}',overwrite=true)
Authorization: Bearer {token}
Accept: application/json;odata=verbose
X-RequestDigest: {form_digest_value}
Content-Type: application/octet-stream
<raw file binary bytes>
Unlike Microsoft Graph, which validates identity entirely through the Entra ID bearer token, legacy SharePoint REST endpoints require a form digest value. The client must first execute a POST request to https://{tenant}.sharepoint.com/sites/{site}/_api/contextinfo to retrieve FormDigestValue before initiating the upload. Furthermore, while the theoretical request limit for Files/add is larger in modern SharePoint Online, sending large payloads in a single request frequently causes connection timeouts and gateway failures.
Steps to Upload Large Files with Microsoft Graph Resumable Sessions
When uploading large datasets, disk images, media archives, or CAD files to SharePoint, single-request uploads become fragile. A brief network interruption terminates the connection, discarding all transferred bytes. Microsoft Graph resolves this problem with resumable upload sessions.
The Three-Step Upload Session Architecture
A Graph upload session breaks file transmission into three distinct phases:
- Create the Upload Session: The client requests an upload session for the target item.
- Stream Chunks Sequentially: The client slices the file into ordered fragments and PUTs each chunk to a dedicated upload URL.
- Commit the File: Once the final byte range arrives, the storage engine commits the file and returns DriveItem metadata.
To create the upload session, issue a POST request to the DriveItem path:
POST https://graph.microsoft.com/v1.0/sites/{site-id}/drive/items/{parent-id}:/{filename}:/createUploadSession
Authorization: Bearer {token}
Content-Type: application/json
{
"item": {
"@microsoft.graph.conflictBehavior": "replace",
"name": "quarterly_financials_archive.zip"
}
}
The response returns an uploadUrl and an expirationDateTime (typically valid for 24 hours):
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#microsoft.graph.uploadSession",
"uploadUrl": "https://sn3302.up.1drv.com/up/fe6987415ace7X4e1eF866337",
"expirationDateTime": "2026-10-05T10:30:00.000Z",
"nextExpectedRanges": ["0-"]
}
Chunk Slicing Rules and Alignment Requirements
Uploading large files in chunks via Microsoft Graph upload sessions requires byte ranges to be multiples of 320 KiB. Specifically, each fragment MUST be an exact multiple of 327,680 bytes (such as 3,276,800 bytes for 3.125 MiB, or 10,485,760 bytes for 10 MiB), with a maximum fragment size of 60 MiB. Using a fragment size that does not divide evenly by 320 KiB results in commit errors on the final request. The final fragment containing the remainder of the file does not need to be a multiple of 320 KiB.
Each chunk request requires two critical headers:
Content-Length: The exact number of bytes in the current request chunk.Content-Range: The byte range represented by this chunk, formatted asbytes {start}-{end}/{total_file_size}.
Do not include the Authorization header when sending PUT requests to the uploadUrl. The uploadUrl is an authenticated temporary endpoint containing an embedded cryptographic signature. Sending an Authorization: Bearer header can trigger an HTTP 401 Unauthorized response from the storage endpoint.
Python Implementation for Graph Chunked Uploads
The following Python script reads a large local file, requests an upload session, slices the file into 3,276,800-byte chunks (exactly 10 multiples of 320 KiB), and streams the fragments sequentially:
import os
import requests
CHUNK_SIZE = 10 * 320 * 1024 ### 3,276,800 bytes (multiple of 320 KiB)
def create_graph_upload_session(
token: str, site_id: str, parent_id: str, filename: str
) -> str:
"""Initiate an upload session and return the temporary uploadUrl."""
url = f"https://graph.microsoft.com/v1.0/sites/{site_id}/drive/items/{parent_id}:/{filename}:/createUploadSession"
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json",
}
payload = {
"item": {
"@microsoft.graph.conflictBehavior": "replace",
"name": filename,
}
}
resp = requests.post(url, headers=headers, json=payload, timeout=30)
resp.raise_for_status()
return resp.json()["uploadUrl"]
def upload_file_in_chunks(upload_url: str, file_path: str) -> dict:
"""Upload local file chunks sequentially to the Graph uploadUrl."""
total_size = os.path.getsize(file_path)
with open(file_path, "rb") as f:
start_byte = 0
while start_byte < total_size:
chunk_data = f.read(CHUNK_SIZE)
chunk_length = len(chunk_data)
end_byte = start_byte + chunk_length - 1
headers = {
"Content-Length": str(chunk_length),
"Content-Range": f"bytes {start_byte}-{end_byte}/{total_size}",
}
resp = requests.put(
upload_url, headers=headers, data=chunk_data, timeout=60
)
### Intermediate chunks return 202 Accepted
if resp.status_code == 202:
start_byte += chunk_length
continue
### Final chunk returns 201 Created or 200 OK with DriveItem metadata
if resp.status_code in (200, 201):
return resp.json()
resp.raise_for_status()
raise RuntimeError("Upload finished without receiving DriveItem metadata")
Connect SharePoint Files to Your Agent Workspaces
Sync SharePoint document libraries into intelligent workspaces with hybrid search and remote MCP tools. Monthly plans start with a 14-day free trial.
How to Handle Errors and Resume Interrupted SharePoint Uploads
In production environments, network drops, socket timeouts, and transient cloud errors inevitably interrupt long-running file transfers. The primary gap in most SharePoint upload guides is omitting error recovery. Microsoft Graph upload sessions provide deterministic inspection and resumption mechanics.
Querying Upload Status and Resuming Transfers
If an upload request drops midway through a multi-gigabyte transfer, all bytes in that active request are discarded, but previously completed fragments remain stored on the server. To discover where the upload should resume, issue an HTTP GET request to the uploadUrl:
GET https://sn3302.up.1drv.com/up/fe6987415ace7X4e1eF866337
The server returns an HTTP 200 OK response with the remaining missing ranges:
{
"expirationDateTime": "2026-10-05T10:30:00.000Z",
"nextExpectedRanges": ["32768000-"]
}
The nextExpectedRanges property tells the client the exact starting byte offset. The client seeks to that offset in the local file and resumes streaming subsequent fragments.
Handling Common HTTP Error Codes
Production upload workers must handle standard HTTP failure modes:
- HTTP 416 (Requested Range Not Satisfiable): Occurs when the client sends a byte range the server has already received. Issue a GET request to the
uploadUrlto resynchronize the client byte pointer. - HTTP 409 (Conflict): Returned on the final chunk if a conflicting file was added to the directory during the upload window. The client can re-commit the session with an updated filename using
@microsoft.graph.sourceUrland@microsoft.graph.conflictBehavior: "rename". - HTTP 429 (Too Many Requests): Microsoft Graph enforces tenant-wide request throttling. When receiving HTTP 429, extract the
Retry-Afterheader value and pause execution for the specified duration before attempting retries. - HTTP 5xx Server Errors (500, 502, 503, 504): Transient gateway and server issues require exponential backoff with randomized jitter.
- HTTP 404 (Not Found): Indicates that the upload session expired or was explicitly deleted. The client must abort and generate a new upload session from scratch.
Cancelling Abandoned Upload Sessions
When a user cancels an upload, or when a worker experiences an unrecoverable local exception, cancel the session to clean up temporary storage buffers on Microsoft servers:
DELETE https://sn3302.up.1drv.com/up/fe6987415ace7X4e1eF866337
The server cleans up all temporary data and responds with HTTP 204 No Content.
Legacy SharePoint REST Chunked Upload Architecture
Before Microsoft Graph, SharePoint REST handled large files through three sequential CSOM endpoints on the file object:
+-------------------------------------------------------------------------+
| Legacy SharePoint REST Chunk Workflow |
+-------------------------------------------------------------------------+
| 1. POST .../Files/add(url='file.bin', overwrite=true) |
| (Create empty placeholder file record) |
| |
| 2. POST .../startupload(uploadId=guid'{guid}') |
| (Transmit chunk 1, initialize server-side buffer) |
| |
| 3. POST .../continueupload(uploadId=guid'{guid}', fileOffset={offset}) |
| (Transmit chunks 2 through N-1, tracking cumulative byte offset) |
| |
| 4. POST .../finishupload(uploadId=guid'{guid}', fileOffset={offset}) |
| (Transmit final chunk, commit binary to library) |
+-------------------------------------------------------------------------+
Unlike Microsoft Graph, which tracks uploaded ranges internally on the server and exposes them via GET requests, legacy REST chunking requires the client to track exact cumulative integer byte offsets across calls. If the client offset drifts by even one byte, the server throws an SPBITSSessionIncompleteException or corrupts the binary. Furthermore, managing form digest token expiration during lengthy multi-gigabyte transfers introduces authentication failure points that Graph eliminates.
Why Intelligent Workspaces Eliminate Upload Pipeline Maintenance
Engineering teams frequently build custom SharePoint upload pipelines not because they want to manage file chunks, but because autonomous agents and analytical pipelines need access to corporate documents. Developing and maintaining custom upload daemons, managing token refreshes across long-running transfers, and handling throttling across enterprise document libraries creates significant infrastructure overhead.
The Workspace Synchronization Approach
Your team keeps their existing storage exactly where it already lives. Rather than writing custom chunked upload daemons to ingest files, you can synchronize designated SharePoint document libraries into a Fast.io workspace using Cloud Sync through the OneDrive connector. Cloud Sync operates one-way or two-way, on a recurring schedule or on demand. (Google Drive, Dropbox, Box, and OneDrive folders sync the same way, on a schedule or on demand).
+-------------------------------------------------------+
| Microsoft SharePoint |
| (Authoritative File Store) |
+---------------------------+---------------------------+
|
| Cloud Sync (Scheduled or On-Demand)
v
+-------------------------------------------------------+
| Fast.io Workspace |
| - Automatic Semantic & Hybrid Search Indexing |
| - Metadata Views (Structured Schema Extraction) |
| - Per-File Version History & Detailed Activity Log |
+---------------------------+---------------------------+
|
| Remote MCP (Streamable HTTP)
v
+-------------------------------------------------------+
| Python AI Agent / Script |
| - Semantic Querying via MCP Tool Calls |
| - Exact Passage Retrieval with File Citations |
| - Zero Local Binary File Ingestion |
+-------------------------------------------------------+
Automatic Hybrid Indexing and Search
Once files sync into a Fast.io workspace, Intelligence Mode auto-indexes every document upon arrival. The workspace builds a hybrid search index combining full-text keyword search, semantic search, and search-by-metadata-value filtering.
Autonomous AI agents and developer scripts connect through the remote MCP server (Claude apps and general MCP clients at https://mcp.fast.io/mcp/tools, coding agents such as Claude Code and Cursor at https://mcp.fast.io/mcp/code), querying specific concepts and retrieving targeted passages with document citations instead of downloading whole multi-gigabyte folders.
Structured Extraction with Metadata Views
Beyond semantic search, enterprise workflows often require extracting structured operational data from uploaded files. Fast.io provides Metadata Views to turn document collections into queryable tables.
Users describe fields in natural language, and AI designs a typed schema supporting Text, Integer, Decimal, Boolean, URL, JSON, and Date & Time formats. Metadata Views process PDFs, spreadsheets, presentations, and scanned forms without rigid OCR rules or templates. Agents can trigger extractions and query structured results directly via MCP tools.
Governance, Versioning, and Performance
In every workspace, access is granted per organization, workspace and share through member roles, accompanied by per-file version history and a detailed activity log. When an agent finishes preparing files or configuring a workspace, ownership transfer allows the agent account to hand the organization over to a person with a claim link.
Performance evaluations across cloud workspaces are published in the Fastio benchmark comparison.
Strategic Implementation Recommendation
Standardize on the direct Microsoft Graph API when your application performs administrative site tasks, updates item permissions, creates document libraries, or executes low-frequency direct file transfers.
Adopt intelligent workspace synchronization via MCP when building agentic workflows, RAG applications, or automated data extraction pipelines. By allowing SharePoint to remain your team's system of record while connecting workspaces over MCP, you eliminate chunked upload maintenance, avoid Entra ID API quota exhaustion, and provide autonomous agents with immediate semantic search across enterprise files.
Sources
References used to verify factual claims in this guide.
-
Microsoft Graph supports single-call PUT uploads up to 250 MB for SharePoint items.
-
Uploading large files in chunks via Microsoft Graph upload sessions requires byte ranges to be multiples of 320 KiB.
Frequently Asked Questions
How do I upload a file to SharePoint using REST API?
To upload a file using the legacy SharePoint REST API, issue a POST request to https://{tenant}.sharepoint.com/sites/{site}/_api/web/GetFolderByServerRelativeUrl('{folder_path}')/Files/add(url='{filename}',overwrite=true). Include the file binary in the request body, set Content-Type to application/octet-stream, and provide an X-RequestDigest header obtained from /_api/contextinfo. For files larger than a few megabytes, use the startupload, continueupload, and finishupload chunked endpoints.
What is the maximum file size for SharePoint Graph API upload?
Microsoft Graph supports single-call PUT uploads up to 250 MB for SharePoint items. For files exceeding 250 MB, or for files where connection reliability is a concern, Microsoft Graph requires creating an upload session via createUploadSession to stream files to SharePoint in chunks.
How do I use an upload session in SharePoint?
To use an upload session in SharePoint via Microsoft Graph, send a POST request to /sites/{site-id}/drive/items/{parent-id}:/{filename}:/createUploadSession to obtain an uploadUrl. Then, upload chunks sequentially via Microsoft Graph upload session requests where byte ranges are exact multiples of 320 KiB and less than 60 MiB. Upload each chunk via an HTTP PUT request to the uploadUrl with Content-Range and Content-Length headers, omitting the Authorization header. The final chunk returns the completed DriveItem metadata.
Why does Microsoft Graph require chunk sizes in multiples of 320 KiB?
Microsoft Graph requires chunk byte ranges to be exact multiples of 320 KiB (327,680 bytes) because the underlying storage infrastructure processes fragmented byte streams in fixed-size blocks. If a non-final fragment is not divisible by 320 KiB, the storage service rejects the byte range or fails during the final commit.
What causes HTTP 401 Unauthorized errors when uploading chunks to uploadUrl?
An HTTP 401 Unauthorized error during chunk upload usually occurs when a client includes an Authorization header with an Entra ID bearer token in the PUT request to the uploadUrl. The uploadUrl already contains a pre-authenticated signed token; passing an additional Authorization header causes authentication validation conflicts.
Can AI agents access SharePoint documents without implementing upload sessions?
Yes. Rather than writing custom chunked upload daemons and local parsing logic, teams can synchronize SharePoint document libraries into a Fast.io workspace using Cloud Sync via the OneDrive connector. Files are automatically indexed upon arrival for hybrid semantic search, allowing AI agents to query content directly over remote MCP without downloading large binary files.
Related Resources
Connect SharePoint Files to Your Agent Workspaces
Sync SharePoint document libraries into intelligent workspaces with hybrid search and remote MCP tools. Monthly plans start with a 14-day free trial.