Revenue Tracking
Mission Control's revenue tracking system aggregates earnings across 5 revenue sources toward a $25M annual goal. Data flows from automated collectors to a real-time dashboard display.
System Architecture
Data Collection
Collector Script
Location: /Users/aurora/.openclaw/workspace/scripts/revenue_collector.py
Schedule: Daily at 6am CT via cron
Manual run: cd /Users/aurora/.openclaw/workspace && python3 scripts/revenue_collector.py
The collector:
- Fetches data from all 5 sources
- Calculates YTD totals, last 30 days, and projected annual
- Posts snapshot to Convex database
- Logs detailed results for debugging
Data Flow
Revenue Sources → Collector Script → Convex Snapshot → Dashboard DisplayRevenue Sources
1. Close CRM (Sponsorship Deals)
Purpose: Won sponsorship opportunities
API: GET https://api.close.com/api/v1/opportunity/
Credentials: .secrets/close_api_key.txt
Migration: Switched from Copper to Close on 2026-03-12/13
Query parameters:
status_type=won— only closed dealsdate_won__gte=2026-01-01— YTD filterdate_won__lte=today— current date
Data extracted:
- Field:
value(in cents, divided by 100 for USD) - Pagination:
_skipparameter withhas_moreflag - Authentication: HTTP Basic (API key as username, empty password)
2. Impact (Affiliate Network)
Purpose: Affiliate network earnings across all campaigns
API: GET https://api.impact.com/Mediapartners/{account_sid}/Reports/partner_performance_by_day
Credentials: .secrets/impact_account_sid.txt, .secrets/impact_api_key.txt
Important: Uses the Reports endpoint, not /Actions. The Actions endpoint only returns pending actions (~$83K), while Reports returns the complete picture (~$454K).
Query parameters:
START_DATE=2026-01-01(YYYY-MM-DD format required)END_DATE=todayPageSize=1000
Data extracted:
- Field:
Total_Cost(includes action earnings + bonuses) - Date format: Strict
YYYY-MM-DD(other formats rejected with 400 error)
3. RedVentures
Purpose: Commission from RV Media Network
API: OAuth2 + GET https://reporting-api.rvmedianetwork.com/overview
Credentials: .secrets/redventures_client_id.txt, .secrets/redventures_api_key.txt, .secrets/redventures_property_id.txt
Authentication flow:
- POST client credentials → bearer token
- GET overview data with token
Limitations:
- Max 31-day window per API call
- Collector makes multiple calls to cover full YTD period
Data extracted:
- Field:
commissionfromoverviewReporting.page[]
4. AdsByMoney (CPC/Publisher Earnings)
Purpose: YTD publisher earnings from AdsByMoney campaigns
Method: Automated scraping with session authentication
Credentials: .secrets/adsbymoney_creds.json
Scraping process:
GET /sign_in→ extract CSRF token from meta tagPOSTcredentials → establish session cookieGET /admin/publisher_campaigns?start_date=2026-01-01&end_date=TODAY&date_range_index=10→ set YTD rangeGET /admin/publisher_overviews?pubid=418&status=active→ fetch earnings JSON- Filter by Unix timestamp to current year, sum totals
Date range indices:
10— custom date range (uses start_date/end_date params)9— last 12 months (ignores start/end params)6— current month7— last month
Fallback: If scraping fails, reads data/revenue/adsbymoney_manual.json
5. MSN (Manual Monthly Revenue)
Purpose: Manual monthly revenue entered by Apple
Storage: data/revenue/msn_monthly.json
Format: {"2026-01": 32250.00, "2026-02": ...}
Update process:
revenue-manual-check-incron fires on the 21st of each month- Asks Apple for MSN + AdsByMoney numbers via message
- Ari logs both values and reruns collector
- Dashboard shows $0 until first report around the 21st
No API: Fully manual entry system
Data Storage
Convex Database
Table: revenue_snapshots
Schema:
typescript
{
snapshotDate: string, // "2026-02-19"
totalYtdUsd: number, // Sum of all sources
projectedAnnualUsd: number, // (YTD_total / days_elapsed) * 365
last30dUsd: number, // Last 30 days across sources
sources: {
close: number | null, // (renamed from 'copper' on 2026-03-13)
impact: number | null,
redventures: number | null,
adsbymoney: number | null,
msn: number,
},
createdAt: number, // Date.now()
}Convex Endpoints
- Write:
POST {CONVEX_SITE_URL}/revenue/snapshot - Read:
GET {CONVEX_SITE_URL}/revenue/latest(used by dashboard) - Functions:
revenue.ts→saveSnapshotmutation +getLatestquery
Dashboard Display
Progress Bar
- Goal: $25M annually
- Calculation:
(totalYtdUsd / 25000000) * 100 - Visual: Green progress bar with percentage
Source Pills
Individual pills showing contribution by source:
- Close CRM (Won): $XXX,XXX
- Impact: $XXX,XXX
- RedVentures: $XXX,XXX
- AdsByMoney: $XXX,XXX
- MSN: $XXX,XXX
Key Metrics
- YTD Total: Current year earnings
- Last 30 Days: Rolling 30-day total
- Projected Annual:
(YTD_total / days_elapsed) * 365
Active Crons
| Cron | Schedule | Purpose |
|---|---|---|
revenue-collector | 6am CT daily | Run collector script, update Convex |
revenue-manual-check-in | 9am on the 21st | Request MSN + AdsByMoney from Apple |
Troubleshooting
If Numbers Look Wrong
Run collector manually:
bashcd /Users/aurora/.openclaw/workspace python3 scripts/revenue_collector.pyCheck source-specific issues:
- AdsByMoney: Verify date range setting (should be YTD, not last 3 days)
- Impact: Confirm using
partner_performance_by_day+Total_Cost, not/Actions+Payout - Close: Check date format is
M/D/YYYYas expected - RedVentures: May need additional 31-day windows as year progresses
Review logs: Each source logs what it found for debugging
Migration Notes
Close CRM Migration (2026-03-12/13):
- Migrated from Copper to Close API
- Convex key renamed from
sources.coppertosources.close - Dashboard API route may still reference
sources.copperfor compatibility - Live test confirmed 67 YTD deals working correctly
Data Validation
The collector outputs detailed logs showing:
- Number of records found per source
- Dollar amounts calculated
- Any errors or warnings
- Final totals and projections
Example output:
Close CRM (Won): 67 deals → $XXX,XXX USD
Impact (Performance by Day): 50 days → $454,893.42 USD YTD
RedVentures: $3,368.54 USD YTD
AdsByMoney (manual): $31,854.33 USD YTD (updated 2026-02-19)
MSN: YTD total 32250.00 USD
Totals — YTD: $X,XXX,XXX | Last 30d: $XXX,XXX | Projected: $X.XM
Snapshot written: 200