| name | sharepoint-api |
| description | Automate SharePoint/OneDrive operations using agent-browser and SharePoint REST APIs. List files, download/upload documents, filter with CAML queries, search content, and discover new APIs via HAR capture. Works with Commercial, GCC, and GCC High tenants. Triggers include "list SharePoint files", "download from OneDrive", "upload to SharePoint", "search SharePoint documents", "SharePoint API automation", or "OneDrive for Business operations". |
| license | MIT |
| compatibility | Requires agent-browser >= 2.0. Install with `npm install -g agent-browser` or `brew install agent-browser`. Chrome/Chromium required for browser automation. |
| metadata | {"author":"Zettersten","version":"1.0","docs":"https://learn.microsoft.com/en-us/sharepoint/dev/sp-add-ins/working-with-lists-and-list-items-with-rest"} |
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
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
.config file
- 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
bash scripts/list-files.sh
bash scripts/list-files.sh --folder "Projects/2024"
bash scripts/list-files.sh --type pptx --limit 10
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:
bash scripts/session-manager.sh create
bash scripts/session-manager.sh status
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
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
/me endpoint)
- 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:
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
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',
: item.
}));
files;
Response Fields:
FileLeafRef → filename
FSObjType → "0" (file) / "1" (folder)
SMTotalSize → size in bytes (string)
Modified. → ISO-8601 timestamp
File_x0020_Type → extension (docx, xlsx, pdf, ...)
FileRef → full server-relative path
UniqueId → 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`;
const headResponse = await fetch(fileUrl, { method: 'HEAD' });
if (!headResponse.ok) {
throw new Error(`File not found: ${headResponse.status}`);
}
const response = await fetch(`${fileUrl}?download=1`);
const blob = await response.blob();
Upload Files
Use SharePoint's /_api/web/GetFolderByServerRelativeUrl() endpoint:
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
bash scripts/session-manager.sh status
bash scripts/session-manager.sh destroy
bash scripts/session-manager.sh cleanup
list-files.sh
List files and folders with filtering, pagination, and output formatting.
bash scripts/list-files.sh
bash scripts/list-files.sh --folder "Projects"
bash scripts/list-files.sh --type docx
bash scripts/list-files.sh --limit 20
bash scripts/list-files.sh --format json
bash scripts/list-files.sh --modified-after "2024-01-01"
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
bash scripts/download-file.sh "Documents/big-file.zip" --resume
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/"
bash scripts/upload-file.sh file.pdf "Documents/" --overwrite
bash scripts/upload-file.sh file.pdf "Documents/" --rename
discover-api.sh
Capture network traffic to discover new SharePoint API endpoints.
bash scripts/discover-api.sh
bash scripts/discover-api.sh --auto --output apis.json
bash scripts/discover-api.sh --replay apis.json
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:
bash scripts/provision-profile.sh
Manual Configuration
Advanced users can edit .config directly:
vi <skill-dir>/.config
bash scripts/session-manager.sh status
Troubleshooting
Profile Lock Error
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
.com vs .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
RenderListDataAsStream instead of individual file queries
See references/troubleshooting.md for comprehensive solutions.
API Discovery
Use HAR capture to find new endpoints:
agent-browser --session "$SESSION" network har start
agent-browser --session "$SESSION" goto "$SP_TENANT_URL/Documents"
agent-browser --session "$SESSION" wait --load networkidle
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