Database
API Routes
Every server endpoint we expose, what it does, and who can call it.
Auth & integrations
| Method | Path | Purpose |
|---|---|---|
| GET | /api/auth/google | Initiates Google OAuth. Redirects to Google consent screen with the full scope set. |
| GET | /api/auth/google/callback | OAuth callback. Exchanges code for tokens, writes to integrations table. |
| GET | /api/auth/callback/google | Alias for the above (legacy path). |
| POST | /api/auth/invite-client | Admin-only. Creates a Supabase user with role=client and sends magic link. |
| GET | /api/google/properties | Lists every GA4 property the agency token can access. Used by admin client edit form. |
| GET | /api/google/locations | Lists every GBP location the agency token can manage. |
Metric routes
All metric routes accept start_date and end_date unless marked otherwise.
| Path | Required params | Source |
|---|---|---|
| /api/metrics/ga4 | property_id | Google Analytics Data API |
| /api/metrics/ga4/traffic | property_id | GA4 — daily users series |
| /api/metrics/ga4/pages | property_id | GA4 — top pages |
| /api/metrics/ga4/acquisition | property_id | GA4 — sessions by channel |
| /api/metrics/gsc | site_url | Search Console |
| /api/metrics/gsc/keywords | site_url | Search Console — top 10 queries |
| /api/metrics/gbp | location_id | GBP Performance API |
| /api/metrics/gbp/reviews | place_id (no date range) | Places API v1 |
| /api/metrics/youtube | channel_id (no date range) | YouTube Data API v3 |
| /api/metrics/pagespeed | url (no date range) | PageSpeed Insights v5 |
| /api/metrics/google-ads | customer_id | Google Ads API |
| /api/metrics/meta-ads | account_id | Meta Marketing API |
| /api/metrics/ghl | location_id, client_id | GoHighLevel |
| /api/metrics/n8n | client_id (no date range) | n8n live pull (conversations) |
| /api/metrics/seo-rankings | domain (no date range) | DataForSEO via cache |
| /api/metrics/sheets-rfms | sheet_id | Google Sheets API |
| POST /api/metrics/external | bearer token | n8n push |
| /api/metrics/external/[clientId] | clientId in path | Read external_metrics cache |
Portal data
| Method | Path | Purpose |
|---|---|---|
| GET | /api/portal/[clientId] | Read all editable portal sections for a client. |
| PUT | /api/portal/[clientId] | Admin-only. Update one section (body: { section, data }). |
Admin actions
| Method | Path | Purpose |
|---|---|---|
| POST | /api/admin/create-client-user | Admin-only. Manually create a Supabase user bound to a client (alternative to invite flow). |
| POST | /api/submit-request | Authenticated. Records a Submit Request entry. Currently triggers a Slack notification. |
Test routes
Unauthenticated, hardcoded to Denver. Used for debugging integrations without going through the UI:
/api/test/youtube/api/test/gbp-reviews/api/test/google-ads/api/test/meta-ads/api/test/meta-insights/api/test/n8n
Production hygiene
Test routes should be removed or moved behind a feature flag before a production deployment that exposes them externally. They are useful in dev — risky in prod.
Standard response shape
Most metric routes return:
{
connected: true | false,
metrics: {
metricName: { value: number, change: number, formatted: string }
},
...auxiliaryFields
}On failure they return { error: 'message' } with HTTP 400/403/500. The dashboard never throws on error — the affected card just stays empty (and is auto-hidden).