Office 365 Management Activity API Integration
6 minute read
Overview
The Office 365 Management Activity API provides comprehensive audit and activity data from Microsoft 365 services including Exchange, SharePoint, Azure Active Directory, Teams, Power BI, and other workloads. The API uses OAuth2 client credentials flow and a content blob retrieval pattern where you query for available content, then automatically fetch individual content blobs.
Prerequisites & Setup
Before configuring Edge Delta, complete these steps in Microsoft Azure:
1. Enable Unified Audit Logging
Unified audit logging must be enabled before the API returns data:
- Navigate to Microsoft Purview compliance portal
- Go to Audit > Search
- If prompted, click “Start recording user and admin activity”
- Wait up to 12 hours for content to become available
PowerShell method:
Connect-ExchangeOnline
Set-AdminAuditLogConfig -UnifiedAuditLogIngestionEnabled $true
2. Register Azure AD Application
- Go to Azure Active Directory > App registrations > New registration
- Name: “EdgeDelta O365 Management API”
- Account type: “Accounts in this organizational directory only”
- Click Register (no redirect URI needed)
3. Configure API Permissions
Add Office 365 Management APIs application permissions (not Microsoft Graph):
- Go to API permissions > Add a permission
- Select APIs my organization uses > Search “Office 365 Management APIs”
- Choose Application permissions
- Add required permissions:
ActivityFeed.Read
(required for all content types)ActivityFeed.ReadDlp
(required only for DLP.All)
- Click “Grant admin consent for [tenant]”
4. Create Client Secret
- Navigate to Certificates & secrets > Client secrets > New client secret
- Description: “EdgeDelta Integration”
- Expiration: 12-24 months (recommended)
- Click Add and immediately copy the secret value
5. Collect Configuration Values
From your Azure AD application Overview page:
- Tenant ID: Directory (tenant) ID
- Client ID: Application (client) ID
- Client Secret: Value copied in step 4
- Publisher Identifier: Use your Tenant ID
6. Start Content Subscriptions
Start subscriptions for each content type you want to monitor (one-time setup):
Bash (Linux/Mac):
# Get OAuth token first
TOKEN=$(curl -X POST "https://login.microsoftonline.com/{TENANT_ID}/oauth2/v2.0/token" \
-d "client_id={CLIENT_ID}&client_secret={CLIENT_SECRET}&scope=https://manage.office.com/.default&grant_type=client_credentials" \
| jq -r '.access_token')
# Start subscriptions
for contentType in "Audit.Exchange" "Audit.SharePoint" "Audit.AzureActiveDirectory" "Audit.General" "DLP.All"
do
curl -X POST "https://manage.office.com/api/v1.0/{TENANT_ID}/activity/feed/subscriptions/start?contentType=${contentType}&PublisherIdentifier={TENANT_ID}" \
-H "Authorization: Bearer ${TOKEN}"
done
PowerShell (Windows):
# Get OAuth token first
$body = @{
client_id = "{CLIENT_ID}"
client_secret = "{CLIENT_SECRET}"
scope = "https://manage.office.com/.default"
grant_type = "client_credentials"
}
$tokenResponse = Invoke-RestMethod -Uri "https://login.microsoftonline.com/{TENANT_ID}/oauth2/v2.0/token" `
-Method POST `
-Body $body
$token = $tokenResponse.access_token
# Start subscriptions
$contentTypes = @("Audit.Exchange", "Audit.SharePoint", "Audit.AzureActiveDirectory", "Audit.General", "DLP.All")
foreach ($contentType in $contentTypes) {
Invoke-RestMethod -Uri "https://manage.office.com/api/v1.0/{TENANT_ID}/activity/feed/subscriptions/start?contentType=$contentType&PublisherIdentifier={TENANT_ID}" `
-Method POST `
-Headers @{Authorization = "Bearer $token"}
Write-Host "Started subscription for $contentType"
}
Subscriptions persist indefinitely; you only need to start them once.
Available Content Types
Content Type | Description | Workloads |
---|---|---|
Audit.Exchange | Email and mailbox activities | Exchange Online, Exchange Admin |
Audit.SharePoint | File and site operations | SharePoint Online, OneDrive |
Audit.AzureActiveDirectory | Identity and access events | Azure AD authentication, user management |
Audit.General | All other Microsoft 365 services | Teams, Power BI, Dynamics 365, Planner, Forms, Copilot, Viva |
DLP.All | Data loss prevention events | DLP policies across all services |
Configuration Examples
Exchange Audit Logs
Complete configuration for Exchange email and mailbox activities:
nodes:
- name: o365_exchange_audits
type: http_pull_input
endpoint: https://manage.office.com/api/v1.0/YOUR_TENANT_ID/activity/feed/subscriptions/content
method: GET
pull_interval: 5m
# OAuth2 Client Credentials Authentication
authorization:
strategy: oauth_client_credentials
client_credentials:
token_url: https://login.microsoftonline.com/YOUR_TENANT_ID/oauth2/v2.0/token
client_id: YOUR_CLIENT_ID
client_secret: YOUR_CLIENT_SECRET
scopes:
- https://manage.office.com/.default
header_templates:
- header: Authorization
value: Bearer $ACCESS_TOKEN
# Content type and publisher identifier
parameters:
- name: contentType
value: Audit.Exchange
- name: PublisherIdentifier
value: YOUR_TENANT_ID
# Time window: 6 minutes lookback, ending 1 minute ago
parameter_expressions:
- name: startTime
value_expression: FormatTime(Now() - Duration("6m"), "%Y-%m-%dT%H:%M:%SZ")
- name: endTime
value_expression: FormatTime(Now() - Duration("1m"), "%Y-%m-%dT%H:%M:%SZ")
# Automatic content blob pagination
pagination:
url_json_path: contentUri
response_format: json
max_parallel: 3
inherit_auth: true
error_strategy: continue
Other Content Types
For SharePoint, Azure AD, General, and DLP content types, use the same configuration and change only the contentType
parameter:
# SharePoint
parameters:
- name: contentType
value: Audit.SharePoint
# Azure Active Directory
parameters:
- name: contentType
value: Audit.AzureActiveDirectory
# General (Teams, Power BI, etc.)
parameters:
- name: contentType
value: Audit.General
# Data Loss Prevention
parameters:
- name: contentType
value: DLP.All
All other configuration remains identical across content types.
Using Environment Variables
For production deployments, use environment variables:
nodes:
- name: o365_exchange_audits
type: http_pull_input
endpoint_expression: Concat(["https://manage.office.com/api/v1.0/", EDXEnv("AZURE_TENANT_ID", ""), "/activity/feed/subscriptions/content"], "")
method: GET
pull_interval: 5m
authorization:
strategy: oauth_client_credentials
client_credentials:
token_url: https://login.microsoftonline.com/YOUR_TENANT_ID/oauth2/v2.0/token
client_id: YOUR_CLIENT_ID
client_secret: YOUR_CLIENT_SECRET
scopes:
- https://manage.office.com/.default
header_templates:
- header: Authorization
value: Bearer $ACCESS_TOKEN
parameters:
- name: contentType
value: Audit.Exchange
parameter_expressions:
- name: PublisherIdentifier
value_expression: EDXEnv("PUBLISHER_IDENTIFIER", "")
- name: startTime
value_expression: FormatTime(Now() - Duration("6m"), "%Y-%m-%dT%H:%M:%SZ")
- name: endTime
value_expression: FormatTime(Now() - Duration("1m"), "%Y-%m-%dT%H:%M:%SZ")
pagination:
url_json_path: contentUri
response_format: json
max_parallel: 3
inherit_auth: true
error_strategy: continue
How Content Blob Pagination Works
The Office 365 Management Activity API uses a two-step retrieval pattern:
Step 1 - List Content Response:
[
{
"contentUri": "https://manage.office.com/.../content-blob-1",
"contentId": "id-1",
"contentType": "Audit.Exchange",
"contentCreated": "2024-01-01T10:00:00Z"
},
{
"contentUri": "https://manage.office.com/.../content-blob-2",
"contentId": "id-2",
"contentType": "Audit.Exchange",
"contentCreated": "2024-01-01T10:05:00Z"
}
]
Step 2 - Automatic Blob Retrieval:
url_json_path: contentUri
extracts all content URLs from the arraymax_parallel: 3
fetches up to 3 blobs concurrentlyinherit_auth: true
uses the same OAuth token for blob requestserror_strategy: continue
processes remaining blobs if one fails
Time Windows and Rate Limiting
Recommended Configuration:
- Pull interval: 5 minutes
- Lookback window: 6 minutes (ending 1 minute ago)
- Parallel blobs: 3
Why end 1 minute ago? The API may have processing delays. The 1-minute lag ensures better data completeness.
Rate Limits:
- Per-application and per-tenant limits vary by license tier
- 5-minute intervals respect typical rate limits
- If you receive HTTP 429 responses, increase
pull_interval
to 10-15 minutes
Troubleshooting
Error | Cause | Solution |
---|---|---|
401 Unauthorized | Invalid credentials or token | Verify client ID, secret, and tenant ID are correct |
403 Forbidden | Missing permissions | Ensure ActivityFeed.Read permission granted with admin consent |
400 Bad Request | Invalid parameters | Check time format (ISO 8601) and contentType value |
429 Too Many Requests | Rate limit exceeded | Increase pull_interval or reduce max_parallel |
Empty results | No data available | Check unified audit logging is enabled; wait up to 12 hours for new tenants |
Subscription not found | Content subscription not started | Run subscription start commands from Prerequisites section |
Common Issues:
- No content blobs: Ensure subscriptions are started (step 6 in Prerequisites)
- Missing permissions: Verify you added permissions to “Office 365 Management APIs”, not “Microsoft Graph”
- Expired secrets: Rotate client secrets every 12-24 months
- Time range errors: Maximum window is 24 hours; content older than 7 days may be unavailable
API Reference
Official Documentation:
- Office 365 Management APIs Overview
- Management Activity API Reference
- Activity API Schema
- Troubleshooting Guide
Sample Audit Logs
Exchange Audit Log:
{
"CreationTime": "2024-01-01T10:00:00",
"Operation": "SendAs",
"Workload": "Exchange",
"UserId": "user@contoso.com",
"ClientIP": "192.168.1.100",
"ResultStatus": "Success",
"MailboxOwnerUPN": "mailbox@contoso.com",
"Item": {
"Subject": "Monthly Report",
"InternetMessageId": "<message-id@contoso.com>"
}
}
SharePoint Audit Log:
{
"CreationTime": "2024-01-01T10:05:00",
"Operation": "FileAccessed",
"Workload": "SharePoint",
"UserId": "user@contoso.com",
"ObjectId": "https://contoso.sharepoint.com/sites/team/Documents/report.docx",
"SourceFileName": "report.docx",
"ItemType": "File"
}
Azure AD Audit Log:
{
"CreationTime": "2024-01-01T10:10:00",
"Operation": "UserLoggedIn",
"Workload": "AzureActiveDirectory",
"UserId": "user@contoso.com",
"ResultStatus": "Success",
"AzureActiveDirectoryEventType": 1,
"ExtendedProperties": [
{
"Name": "UserAgent",
"Value": "Mozilla/5.0 (Windows NT 10.0) Chrome/120.0"
}
]
}
Comparison with Microsoft Graph API
Feature | Office 365 Management API | Microsoft Graph API |
---|---|---|
Purpose | Comprehensive audit logs | Real-time directory queries |
Authentication | ActivityFeed.Read permission | AuditLog.Read.All permission |
Pagination | Content blob pattern (contentUri ) | OData @odata/.nextLink |
Workloads | All M365: Exchange, SharePoint, Teams, Power BI, DLP | Primarily Azure AD, Security, Compliance |
Best For | Compliance monitoring, SIEM integration | Real-time security alerts, directory management |
Many organizations use both APIs for comprehensive Microsoft 365 monitoring.