This Python script demonstrates how to create a meeting on behalf of a subuser in a Webex organization using Webex Service App credentials. It showcases the power of impersonation functionality available in Webex Service Apps, allowing administrators to schedule meetings for other users in their organization.
✅ Meeting Creation: Create meetings on behalf of organization users
✅ Token Management: Automatic token refresh when access tokens expire
✅ Error Handling: Robust error handling with 401 retry logic
✅ Simple Setup: Minimal configuration required
✅ Production Ready: Includes best practices for token storage considerations
- Administrative Tools: Build tools for admins to schedule meetings for team members
- Automated Scheduling: Create meetings programmatically for events or workflows
- Bulk Operations: Schedule multiple meetings across different users
- Integration: Integrate with existing systems to provide meeting scheduling capabilities
- Prerequisites
- Installation
- Configuration
- Usage
- Code Structure
- API Reference
- Error Handling
- Best Practices
- Troubleshooting
- Contributing
- License
- Python 3.6+ - Download Python
- pip - Python package installer (usually comes with Python)
- Webex Developer Account - Sign up for free
- Webex Service App - Registered and authorized by an organization admin
Your Webex Service App must be registered with the following scopes:
meeting:admin_schedule_write
- Required for impersonation functionality (scheduling meetings on behalf of other users)
-
Clone or download this repository:
git clone <repository-url> cd simple_service_app
-
Install dependencies:
pip install requests
Note: Other dependencies (
json
,os
,datetime
,webbrowser
) are part of the Python Standard Library and don't need separate installation.
-
Register a Service App:
- Visit Webex Developer Portal
- Create a new Service App
- Select the required scope:
meeting:admin_schedule_write
- Note down your Client ID and Client Secret
-
Authorize the Service App:
- An organization admin must authorize your Service App
- This will provide you with Access Token and Refresh Token
Edit the serviceapp.py
file and replace the placeholder values:
# Replace these values with your actual Service App credentials
clientID = "YOUR CLIENT ID HERE" # Your Service App Client ID
secretID = "YOUR CLIENT SECRET HERE" # Your Service App Client Secret
access_token = 'ACCESS TOKEN POST ADMIN AUTHORIZATION' # Initial access token
refresh_token = 'REFRESH TOKEN POST ADMIN AUTHORIZATION' # Initial refresh token
Replace the placeholder email with the actual subuser's email:
'hostEmail': 'A sub users email' # Replace with actual user email
Run the script using Python:
python serviceapp.py
- Meeting Creation: The script creates a meeting scheduled for 24 hours from now, lasting 1 hour
- Token Validation: If the access token is valid, the meeting is created successfully
- Automatic Refresh: If the access token is expired (401 error), the script automatically refreshes the tokens and retries
- Success Response: On success, meeting details are displayed in the console
Successful Meeting Creation:
statusCode: 200
{
'id': 'meeting_id_here',
'title': 'Example Meeting Title',
'start': '2024-01-15T10:00:00Z',
'end': '2024-01-15T11:00:00Z',
'hostEmail': 'user@example.com',
'webLink': 'https://meet.webex.com/meet/...',
'meetingNumber': '123456789'
}
Token Refresh (when needed):
function : get_token_refresh()
Token returned in refresh result : eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9...
Refresh Token returned in refresh result : eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9...
graph TB
A[Script Start] --> B[create_meeting()]
B --> C{Access Token Valid?}
C -->|Yes| D[Meeting Created Successfully]
C -->|No 401| E[get_tokens_refresh()]
E --> F[Update Tokens]
F --> G[Retry create_meeting()]
G --> D
Creates a meeting on behalf of a subuser in the Webex organization.
Features:
- Schedules meeting 24 hours from current time
- Meeting duration: 1 hour
- Uses impersonation via
hostEmail
parameter - Returns response object with meeting details
Parameters:
- Uses global variables for tokens and configuration
- Meeting details are hardcoded but can be customized
Response:
- 200: Meeting created successfully
- 401: Access token expired (triggers refresh)
- Other errors: Various API errors
Refreshes the access token using the refresh token when a 401 error occurs.
Process:
- Makes POST request to
/v1/access_token
endpoint - Uses refresh token to get new access and refresh tokens
- Returns new tokens for immediate use
Parameters:
grant_type
: "refresh_token"client_id
: Service App Client IDclient_secret
: Service App Client Secretrefresh_token
: Current refresh token
Returns:
- New access token
- New refresh token
Variable | Description | Example |
---|---|---|
clientID |
Service App Client ID | C1234567890abcdef... |
secretID |
Service App Client Secret | secret123... |
access_token |
Current access token | Bearer eyJ0eXAiOiJKV1Q... |
refresh_token |
Current refresh token | eyJ0eXAiOiJKV1QiLCJh... |
- Endpoint:
POST https://webexapis.com/v1/meetings
- Documentation: Webex Meetings API
- Headers:
Authorization: Bearer {access_token}
Content-Type: application/json
Request Body:
{
"title": "Example Meeting Title",
"start": "2024-01-15T10:00:00Z",
"end": "2024-01-15T11:00:00Z",
"hostEmail": "user@example.com"
}
- Endpoint:
POST https://webexapis.com/v1/access_token
- Headers:
Accept: application/json
Content-Type: application/x-www-form-urlencoded
Request Body:
grant_type=refresh_token&client_id={clientID}&client_secret={secretID}&refresh_token={refresh_token}
Parameter | Type | Required | Description |
---|---|---|---|
title |
String | Yes | Meeting title (max 128 characters) |
start |
String | Yes | Meeting start time (ISO 8601 format) |
end |
String | Yes | Meeting end time (ISO 8601 format) |
hostEmail |
String | Yes | Email of the user on whose behalf the meeting is created |
Code | Description | Action |
---|---|---|
200 | Success | Meeting created successfully |
401 | Unauthorized | Access token expired - refresh and retry |
400 | Bad Request | Check request parameters |
403 | Forbidden | Insufficient permissions or invalid host email |
429 | Rate Limited | Implement retry with backoff |
The script includes automatic error handling for common scenarios:
-
Token Expiration (401):
- Automatically refreshes tokens
- Retries the meeting creation
- No manual intervention required
-
API Errors:
- Displays error code and message
- Provides debugging information
You can extend the error handling by modifying the create_meeting()
function:
def create_meeting():
# ... existing code ...
if response.status_code == 200:
print('Meeting created successfully!')
meeting_data = response.json()
print(f"Meeting ID: {meeting_data.get('id')}")
print(f"Meeting Link: {meeting_data.get('webLink')}")
elif response.status_code == 400:
print('Bad Request: Check your meeting parameters')
elif response.status_code == 403:
print('Forbidden: Check host email or permissions')
elif response.status_code == 429:
print('Rate Limited: Please wait before retrying')
else:
print(f'Error: {response.status_code} - {response.text}')
return response
-
Token Storage:
# ❌ Don't store tokens in source code (production) access_token = 'hardcoded_token' # ✅ Use environment variables (production) import os access_token = os.getenv('WEBEX_ACCESS_TOKEN')
-
Environment Variables:
# Create .env file WEBEX_CLIENT_ID=your_client_id WEBEX_CLIENT_SECRET=your_client_secret WEBEX_ACCESS_TOKEN=your_access_token WEBEX_REFRESH_TOKEN=your_refresh_token
-
Token Refresh:
- Store new tokens after each refresh
- Implement proper token persistence
- Use database or secure storage for production
-
Configuration Management:
import configparser config = configparser.ConfigParser() config.read('config.ini') clientID = config['webex']['client_id'] secretID = config['webex']['client_secret']
-
Error Logging:
import logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) def create_meeting(): try: # ... meeting creation logic ... logger.info("Meeting created successfully") except Exception as e: logger.error(f"Failed to create meeting: {e}")
-
Input Validation:
def validate_email(email): import re pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' return re.match(pattern, email) is not None
- Token Persistence: Store tokens in a database or secure key vault
- Rate Limiting: Implement retry logic with exponential backoff
- Monitoring: Add logging and monitoring for production use
- Configuration: Use environment variables or config files
- Error Handling: Implement comprehensive error handling and reporting
Problem: Access token is expired or invalid.
Solution:
- The script automatically handles this by refreshing tokens
- Ensure your refresh token is valid
- Check that your Service App is properly authorized
Problem: Insufficient permissions or invalid host email.
Solutions:
- Verify the
hostEmail
belongs to your organization - Ensure your Service App has
meeting:admin_schedule_write
scope - Check that the Service App is authorized by an org admin
Problem: Invalid request parameters.
Solutions:
- Check meeting start/end times are in ISO 8601 format
- Ensure meeting title is not longer than 128 characters
- Verify all required parameters are provided
Problem: Module not found errors.
Solutions:
- Install required dependencies:
pip install requests
- Ensure Python 3.6+ is installed
- Check that all imports are correctly spelled
Add debug information to troubleshoot issues:
import logging
logging.basicConfig(level=logging.DEBUG)
# Add before API calls
print(f"Using access token: {access_token[:20]}...")
print(f"Meeting data: {json.dumps(body, indent=2)}")
To test the token refresh functionality, uncomment this line in the script:
# Uncomment this line to force a 401 error and test token refresh
access_token += 'invalid'
We welcome contributions to improve this sample code!
- Fork the repository
- Create a feature branch:
git checkout -b feature/your-improvement
- Make your changes:
- Follow Python best practices
- Add comments for complex logic
- Test your changes thoroughly
- Submit a pull request
- Code Style: Follow PEP 8 Python style guidelines
- Documentation: Update README for new features
- Testing: Test your changes with valid Webex credentials
- Comments: Add meaningful comments for complex logic
- Add command-line argument parsing
- Implement configuration file support
- Add bulk meeting creation functionality
- Create a web interface
- Add meeting templates
- Implement scheduled meeting creation
This project is licensed under the Cisco Sample Code License.
- ✅ Permitted: Copy, modify, and redistribute for use with Cisco products
- ❌ Prohibited: Use independent of Cisco products or to compete with Cisco
- ℹ️ Warranty: Provided "as is" without warranty
- ℹ️ Support: Not supported by Cisco TAC
See the LICENSE file for full license terms.
For issues and questions:
- Check the Troubleshooting section
- Review Webex Developer Documentation
- Visit the Webex Developer Community
Happy Coding! 🚀