Connectors
Stripe Connect
Category: Payments
What it does: Tenants connect their own Stripe account via OAuth so Compass can read their patient subscriptions, invoices, and one-time charges — powering the /revenue, /retention, and /acquisition dashboards with real data.
Prerequisites
You need a Stripe Connect platform account (separate from the tenant's own Stripe account). Compass acts as the platform; each tenant's Stripe account is the connected account.
Step 1 — Create the Stripe Connect platform application
- Go to dashboard.stripe.com and log in as the Compass platform account (OpenLoop's Stripe account).
- Navigate to Settings → Connect settings.
- Under Integration, choose OAuth and note the Client ID (starts with
ca_...). This isSTRIPE_CONNECT_CLIENT_ID. - Under Redirect URIs, add:
https://joincompass.ai/api/connect/stripe/callback- For local development, also add:
http://localhost:3000/api/connect/stripe/callback
- For local development, also add:
- Choose the OAuth scopes:
read_write(lets Compass read subscriptions and invoices on behalf of the tenant).
Step 2 — Set environment variables
STRIPE_CONNECT_CLIENT_ID="ca_..." # from Connect settings → Client ID
STRIPE_SECRET_KEY="sk_live_..." # platform account's secret key
OAUTH_REDIRECT_BASE_URL="https://joincompass.ai"
Step 3 — How the OAuth flow works
- Tenant clicks Connect on Settings → Integrations → Stripe.
- Compass redirects to
https://connect.stripe.com/oauth/authorizewith the platform Client ID,scope=read_write, and a one-time CSRF state nonce. - Tenant logs in to their Stripe account and authorizes Compass.
- Stripe redirects back to
/api/connect/stripe/callback?code=...&state=.... - Compass exchanges the code for an access token + connected account ID (
acct_...). - Access token is stored in
IntegrationCredential(key =access_token). - Tenant is redirected to
/settings/integrations?connected=stripe.
Step 4 — Backfill historical data (manual)
After connecting, call backfillStripeData(tenantId) from lib/connectors/stripe-connect.ts to pull the last 90 days of subscriptions and invoices. This is a one-time manual operation — run it from a script or REPL.
import { backfillStripeData } from "@/lib/connectors/stripe-connect";
const result = await backfillStripeData("tenant-cuid-here");
console.log(result); // { customersUpserted, subscriptionsCreated, ordersCreated }
Permissions
The read_write scope allows Compass to:
- Read customers, subscriptions, and invoices
- Does not allow charging or modifying the tenant's Stripe account
Disconnect
Clicking Disconnect in the UI deletes the Integration and IntegrationCredential rows.
TODO: Call stripe.oauth.deauthorize({ client_id, stripe_user_id }) to revoke the token at Stripe before deletion.
Troubleshooting
| Error param | Cause |
|---|---|
stripe_denied |
Tenant clicked "Cancel" on the Stripe authorization page |
stripe_state_invalid |
CSRF state nonce expired (10-min TTL) or was tampered with |
stripe_exchange_failed |
Stripe API error during code exchange — check STRIPE_SECRET_KEY |
Per-tenant webhook setup
Stripe Connect doesn't deliver events from the platform account back to the tenant context automatically — each connected tenant configures their own webhook URL so Compass can route events to the right workspace.
- In Stripe Dashboard → Developers → Webhooks, add an endpoint:
https://joincompass.ai/api/webhooks/stripe/<your-tenant-slug>. Each tenant uses a distinct URL keyed by their workspace slug. - Select events:
payment_intent.succeeded,customer.subscription.created,customer.subscription.deleted,invoice.paid,invoice.payment_failed - Copy the signing secret and paste into Compass → Settings → Integrations → Stripe → Configure.
Idempotency is enforced automatically — duplicate Stripe deliveries (same event.id) are dropped via an audit-log lookup keyed by (tenantId, eventId).