Polar
Connect your Polar.sh merchant account via OAuth to track revenue/subscription/order metrics. Multi-organization server-side aggregation.
Last updated: 2026-05-18
The Polar integration uses OAuth 2.0 + PKCE (S256) + client_secret_post flow with read-only tokens. Tokens are encrypted at rest with AES-256-GCM, and refresh tokens are single-use rotating.
Prerequisites
- Polar account + 1 or more organizations (connection works without orgs — data shows as 0)
- OAuth authorization permission (organization owner / member)
- Starter / Plus / Max plan (revenue alerts are paid features)
OAuth connection
Open account settings
Click Connect on the Polar card in /dashboard/account or /dashboard/integrations.
Polar authentication
Desktop opens a popup, mobile redirects to polar.sh login. Sign in and approve read-only permissions.
Organization auto-discovery
Opseer fetches your active organizations and stores them in metadata. New users without organizations connect with empty state.
Done
Popup closes or confirmation page appears. Connected organizations are listed in the account/integrations page.
Polar is account-level. Once connected, it works the same across all your Opseer projects. 0 organizations is OK — once you create one on polar.sh, the next Refresh will pick it up.
Requested scopes
All 9 are read-only — Opseer does not modify your Polar data.
- openid, email — account identification
- metrics:read — daily metric time series
- subscriptions:read, organizations:read — subscription/org info
- orders:read, refunds:read — orders/refunds
- products:read, customers:read — products/customers
Displayed data
/dashboard/revenue/polar fetches a single metrics API call returning daily time series + multi-organization server-side aggregation.
Core metrics (Today/Yesterday + Period summary)
- MRR (Monthly Recurring Revenue) — sum of monthly recurring revenue from active subscriptions
- Revenue / Net Revenue — gross revenue / after refunds
- Active Subscriptions — point-in-time active sub count
- New Subscriptions / Churned Subscriptions — new/expired in period
- Trial MRR — MRR from trialing subscriptions
- Average Revenue Per User (ARPU)
Polar-specific metrics (top / bottom cards)
- Cumulative Revenue — total revenue from inception (snapshot)
- Checkout Conversion — conversion rate from checkout to paid
- Orders — total payment count (new + renewals + one-time)
- Renewed Subscriptions — renewal count
- Canceled Subscriptions — cancellation intent (before expiry)
- One-time Products / Revenue — one-time product sales
Multi-organization handling
When multiple organizations exist in your Polar account, all active orgs are server-side aggregated for display (single API call).
- Auto-saved to metadata.organizations[] on connect
- Refresh auto-discovers new organizations
- Only status="active" orgs are queried (excludes created/review/blocked, etc.)
- Per-organization detail table only shown when multi-org
When orgs use different currencies (e.g. USD + EUR), aggregated values are shown without currency conversion. An amber warning banner appears at the top.
Cache policy
- 90-day sliding window — fetched only when Refresh is clicked
- Period switching uses cache JSON aggregation (zero round-trip)
- today/yesterday is realtime (Polar has no D-1 lag)
- Custom range fetches arbitrary periods outside the cache window via single API call (no cache write). Free start date, max 90-day width
Sandbox vs production
Opseer supports production only. Sandbox requires a separate OAuth client and uses a different base URL (sandbox-api.polar.sh).
Token rotation policy
- access_token: 10-day expiry
- refresh_token: single-use rotating — issued fresh on each refresh, previous immediately revoked
- Opseer handles concurrent refresh races with Pattern A+B (re-read winner)
- Re-authentication required only on explicit revoke or refresh token loss
Disconnect
Click "Disconnect" on the Polar card (account/integrations page). Encrypted tokens are removed and the integration is marked inactive. To fully revoke on Polar side, remove Opseer from polar.sh/settings Connected Apps.
Security
- OAuth 2.0 + PKCE (S256) — code_verifier never leaves Opseer server
- Confidential client + client_secret_post — client_secret is server-side only
- AES-256-GCM token encryption at rest (opseer_user_integration.config)
- sub_type=user — user-level token grants access to all organizations
- No write scopes requested — Opseer cannot modify Polar data
Troubleshooting
"No organization" notice
Connected but no organizations on polar.sh. Create one at polar.sh/dashboard then Refresh, or disconnect/reconnect.
"OAuth failed" or invalid_grant
Refresh token race or explicit revoke. Disconnect and reconnect to get a fresh token.
Multi-currency warning banner
When multiple orgs use different currencies, aggregated values are shown without currency conversion. Per-org detail table provides accurate breakdown.