A Python tool to identify which applications are creating Microsoft Graph subscriptions in your tenant. This tool helps resolve subscription quota issues and provides visibility into subscription ownership across all resources.
** PowerShell Version Available!** If you prefer PowerShell, see
Get-GraphSubscriptions.ps1- a standalone script with all functionality in a single file. Documentation
When managing Microsoft Graph subscriptions (webhooks), you may encounter:
- Quota limits on resources like Teams callTranscript
- "Tenant has reached its maximum number of subscriptions" errors
- Difficulty identifying which applications own which subscriptions
The Microsoft Graph subscriptions API has limitations:
- Only returns paginated results
- Doesn't support OData query parameters for filtering
- Doesn't directly show app ownership details
This tool solves these problems by providing complete visibility into all subscriptions and their owning applications.
- Delegated Authentication: Uses interactive browser login with Global Admin account
- Full Pagination Support: Automatically retrieves all subscription pages
- Application Mapping: Resolves
applicationIdto app display names - Complete Coverage: Lists all Graph subscriptions across all resources
- Transcript Tracking: Separately identifies callTranscript subscriptions
- Detailed Reporting: Outputs both console and JSON reports
- Token Caching: Reuses cached tokens for efficiency
-
Azure AD App Registration:
- Create an app registration in Azure Portal
- Set as Public client (for delegated auth)
- Add Redirect URI:
http://localhost(Mobile and desktop applications) - Grant API Permissions:
Subscription.Read.All(Delegated)Application.Read.All(Delegated) - for app name resolution
- Have a Global Admin account to sign in with
-
Python 3.8+ installed
-
Clone this repository:
git clone https://github.com/dylanstetts/listGraphWebhooks.git cd listGraphWebhooks -
Install dependencies:
pip install -r requirements.txt
-
Configure environment variables:
-
Configure environment variables:
- Copy
.env.exampleto.env - Edit
.envand fill in your values:
CLIENT_ID=your-app-registration-client-id TENANT_ID=your-tenant-id - Copy
-
Go to Azure Portal → Azure Active Directory → App registrations → New registration
-
Configure the app:
- Name: Graph Subscription Analyzer
- Supported account types: Accounts in this organizational directory only
- Redirect URI: Select "Public client/native (mobile & desktop)" and enter
http://localhost
-
After creation, note the:
- Application (client) ID → use for
CLIENT_ID - Directory (tenant) ID → use for
TENANT_ID
- Application (client) ID → use for
-
Configure Authentication:
- Go to Authentication blade
- Under "Advanced settings" → "Allow public client flows" → Yes
-
Grant API Permissions:
- Go to API permissions blade
- Click Add a permission → Microsoft Graph → Delegated permissions
- Add:
Subscription.Read.AllApplication.Read.All
- Click Grant admin consent for your organization
Run the analyzer:
python subscription_analyzer.py- Authentication: Browser window opens for you to sign in with Global Admin account
- Fetching: Tool retrieves all subscription pages across your tenant
- Analysis: Identifies all subscriptions and separately tracks callTranscript resources
- Mapping: Resolves application IDs to display names
- Reporting: Outputs to console and JSON file
================================================================================
MICROSOFT GRAPH SUBSCRIPTION REPORT
================================================================================
Generated: 2025-12-10T16:26:00Z
Total Subscriptions: 150
CallTranscript Subscriptions: 75
Reported Subscriptions: 150
Unique Applications: 5
================================================================================
Application: Teams Recording Bot
App ID: 12345678-1234-1234-1234-123456789abc
Service Principal ID: 87654321-4321-4321-4321-cba987654321
Subscription Count: 45
Subscriptions:
• ID: sub-id-1
Resource: communications/onlineMeetings/getAllTranscripts
Change Type: created
Expires: 2025-12-11T16:26:00Z
Notification URL: https://example.com/webhook
...
The tool generates a timestamped JSON report:
- Filename:
subscription_report_YYYYMMDD_HHMMSS.json - Contains:
- Complete subscription details
- Application mappings
- Resource information
- Expiration dates
- Notification URLs
Error: "AADSTS65001: The user or administrator has not consented"
- Solution: Ensure admin consent is granted in the app registration
Error: "AADSTS7000218: The request body must contain the following parameter: 'client_assertion'"
- Solution: Enable "Allow public client flows" in app authentication settings
Error: "Insufficient privileges to complete the operation"
- Solution:
- Verify
Subscription.Read.Allis granted - Ensure you're signing in with a Global Admin account
- Grant admin consent for the permissions
- Verify
- Verify you have subscriptions in your tenant: Check manually in Graph Explorer
- Ensure the token has the correct scopes
- Display Name: Human-readable app name
- Application ID: Unique identifier for the app registration
- Service Principal ID: Instance of the app in your tenant
- Subscription Count: How many subscriptions this app created
- Resource: The Graph resource being monitored (look for
transcript)
Once you've identified the problematic apps:
- Contact app owners: Ask them to delete unnecessary subscriptions
- Delete via Graph API: Use
DELETE /subscriptions/{id}withSubscription.ReadWrite.Allpermission - Disable apps: If apps are no longer needed, disable them in Azure AD
- Subscriptions: Microsoft Graph Subscriptions API
- Service Principals: Microsoft Graph Service Principals API
GitHub: https://github.com/dylanstetts/listGraphWebhooks
MIT License - see LICENSE file for details.
Contributions are welcome! Feel free to submit issues or pull requests for:
- Export to CSV format
- Filter by resource type or expiration date
- Automatic cleanup functionality
- Support for application permissions (unattended scenarios)
- Additional reporting formats
Created by Dylan Stetts to help Microsoft 365 administrators manage Graph subscription quotas.
- Support for application permissions (unattended scenarios)