SharePoint/OneDrive API Automation
Automate SharePoint and OneDrive for Business operations using agent-browser with SharePoint REST APIs. Execute authenticated API calls from JavaScript within a browser context, avoiding OAuth token management while gaining full access to SharePoint's RenderListDataAsStream, Graph API (SharePoint-hosted), and direct file operations.
Why This Approach
API over browser automation → 10-100x faster, reliable, structured data, composable with jq/other tools.
agent-browser for authentication → Inherits session cookies from authenticated browser profile, no OAuth flow required.
Works across tenant types → Commercial, GCC, GCC High with URL configuration only.
⚠️ Critical: Browser JavaScript Context
agent-browser executes JavaScript in Chromium browser, NOT Node.js.
Browser JavaScript does NOT have process.env. All scripts use bash template substitution to pass variables.
✅ Correct Pattern (used throughout skill):
VAR="value"
cat <<EOF | agent-browser eval --stdin
const myVar = "$VAR"; // Bash substitutes before sending to browser
EOF
❌ Wrong Pattern (will fail):
export VAR="value"
cat <<'EOF' | agent-browser eval --stdin
const myVar = process.env.VAR; // ERROR: process not defined in browser
EOF
Key differences:
- Use
<<EOF(no quotes) to enable bash variable substitution - Use
<<'EOF'(with quotes) to prevent substitution - Escape template literals:
\${variable}`` in heredoc - Browser has
fetch(),window,document - Browser lacks
process,require(),Buffer,fs
Prerequisites
- agent-browser installed and in PATH
- Chrome/Chromium browser
Note: SharePoint profile and configuration are created automatically by the skill on first use via an interactive wizard.
Quick Start
1. Provision Profile (First Time Only)
On first use, the skill will automatically prompt you to provision a SharePoint profile:
cd /path/to/skills/sharepoint-api
# Create session (will launch provision wizard if needed)
bash scripts/session-manager.sh create
The wizard will:
- Prompt for your tenant type (Commercial, GCC High, or Custom)
- Collect tenant URL and user path
- Open a browser for Microsoft 365 authentication
- Save configuration to
.configfile - Store authenticated profile in
profile/directory
Or provision explicitly:
bash scripts/provision-profile.sh
2. Create Session
After provisioning, create sessions normally:
bash scripts/session-manager.sh create
Configuration is automatically loaded from .config file.
3. Use the Skill
# List root files
bash scripts/list-files.sh
# List subfolder
bash scripts/list-files.sh --folder "Projects/2024"
# Filter by type
bash scripts/list-files.sh --type pptx --limit 10
# Download file
bash scripts/download-file.sh "Documents/report.pdf"
All scripts automatically load configuration from .config file.
Core Patterns
Session Management
The skill automatically manages browser profile locks:
# Create session (handles cleanup automatically)
bash scripts/session-manager.sh create
# Check status
bash scripts/session-manager.sh status
# Cleanup manually if needed
bash scripts/session-manager.sh cleanup
Profile is stored in <skill-dir>/profile/ and managed by the skill.
API Call Pattern
Execute JavaScript fetch() within authenticated browser context:
cat <<'EOF' | agent-browser --session "$SESSION" eval --stdin
(async () => {
const response = await fetch('https://TENANT/_api/ENDPOINT', {
method: 'POST',
headers: {
'Accept': 'application/json;odata=verbose',
'Content-Type': 'application/json;odata=verbose'
},
body: JSON.stringify({ /* parameters */ })
});
const data = await response.json();
return JSON.stringify(data, null, 2);
})();
EOF
Error Handling
# Check response status
cat <<'EOF' | agent-browser --session "$SESSION" eval --stdin
(async () => {
const response = await fetch(url, options);
if (!response.ok) {
return JSON.stringify({
error: true,
status: response.status,
statusText: response.statusText
}, null, 2);
}
return JSON.stringify(await response.json(), null, 2);
})();
EOF
Microsoft Graph API (Recommended)
Endpoint: /_api/v2.0/me/drive/*
Graph API is simpler and more reliable than SharePoint REST for file operations.
Advantages:
- No personal path construction needed (uses
/meendpoint) - Simpler URL structure
- Better error messages
- Consistent across tenant types
- Modern JSON responses
List files:
bash scripts/list-files-graph.sh
bash scripts/list-files-graph.sh "Documents/Subfolder"
Direct API calls:
# List root
cat <<EOF | agent-browser --session "$SESSION" eval --stdin
(async () => {
const response = await fetch("$SP_TENANT_URL/_api/v2.0/me/drive/root/children");
const data = await response.json();
return JSON.stringify(data.value.map(item => ({
name: item.name,
type: item.folder ? 'folder' : 'file',
size: item.size,
modified: item.lastModifiedDateTime
})), null, 2);
})();
EOF
# List specific folder
cat <<EOF | agent-browser --session "$SESSION" eval --stdin
(async () => {
const response = await fetch("$SP_TENANT_URL/_api/v2.0/me/drive/root:/Documents/Project:/children");
const data = await response.json();
return JSON.stringify(data.value, null, 2);
})();
EOF
Common Operations
List Files (Root)
Endpoint: RenderListDataAsStream
const response = await fetch(
`${SP_TENANT_URL}${SP_USER_PATH}/_api/web/GetListUsingPath(DecodedUrl=@a1)/RenderListDataAsStream?@a1='${encodeURIComponent(SP_USER_PATH + '/Documents')}'&TryNewExperienceSingle=TRUE`,
{
method: 'POST',
headers: {
'Accept': 'application/json;odata=verbose',
'Content-Type': 'application/json;odata=verbose'
},
body: JSON.stringify({
parameters: {
__metadata: { type: 'SP.RenderListDataParameters' },
RenderOptions: 5691143
}
})
}
);
const data = await response.json();
const files = data.ListData.Row.map(item => ({
name: item.FileLeafRef,
type: item.FSObjType === '1' ? 'folder' : 'file',
size: parseInt(item.SMTotalSize || 0),
modified: item['Modified.'],
fileType: item['File_x0020_Type'] || 'folder',
path: item.FileRef
}));
return files;
Response Fields:
FileLeafRef→ filenameFSObjType→ "0" (file) / "1" (folder)SMTotalSize→ size in bytes (string)Modified.→ ISO-8601 timestampFile_x0020_Type→ extension (docx, xlsx, pdf, ...)FileRef→ full server-relative pathUniqueId→ GUID
List Subfolder Files
Add FolderServerRelativeUrl parameter:
{
parameters: {
__metadata: { type: 'SP.RenderListDataParameters' },
RenderOptions: 5691143,
FolderServerRelativeUrl: `${SP_USER_PATH}/Documents/Projects`
}
}
Filter by File Type
Use ViewXml with CAML query:
{
parameters: {
__metadata: { type: 'SP.RenderListDataParameters' },
RenderOptions: 5691143,
ViewXml: '<View><Query><Where><Eq><FieldRef Name="File_x0020_Type"/><Value Type="Text">pptx</Value></Eq></Where></Query></View>'
}
}
Pagination
ViewXml: '<View><RowLimit>50</RowLimit></View>'
For subsequent pages, include DirPagingInfo from previous response.
Download Files
Direct path (authenticated via browser session):
const fileUrl = `${SP_TENANT_URL}${SP_USER_PATH}/Documents/report.pdf`;
// Check if exists
const headResponse = await fetch(fileUrl, { method: 'HEAD' });
if (!headResponse.ok) {
throw new Error(`File not found: ${headResponse.status}`);
}
// Download (optional ?download=1 forces download vs preview)
const response = await fetch(`${fileUrl}?download=1`);
const blob = await response.blob();
// ... handle blob (save to file, etc.)
Upload Files
Use SharePoint's /_api/web/GetFolderByServerRelativeUrl() endpoint:
// 1. Read file as ArrayBuffer (in Node) or from File input (in browser)
// 2. Upload via POST
const uploadUrl = `${SP_TENANT_URL}/_api/web/GetFolderByServerRelativeUrl('${folderPath}')/Files/add(url='${filename}',overwrite=true)`;
const response = await fetch(uploadUrl, {
method: 'POST',
headers: {
'Accept': 'application/json;odata=verbose',
'Content-Type': 'application/octet-stream'
},
body: fileArrayBuffer
});
Microsoft Graph API (SharePoint-hosted)
Works with browser authentication (no separate OAuth token):
const response = await fetch(`${SP_TENANT_URL}/_api/v2.0/me/drive/root/children`);
const data = await response.json();
data.value.forEach(item => {
console.log(item.name, item.size, item.lastModifiedDateTime);
});
Does not work: Public https://graph.microsoft.com/v1.0/... (requires OAuth token).
Scripts Reference
Five bundled scripts in scripts/. Run with bash scripts/<name>.sh or copy into your project.
session-manager.sh
Create, check, and destroy SharePoint sessions with proper profile lock handling.
bash scripts/session-manager.sh create # Create new session
bash scripts/session-manager.sh status # Check current session
bash scripts/session-manager.sh destroy # Cleanup session
bash scripts/session-manager.sh cleanup # Force cleanup (kill processes, remove locks)
list-files.sh
List files and folders with filtering, pagination, and output formatting.
bash scripts/list-files.sh # List root
bash scripts/list-files.sh --folder "Projects" # List subfolder
bash scripts/list-files.sh --type docx # Filter by extension
bash scripts/list-files.sh --limit 20 # Limit results
bash scripts/list-files.sh --format json # Output format (json|csv|table)
bash scripts/list-files.sh --modified-after "2024-01-01" # Date filter
download-file.sh
Download files from SharePoint/OneDrive.
bash scripts/download-file.sh "Documents/report.pdf"
bash scripts/download-file.sh "Documents/report.pdf" --output ~/Downloads/
bash scripts/download-file.sh "Documents/*.pdf" --batch # Pattern matching
bash scripts/download-file.sh "Documents/big-file.zip" --resume # Resume partial
upload-file.sh
Upload files to SharePoint/OneDrive.
bash scripts/upload-file.sh local.pdf "Documents/remote.pdf"
bash scripts/upload-file.sh *.docx "Documents/Batch/" # Batch upload
bash scripts/upload-file.sh file.pdf "Documents/" --overwrite
bash scripts/upload-file.sh file.pdf "Documents/" --rename # Auto-rename on conflict
discover-api.sh
Capture network traffic to discover new SharePoint API endpoints.
bash scripts/discover-api.sh # Interactive mode
bash scripts/discover-api.sh --auto --output apis.json # Auto-navigate common pages
bash scripts/discover-api.sh --replay apis.json # Replay captured requests
Configuration
Configuration is stored in <skill-dir>/.config and automatically loaded by all scripts.
Auto-Generated Configuration
Created by provision-profile.sh, contains:
| Variable | Description | Example |
|---|---|---|
SP_TENANT_URL |
SharePoint tenant base URL | https://contoso.sharepoint.com |
SP_USER_PATH |
Personal site path | /personal/john_contoso_com |
SP_PROFILE_PATH |
Profile directory (within skill) | <skill-dir>/profile |
SP_TENANT_TYPE |
Tenant type | commercial, gcc-high, custom |
SP_SESSION_PREFIX |
Session ID prefix | sharepoint |
SP_RENDER_OPTIONS |
API options | 5691143 |
Environment Variable Overrides
Environment variables override .config values if set:
export SP_TENANT_URL="https://other-tenant.sharepoint.com"
bash scripts/list-files.sh
Tenant Types
The provision wizard supports:
- Commercial (
.sharepoint.com) - Standard Microsoft 365 - GCC High (
.sharepoint.us) - US Government/Defense - Custom - Manual URL entry
See references/tenant-types.md for complete details.
Re-provisioning
To change tenant or re-authenticate:
# Run provision wizard again
bash scripts/provision-profile.sh
# It will detect existing profile and prompt to overwrite
Manual Configuration
Advanced users can edit .config directly:
# Edit configuration
vi <skill-dir>/.config
# Test
bash scripts/session-manager.sh status
Troubleshooting
Profile Lock Error
# Cleanup automatically handled by session-manager
bash scripts/session-manager.sh cleanup
401 Unauthorized
- Profile authentication expired → Re-authenticate manually
- Wrong tenant URL → Verify
SP_TENANT_URL - Tenant type mismatch → Check
.comvs.us
CAML Query Syntax Error
- XML must be well-formed
- Field names are case-sensitive
- Use
_x0020_for spaces in field names (e.g.,File_x0020_Type)
Rate Limiting / 429 Errors
SharePoint throttles aggressive requests:
- Add delays between requests (500ms-1s)
- Batch operations where possible
- Use
RenderListDataAsStreaminstead of individual file queries
See references/troubleshooting.md for comprehensive solutions.
API Discovery
Use HAR capture to find new endpoints:
# Start capture
agent-browser --session "$SESSION" network har start
# Navigate to SharePoint UI, perform actions
agent-browser --session "$SESSION" goto "$SP_TENANT_URL/Documents"
agent-browser --session "$SESSION" wait --load networkidle
# Stop and analyze
agent-browser --session "$SESSION" network har stop /tmp/sharepoint.har
jq '.log.entries[] | select(.request.url | contains("_api")) | {url: .request.url, method: .request.method}' /tmp/sharepoint.har
Or use discover-api.sh for automated workflow.
Learn More
- Authentication & profiles:
references/authentication.md - Complete API reference:
references/api-reference.md - Troubleshooting guide:
references/troubleshooting.md - Tenant type differences:
references/tenant-types.md - Microsoft SharePoint REST API: https://learn.microsoft.com/en-us/sharepoint/dev/sp-add-ins/working-with-lists-and-list-items-with-rest