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

  1. Go to dashboard.stripe.com and log in as the Compass platform account (OpenLoop's Stripe account).
  2. Navigate to Settings → Connect settings.
  3. Under Integration, choose OAuth and note the Client ID (starts with ca_...). This is STRIPE_CONNECT_CLIENT_ID.
  4. Under Redirect URIs, add: https://joincompass.ai/api/connect/stripe/callback
    • For local development, also add: http://localhost:3000/api/connect/stripe/callback
  5. 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

  1. Tenant clicks Connect on Settings → Integrations → Stripe.
  2. Compass redirects to https://connect.stripe.com/oauth/authorize with the platform Client ID, scope=read_write, and a one-time CSRF state nonce.
  3. Tenant logs in to their Stripe account and authorizes Compass.
  4. Stripe redirects back to /api/connect/stripe/callback?code=...&state=....
  5. Compass exchanges the code for an access token + connected account ID (acct_...).
  6. Access token is stored in IntegrationCredential (key = access_token).
  7. 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.

  1. 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.
  2. Select events: payment_intent.succeeded, customer.subscription.created, customer.subscription.deleted, invoice.paid, invoice.payment_failed
  3. 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).