How to Convert Files to PDF with Microsoft Graph API
Convert OneDrive and SharePoint files to PDF with Microsoft Graph using format=pdf, redirects, permissions, code examples, and troubleshooting.
Microsoft Graph converts a supported OneDrive, OneDrive for Business, or SharePoint driveItem to PDF through the content endpoint. Add format=pdf, send an authenticated GET, then follow the 302 Found redirect in the Location header to download the PDF bytes.
The basic request is:
GET https://graph.microsoft.com/v1.0/me/drive/items/{item-id}/content?format=pdf
Authorization: Bearer ACCESS_TOKEN
The converted response is temporary. Microsoft returns a preauthenticated download URL that normally remains valid for only a short period, so follow it promptly and do not add your Graph authorization header to that second request. See Microsoft’s convert to other formats reference.
1. What the conversion endpoint does
This is a content-download operation, not a separate export job. The ordinary /content route downloads the original file. Appending ?format=pdf asks Graph to produce a PDF rendition instead. Microsoft explicitly warns that not all files can be converted into all formats, so check the supported-source table before building a workflow.
| Goal | Request | Result |
|---|---|---|
| Download the original file | /content |
Original bytes and media type |
| Convert to PDF | /content?format=pdf |
PDF bytes through a redirect |
Common supported sources include DOC and DOCX, PPT and PPTX, XLS and XLSX, HTML, EPUB, ODT, RTF, TIFF, and several email and image formats. The complete list changes with the API documentation; consult the current supported-extension table rather than assuming every extension works.
2. Before you write code
- Register or select an app in Microsoft Entra ID and configure the account flow you need.
- Obtain a Graph access token for the user or application that can read the file.
- Identify the drive item by item ID, drive ID, site and library, or path.
- Confirm the source extension appears in Microsoft’s PDF conversion table.
- Choose least-privileged permissions. For delegated work or school and personal accounts, Microsoft lists
Files.Readas least privileged for this conversion call. For application permissions, it listsFiles.ReadWrite.All. SharePoint Embedded also requiresFileStorageContainer.Selectedand the applicable container-type permissions. Actual access still depends on the file, drive, site, and container context.
File operations use the drive and driveItem resources across OneDrive, OneDrive for Business, and SharePoint document libraries. The endpoint is documented for the Global, US Government L4, US Government L5 (DoD), and China operated by 21Vianet national clouds.
3. Address a file by item ID
For a file in the signed-in user’s OneDrive:
GET https://graph.microsoft.com/v1.0/me/drive/items/{item-id}/content?format=pdf
For a specific drive:
GET https://graph.microsoft.com/v1.0/drives/{drive-id}/items/{item-id}/content?format=pdf
Item IDs are stable identifiers for the item in that drive. Resolve them first with the drive, site, or search APIs when your application starts with a filename or URL.
4. Address a file by path
Graph also supports root-relative path addressing. URL-encode path segments, especially spaces, #, ?, and percent signs.
GET https://graph.microsoft.com/v1.0/me/drive/root:/Reports/Quarterly report.docx:/content?format=pdf
For SharePoint or another drive, use the corresponding /drives/{drive-id}/root:/path:/content?format=pdf form. Item IDs are usually safer for repeatable processing because a rename does not require rebuilding a path.
5. cURL: follow the redirect and save the PDF
Use -D - while debugging so you can see the Graph response. In production, --location follows the temporary download URL and writes the final bytes.
curl --fail --show-error --location \
-H "Authorization: Bearer $GRAPH_ACCESS_TOKEN" \
"https://graph.microsoft.com/v1.0/me/drive/items/$ITEM_ID/content?format=pdf" \
-o converted.pdf
If you need to inspect the redirect manually:
curl --include --dump-header graph-headers.txt \
-H "Authorization: Bearer $GRAPH_ACCESS_TOKEN" \
"https://graph.microsoft.com/v1.0/me/drive/items/$ITEM_ID/content?format=pdf"
Read the Location value from the 302 response, then request that URL without the Graph Authorization header:
curl --fail --show-error "$LOCATION" -o converted.pdf
6. Python implementation
This example disables automatic redirects so it can validate the documented two-step exchange and avoid accidentally sending credentials to a different host.
import os
from pathlib import Path
from urllib.parse import urljoin
import requests
GRAPH = "https://graph.microsoft.com/v1.0"
token = os.environ["GRAPH_ACCESS_TOKEN"]
item_id = os.environ["GRAPH_ITEM_ID"]
content_url = f"{GRAPH}/me/drive/items/{item_id}/content"
response = requests.get(
content_url,
params={"format": "pdf"},
headers={"Authorization": f"Bearer {token}"},
allow_redirects=False,
timeout=90,
)
response.raise_for_status()
if response.status_code not in (301, 302, 303, 307, 308):
raise RuntimeError(f"Expected a redirect, got {response.status_code}")
location = response.headers.get("Location")
if not location:
raise RuntimeError("Graph returned a redirect without a Location header")
download = requests.get(location, timeout=90)
download.raise_for_status()
Path("converted.pdf").write_bytes(download.content)
print("Wrote converted.pdf")
For a trusted client that follows redirects automatically, requests.get(..., allow_redirects=True) is shorter. Keeping the two requests explicit makes it easier to log status codes, enforce a redirect policy, and avoid leaking the bearer token.
7. Node.js implementation
Node.js 18 or later includes fetch. The first request receives the redirect; the second downloads the PDF without the Graph token.
import { writeFile } from "node:fs/promises";
const token = process.env.GRAPH_ACCESS_TOKEN;
const itemId = process.env.GRAPH_ITEM_ID;
const endpoint = new URL(
`https://graph.microsoft.com/v1.0/me/drive/items/${encodeURIComponent(itemId)}/content`
);
endpoint.searchParams.set("format", "pdf");
const graphResponse = await fetch(endpoint, {
headers: { Authorization: `Bearer ${token}` },
redirect: "manual"
});
if (![301, 302, 303, 307, 308].includes(graphResponse.status)) {
throw new Error(`Graph returned ${graphResponse.status}`);
}
const location = graphResponse.headers.get("location");
if (!location) throw new Error("Missing Location header");
const pdfResponse = await fetch(location);
if (!pdfResponse.ok) {
throw new Error(`PDF download returned ${pdfResponse.status}`);
}
await writeFile("converted.pdf", Buffer.from(await pdfResponse.arrayBuffer()));
console.log("Wrote converted.pdf");
If you use an HTTP library with automatic redirects, verify its redirect policy and header behavior. The preauthenticated URL is the credential for the download; do not copy the bearer token onto that request.
8. Raw HTTP request
GET /v1.0/me/drive/items/0123456789/content?format=pdf HTTP/1.1
Host: graph.microsoft.com
Authorization: Bearer eyJ...
HTTP/1.1 302 Found
Location: https://...
The redirect target returns the PDF body. Save it as binary data and use the response’s content type and length for validation. Do not parse PDF bytes as UTF-8 text.
9. Permissions and access patterns
| Access pattern | Least-privileged permission listed by Microsoft | Notes |
|---|---|---|
| Delegated, work or school account | Files.Read |
The signed-in user must be able to read the item. |
| Delegated, personal Microsoft account | Files.Read |
The item must be in the user’s accessible OneDrive. |
| Application permission | Files.ReadWrite.All |
Use only when an app-only workflow is required. |
| SharePoint Embedded | FileStorageContainer.Selected plus container permissions |
These requirements are additional to Graph permissions. |
Requesting a broader scope does not bypass SharePoint permissions, item sharing restrictions, conditional access, or tenant policies. Keep tokens on the server and grant only the access mode your deployment needs. See Microsoft’s permissions section.
10. Supported files and conversion limits
Conversion is dependent on both the source extension and the requested target. A DOCX that converts successfully does not imply that an arbitrary binary, protected file, or unfamiliar extension will convert. Microsoft’s reference includes Office documents plus HTML, EPUB, ODT, RTF, TIFF, message formats, and many others.
- Check the current source-extension table before accepting an upload.
- Preserve the original file so a conversion failure does not destroy source data.
- Expect layout differences for unusual fonts, macros, embedded media, formulas, or unsupported features.
- Treat password-protected, encrypted, corrupted, or partially synchronized items as possible failures.
- Do not promise universal conversion; Microsoft states that not all files can be converted into all formats.
11. Error handling and troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
401 Unauthorized |
Missing, expired, or incorrectly scoped token | Acquire a fresh token for Microsoft Graph and send it only to the Graph request. |
403 Forbidden |
The app or user cannot read the drive item, or SharePoint policy blocks access | Verify consent, least-privileged scope, site/library permissions, and container permissions. |
404 Not Found |
Wrong drive, item ID, path, or account context | Resolve the item again in the same drive and use the correct addressing form. |
400 Bad Request |
Malformed URL, path encoding, or unsupported query value | URL-encode path segments and use exactly format=pdf. |
302 but no file saved |
Client did not follow Location |
Enable redirects or make the second request explicitly. |
| Download URL returns an error | The short-lived URL expired or was reused too late | Request a new conversion URL and download immediately. |
| Conversion fails for one extension | Source type is not supported or the file contains unsupported content | Check the live supported-format table and test a representative file. |
| PDF is unreadable | Binary data was decoded as text or truncated | Write the response body as bytes and verify the file begins with the PDF signature. |
| Throttling response | Tenant or service request limits | Honor Retry-After, use exponential backoff with jitter, and avoid duplicate conversions. |
12. Reliability, performance, and cost notes
Redirect and retry behavior
Conversion and download are separate network operations. Put a deadline around each, log both status codes, and retry only transient failures. If the redirect target expires, repeat the Graph request instead of retrying an old download URL.
Reduce unnecessary work
- Cache a PDF keyed by the drive item ID and source version or eTag when your product can tolerate it.
- Do not reconvert unchanged files in a polling loop.
- Use bounded concurrency for batches and respect
Retry-After. - Stream large responses to disk instead of holding every PDF in memory.
- Record source ID, source version, conversion status, and byte count for auditability.
Microsoft’s reference does not publish a universal conversion latency, success rate, or fidelity benchmark. Measure your own file mix and tenant conditions if those values affect an SLA.
13. A production checklist
- Use the v1.0 endpoint and the correct national-cloud host for your deployment.
- Confirm the item is in OneDrive, OneDrive for Business, or a SharePoint document library you can access.
- Grant the narrowest permission that matches delegated or application access.
- Verify the source extension against Microsoft’s current table.
- Send
format=pdfon the content request. - Follow
Locationpromptly and omit the Graph bearer token from the follow-up. - Save bytes, not decoded text.
- Handle expired redirects, throttling, permission errors, and unsupported formats.
- Keep the original file and conversion metadata.
14. Or skip the browser setup
If your actual goal is a visual capture of a web page rather than converting a OneDrive or SharePoint file, ScreenshotNeo provides a one-call screenshot API. It is a different workflow from Microsoft Graph file conversion, but it removes browser automation when you need PNG, JPEG, WebP, or PDF output from a URL.
See the ScreenshotNeo API documentation for all options. A minimal request is:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' }); const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before capture. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers identify the page verdict and billing result. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.
15. FAQ
Does ?format=pdf download the original file?
No. The plain /content route downloads the original. The format=pdf variant requests a converted rendition.
Can I use a filename instead of an item ID?
Yes. Use the documented root-relative path form, with correct URL encoding. Item IDs are generally less fragile when files can be renamed.
Do I send the bearer token to the redirect URL?
No. The redirect target is preauthenticated. Send the Graph token to Microsoft Graph, then fetch the returned URL without that header.
Is conversion asynchronous?
The documented flow is a content request followed by a redirect and download. Your client should still use timeouts and handle throttling for large or busy workloads.
Where can I verify whether a file type is supported?
Use Microsoft’s live supported-format table; support is source-format dependent.


