Two Stripe roles in the app
Both use the same
STRIPE_SECRET_KEY but different tables. The rest of this page focuses on Connect.
Stripe panel
Open it from a business’s Settings → Data Sources → Stripe. The panel shows:- Status badge — Not connected until OAuth completes; Connected with the account display name afterwards.
- Description — Connect this business’s Stripe account to sync customers, products and orders.
- Status row — Repeats the current state.
- Connect button — Starts the Stripe Connect OAuth flow.
What gets stored
Each business has at most one row in thestripe_access table:
No refresh token is stored. Access goes through the platform’s Stripe Connect app (
STRIPE_CONNECT_CLIENT_ID + STRIPE_SECRET_KEY) acting on behalf of stripe_account_id.How a business connects
- Agency app —
stripeSetting.jscallsGET /api/stripe/connect-url(requires business access). - The user is sent to Stripe Connect with scope
read_write. - The callback
GET /api/stripe/oauth/callbackexchanges the code, saves or updatesstripe_access, then redirects back to settings with?stripe=connectedor?stripe=error. - Client portal uses the same pattern with
state=forclient:…and client routes (/stripe/connect-url,/stripe/status,/stripe/disconnect).
Environment variables
STRIPE_SECRET_KEYSTRIPE_CONNECT_CLIENT_IDSTRIPE_OAUTH_REDIRECT_URI- Plus frontend redirect URLs for agency vs. forclient flows.
What data is pulled
A scheduled job (stripeScheduler, npm run job:stripe) and the Manual sync button both call fetchStripeData, which uses the platform secret with stripeAccount: stripe_account_id (Connect context).
Data is synced incrementally by last_successful_date when set:
The account display name is refreshed from
accounts.retrieve on each sync.
Disconnect and clear
DELETE /api/stripe/:businessId removes stripe_access plus the business’s products, orders, customers, and sync jobs. It does not clear every Stripe-related table — invoices and checkout sessions may remain unless cleared elsewhere.
Revoked access
The Connect webhookaccount.application.deauthorized clears stripe_access and marks the job failed, so the settings UI surfaces a reconnect prompt.
How the data is used
Contacts and Sales UI
Spend is deduplicated across invoices, checkout sessions, and standalone payment intents so the same payment never double-counts.
Settings
- Connection status and account name shown at the top of the Stripe panel.
- Manual sync (
ManualSyncBlock type="stripe") triggers the same fetch path as the scheduler — useful after a fresh connection or after disconnect/reconnect.
Not used (today)
- Stripe data does not feed the Facebook/ad rules engine (unlike Clarity).
- ROAS and ad reporting in the Business dashboard still come primarily from GHL and other sources. Wire Stripe in separately if you need it as a revenue source.
Platform Stripe (SaaS billing)
Separate from the per-business Connect account, the platform’s own Stripe account handles:- Tenant subscriptions, invoices, package
stripe_price_id, and onboarding checkout. - Webhooks:
checkout.session.completed,customer.subscription.*,invoice.*, credit grants, seat limits, and more.
/api/webhooks/stripe.
Troubleshooting
Summary
- Stripe Connect — one linked
acct_…per business via OAuth. Daily and manual sync of customers, products, prices, payments, invoices, and checkout into local tables. Used to enrich Contacts and Sales grids with spend and order counts by email, plus a dedicated Stripe customers view. - Platform Stripe — billing your tenants on The Agency Engineer itself.
Next steps
Connect GoHighLevel
Pair Stripe with GHL so customer spend ties back to leads and pipelines.
Business dashboard
See where business KPIs come from today (and where Stripe is not yet wired).