🚀 Automate your meeting-based invoicing workflow with Google Calendar and Stripe integration
Transform your consulting workflow by automatically identifying meetings with Stripe customers, tracking invoicing status, and creating detailed draft invoices with custom synopses.
- Quick Start
- Key Features
- Installation
- Setup Guide
- Basic Usage
- Interactive Workflow
- Advanced Features
- Testing & Development
- Troubleshooting
- Security & Best Practices
- Contributing
Get up and running in 5 minutes:
-
Install dependencies:
pip install stripe google-auth google-auth-oauthlib google-auth-httplib2 google-api-python-client python-dateutil
-
Set your Stripe API key:
# Option A: .env file (recommended) echo "STRIPE_SECRET_KEY=sk_test_..." > .env # Option B: Environment variable export STRIPE_SECRET_KEY="sk_test_..."
-
Get Google Calendar credentials:
- Go to Google Cloud Console
- Enable Calendar API → Create OAuth credentials → Download as
credentials.json
-
Run the automation:
python invoice_automation.py
That's it! The script will guide you through Google authentication and show your meetings ready for invoicing.
- Smart Calendar Integration: Automatically fetches meetings with robust token management
- Customer Matching: Cross-references attendees with your Stripe customer list
- Duplicate Prevention: Tracks invoiced meetings to prevent double-billing
- Flexible Pricing: Different hourly rates per customer (stored in Stripe metadata)
- Visual Meeting Selection: Clear status indicators (⭕ uninvoiced, 📄 drafted, ✅ sent)
- Meeting Editing: Adjust start times and durations if actual differs from scheduled
- Custom Rate Override: Set special rates for specific meetings or update customer defaults
- Personalized Synopses: Add custom descriptions for each meeting on invoices
- Smart Token Management: Handles Google OAuth expiration with user-friendly prompts
- Comprehensive Testing: 66 tests with 75% code coverage
- Error Recovery: Graceful handling of API failures and authentication issues
- Python 3.7+
- Stripe account with API access
- Google account with Calendar API access
# Option 1: Direct installation
pip install stripe google-auth google-auth-oauthlib google-auth-httplib2 google-api-python-client python-dateutil
# Option 2: From requirements file (if available)
pip install -r requirements.txtGet your API key:
-
Copy your Secret Key (starts with
sk_test_orsk_live_) -
Configure environment variables (choose one method):
Option A: .env file (recommended)
# Create .env file in project directory echo "STRIPE_SECRET_KEY=sk_test_your_actual_key_here" > .env echo "DEFAULT_HOURLY_RATE=150.00" >> .env echo "DAYS_BACK=7" >> .env
Option B: Shell environment
export STRIPE_SECRET_KEY="sk_test_your_actual_key_here" export DEFAULT_HOURLY_RATE="150.00" export DAYS_BACK="7"
Optional: Set up customer hourly rates
- Via Stripe Dashboard: Customers → [Customer] → Edit → Add metadata:
hourly_rate=200.00 - Programmatically: Use
invoicer.set_customer_hourly_rate("cus_ABC123", 200.00)in the script
-
Enable the API:
- Go to Google Cloud Console
- Create/select a project → Enable Google Calendar API
-
Create OAuth credentials:
- Go to Credentials → Create → OAuth 2.0 Client ID
- Choose "Desktop application"
- Download the JSON file
-
Install credentials:
- Rename downloaded file to
credentials.json - Place in your script directory
- Rename downloaded file to
The script automatically loads configuration from environment variables or a .env file:
Environment Variables:
STRIPE_SECRET_KEY- Your Stripe secret API key (required)DEFAULT_HOURLY_RATE- Default hourly rate for customers without specific rates (default: 150.00)DAYS_BACK- Number of days back to check for meetings (default: 7)
Using .env file (recommended):
# .env file in project directory
STRIPE_SECRET_KEY=sk_test_your_actual_key_here
DEFAULT_HOURLY_RATE=150.00
DAYS_BACK=7Manual configuration in code:
# Edit these settings in main() function if not using .env
STRIPE_API_KEY = os.getenv('STRIPE_SECRET_KEY')
DAYS_BACK = int(os.getenv('DAYS_BACK', 7))
DEFAULT_HOURLY_RATE = float(os.getenv('DEFAULT_HOURLY_RATE', 150.00))python invoice_automation.pyWhat happens:
- Google opens browser for Calendar authentication (first time only)
- Script scans for meetings with your Stripe customers
- Shows interactive interface for meeting selection
- Guides you through synopsis entry
- Creates draft invoices in Stripe
your-project/
├── invoice_automation.py
├── credentials.json # Google Calendar API credentials
├── token.json # Auto-generated OAuth token (don't commit!)
├── .env # Environment variables (don't commit!)
└── README.md
The script displays meetings organized by customer with clear status indicators:
📧 John Smith ([email protected]) - $200/hour
------------------------------------------------------------
1. [✓] ⭕ Weekly Strategy Review
📅 2025-06-15 at 2:00 PM (1.0h) - $200.00
📊 Status: Not invoiced
2. [ ] ✅ Project Planning Meeting
📅 2025-06-17 at 10:30 AM (1.5h) - $300.00
📊 Status: Invoice sent
Status Icons:
- ⭕ Not invoiced (auto-selected for billing)
- 📄 Draft created (invoice drafted but not sent)
- ✅ Invoice sent (already invoiced and sent)
Selection Commands:
[number]- Toggle meeting selectionall- Select all uninvoiced meetingsnone- Deselect all meetingscontinue- Proceed to synopsis entry
Editing Commands:
edit [number]- Edit meeting time and durationtime [number]- Quick shortcut for editingrate [number] [amount]- Set custom rate for specific meetingsetrate [email] [amount]- Update customer's default hourly rate
Help Commands:
?- Show command helpquit- Exit program
Enter command: edit 1
📝 EDITING MEETING: Weekly Strategy Review
📅 Original: 2025-06-15 at 2:00 PM (1.0h)
Enter new values (press Enter to keep current):
Start time [2:00 PM]: 2:30 PM
Duration in hours [1.0]: 1.5
✅ Meeting updated:
📅 2025-06-15 at 2:30 PM (1.5h)
✏️ This meeting has been edited
Visual Indicators:
- ✏️ = Meeting time/duration has been edited
- 💰$X/h = Custom rate applied to meeting
After selecting meetings, you'll add custom descriptions:
📅 Weekly Strategy Review - 2025-06-15 at 2:30 PM ✏️
Duration: 1.5h
Synopsis [Weekly Strategy Review]: Discussed Q3 goals and budget planning
✓ Synopsis saved
Then review and confirm before creating invoices:
📊 SUMMARY:
Total Meetings: 2
Total Amount: $475.00
• Weekly Strategy Review ✏️
2025-06-15 at 2:30 PM (1.5h) - $300.00
• Project Planning Meeting 💰$250/h
2025-06-17 at 10:30 AM (1.0h) - $250.00
Create 2 draft invoices? (y/n): y
✅ SUCCESS: Created 2 draft invoices!
- Scans Google Calendar events in specified date range
- Matches attendees/organizers with Stripe customer emails
- Calculates duration from start/end times
- Generates unique meeting IDs (hash of customer + date + title)
- Scans existing Stripe invoices for meeting IDs in descriptions
- Prevents duplicate invoicing with persistent tracking
- Each meeting becomes a line item:
"Description - Date at Time (Duration @ Rate) [ID:abc123]"
Set rates programmatically:
invoicer = StripeCalendarInvoicer(stripe_api_key="sk_...")
invoicer.set_customer_hourly_rate("cus_ABC123", 200.00) # Premium client
invoicer.set_customer_hourly_rate("cus_DEF456", 125.00) # Standard clientThe project includes comprehensive testing with 66 tests achieving 75% code coverage.
# Install test dependencies
pip install -r test_requirements.txt
# Run all tests with coverage
python run_tests.py all --coverage
# Run specific test suites
python run_tests.py unit # Unit tests for core functions
python run_tests.py integration # Integration tests (Stripe/Google)
python run_tests.py commands # Interactive command tests
python run_tests.py e2e # End-to-end workflow tests- Authentication Logic: Token handling, expiration, refresh failures
- Display Formatting: Visual indicators, time formatting, error fallbacks
- Input Validation: Command parsing, malformed inputs, edge cases
- Core Business Logic: Meeting detection, invoice creation, rate management
- Integration Testing: Mocked Stripe and Google Calendar API interactions
- End-to-End Workflows: Complete user scenarios with error recovery
See TESTING.md for detailed testing documentation.
❌ "Google Calendar token has expired and cannot be refreshed"
- Happens after ~6 months of token inactivity
- Script prompts to remove expired token automatically
- Choose 'y' to delete
token.jsonand re-authenticate - Or manually delete
token.jsonand run script again
❌ "Failed to initialize Google Calendar service"
- Check
credentials.jsonexists and is valid - Ensure Calendar API is enabled in Google Cloud Console
- Verify OAuth credentials are for "Desktop application"
- Try downloading fresh credentials from Google Cloud
❌ "No customers found"
- Verify Stripe API key is correct and has read permissions
- Check customers in Stripe have email addresses
- Ensure you're using the right API key (test vs live)
❌ "No calendar events found"
- Check
DAYS_BACKsetting (default: 7 days) - Verify you have meetings in the specified date range
- Ensure meeting attendees match Stripe customer emails
❌ "Missing customer hourly rates"
- Script uses
DEFAULT_HOURLY_RATEfor customers without metadata - Set rates in Stripe: Customer → Edit → Metadata:
hourly_rate=200.00 - Or use
setratecommand during meeting selection
❌ "Error fetching calendar events"
- Re-authenticate by deleting
token.json - Check Google Calendar API quotas in Cloud Console
- Verify internet connection and firewall settings
❌ "Stripe API errors"
- Check API key permissions and rate limits
- Verify customer IDs are valid
- Review Stripe Dashboard for additional error details
- Never commit
credentials.jsonortoken.jsonto version control - Use environment variables for Stripe API keys
- Rotate API keys regularly and use test keys during development
- Grant minimal permissions: Script only needs Calendar read access
- Review draft invoices in Stripe before sending to customers
- Test First: Run in test environment before production use
- Backup Credentials: Keep secure backups of
credentials.json - Descriptive Meetings: Use clear meeting titles for better synopses
- Time Accuracy: Use edit feature for meetings that ran over/under scheduled time
- Rate Management: Store rates in Stripe metadata rather than hardcoding
- Regular Reviews: Check invoice drafts before sending to customers
# Add to .gitignore
credentials.json
token.json
.env- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Run tests to ensure nothing breaks (
python run_tests.py all) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
# Install dev dependencies
pip install -r test_requirements.txt
# Run tests before committing
python run_tests.py all --coverage
# Check coverage is maintained
# Target: 75%+ coverageIf you encounter issues:
- Check troubleshooting section above for common solutions
- Review logs - the script provides detailed error messages
- Verify setup - ensure API keys and credentials are correct
- Consult documentation - Stripe API and Google Calendar API
- Open an issue with detailed error logs and setup information
⚡ Happy Invoicing! This automation can save hours of manual work while ensuring accurate billing and nothing falls through the cracks.