On this page · 11 sections
Overview
The Stripe Connect integration is the input source for Kustiq’s churn engine. It listens to subscription, invoice, and dispute events on your Stripe account and turns them into a live churn-risk score on every paying customer. It does not run Kustiq’s own billing, and it does not run your reporting.
One direction, Stripe to Kustiq. We never call POST, PATCH, or DELETE against your Stripe account. The OAuth token is requested with the read-only Connect role, and the dashboard reflects that scope. 11 event types feed the engine: 5 churn signals, 3 recovery signals, 3 context events. The full list is in the Event reference below.
With the integration on, a customer who hits invoice.payment_failed twice inside 14 days appears at the top of the at-risk segment within 90 seconds. With Stripe alone, the same signal stays in the dashboard event log nobody scrolls.
Setup, in 4 minutes
Five steps. Stripe-side OAuth, no API key paste, no restricted-key creation. The grant is scoped read_only from the consent screen and you can downgrade or revoke it from your Stripe dashboard at any time.
Open Integrations in your Kustiq workspace
~ 20 secondsFrom the dashboard, go to Settings → Integrations. Find the Stripe card, click Connect. The Stripe Connect button opens in the same tab.
Authorise the Stripe Connect consent screen
~ 60 secondsStripe shows the consent dialog. Pick the account, review the role (read_only), the resources (customer_read, subscription_read, invoice_read, charge_read, dispute_read), click Connect my Stripe account. Stripe redirects back to Kustiq and the integration card flips to Connected.
Choose mode and backfill window
~ 30 secondsPick live or test mode and the backfill window: 30 days, 90 days, or all-time. Kustiq pulls past invoices and subscription events for that window so the engine has cohort context on day one. All-time on a 5-year-old account takes 6 to 12 minutes.
Confirm the customer match
~ 1 minuteKustiq matches Stripe customers to your existing churn-engine profiles by email and domain. The match table shows Stripe customer ID on the left, Kustiq profile on the right, confidence in the middle. Anything below 90% confidence stays unmatched until you review.
Verify in the churn dashboard
~ 30 secondsOpen /dashboard/churn. The at-risk segment populates from the backfill within minutes; the live event stream drives updates from there forward. Median end-to-end latency for a Stripe webhook to a dashboard score change is 90 seconds.
Event reference
11 event types in total. The engine ignores everything else Stripe sends, so an extra event in your account does not cost you anything and does not affect the score.
Churn signals
5 events- customer.subscription.deletedChurn
- customer.subscription.updatedDowngrade
- customer.subscription.pausedPause
- invoice.payment_failedDunning
- charge.dispute.createdDispute
Recovery signals
3 events- invoice.payment_succeededRecovered
- customer.subscription.resumedResumed
- customer.subscription.updatedUpgrade
subscription.updated appears in two columns; the engine reads previous_attributes.items to decide direction.
Context events
3 events- customer.createdProfile
- customer.updatedProfile
- invoice.finalizedCycle
Context events do not move the score on their own. They feed cohort and tenure features the score depends on.
Wire Stripe in 4 minutes, churn scores within 90 seconds.
Pro plan ($119/mo). The Stripe Connect integration is included; no per-event fee on usage.
Permissions and scopes
Kustiq requests one Stripe Connect role and five read resources, no more. Every grant is read-only and revocable from Stripe → Settings → Connected apps without contacting support.
read_only· the Connect role. Cannot create, update, or delete anything in your Stripe account.customer_read· read customer name, email, metadata. Used for matching and tenure features.subscription_read· read subscription state, plan, cancellation reason, pause schedule.invoice_read· read invoice status, attempt count, amount, currency. Drives the dunning signal.charge_read+dispute_read· read dispute reason and outcome on a charge. Drives the dispute signal.
Kustiq does not request balance_read, transfer_read, payout_read, tax_read, or any write role. If your IT review asks for a written list of what we touch, the six lines above are the answer.
Webhook verification
Kustiq registers one webhook endpoint on your account at connect time. We verify Stripe’s signature on every inbound request before the event hits the engine. The snippet below mirrors how we verify on our side, so you can audit the exact code path.
// Express handler. Use express.raw({ type: "application/json" }). const stripe = require("stripe")(process.env.STRIPE_SECRET); const SECRET = process.env.STRIPE_WEBHOOK_SECRET; function verify(req) { const sig = req.headers["stripe-signature"]; try { const event = stripe.webhooks.constructEvent( req.body, // raw bytes, not parsed JSON sig, SECRET, ); return event; } catch (err) { // invalid signature, replay, or stale timestamp (> 5 min) return null; } }
Retry policy mirrors Stripe. A 5xx response or no response inside 10s triggers exponential backoff (1m, 5m, 30m, 2h, 12h) for up to 24 hours, then the event is marked failed in /dashboard/integrations with the underlying Stripe event ID.
Sync rules
- Cadence. Real-time via webhook. The backfill runs once on connect; after that, no polling.
- Direction. One way, Stripe to Kustiq. The integration cannot write, update, refund, or cancel anything on your account.
- Mode. Live and test grants are separate OAuth connections. Re-run the connect flow on the matching mode if you switch.
- Match key. Stripe customer email first, customer- metadata
kustiq_profile_idoverride second, domain fallback third. Confidence below 90% never feeds the score. - Latency. Median 90 seconds from Stripe webhook to dashboard score change. p95 under 4 minutes.
- Backfill. 30 / 90 / all-time. Picked once at setup, replayable from
/dashboard/integrations. - Rate limit.Stripe’s read API limits apply during backfill; live mode caps at 100 req / sec, test mode at 25.
Trust and data handling
This section is the answer to your IT review. What we store, what we never touch, where it lives.
What Kustiq stores, what Kustiq never touches
Kustiq stores only Stripe customer and subscription IDs and aggregate signals derived from the events listed above. No card numbers, no charge tokens, no PII beyond what is needed to match a Stripe customer to a Kustiq profile. Token storage is encrypted at rest with AES-256 and rotated every 6 hours.
What we store
- +
customer.id,subscription.id,invoice.id - +Customer email, name (for matching only)
- +Aggregate signals: status, amount band, attempt count
- +Encrypted OAuth refresh token
- +Event ID + timestamp (idempotency)
What we never touch
- −Card numbers (PAN), CVC, full BIN
- −Charge tokens, payment-method tokens
- −Beyond-match PII (address, tax IDs, phone)
- −Bank-account numbers, payouts, balance
- −Anything write-side on your account
Region pinning matches the rest of the platform. EU workspaces route Stripe events through Frankfurt; US workspaces route through Virginia. Cross-region routing is opt-in per workspace and visible from Settings → Region. Full DPA at /dpa, security posture at /trust.
Disconnect
Two paths. From Stripe: Stripe → Settings → Connected apps → Kustiq → Revoke access. From Kustiq: Settings → Integrations → Stripe → Disconnect. Either revokes the OAuth grant within 5 minutes; live webhook delivery stops immediately.
What disconnect does, and what it does not do
Disconnect stops Kustiq from receiving any new event from your Stripe account. Existing churn scores stay on your Kustiq profiles until you delete them or reconnect; backfilled history is preserved so you can re-enable without losing context.
Settings → Data → Erase Stripe-derived signals or email support.Troubleshooting
Ten known states. Each has a stable anchor so you can link a teammate to the exact row.
OAuth grant revoked by Stripe #
The Stripe-side admin revoked the connected app, or the access token expired without a successful refresh. Reconnect from Settings → Integrations. Past scores stay; no Stripe data is lost.
Connect role downgraded below read_only #
The grant was changed to a custom Connect role that no longer includes read on subscriptions or invoices. Restore the read_only role, or re-run OAuth from Kustiq.
Live webhook signed with test secret #
You connected the test account but the workspace is set to live, or vice versa. Disconnect, reconnect on the matching mode. Test events never move live scores.
Stripe rate-limit during backfill #
Another integration on the same Stripe account is consuming the read budget. Kustiq pauses the backfill, retries on the schedule above. No action needed unless backfill stalls past 12 hours.
Customer match confidence under 90% #
The Stripe customer has no email and no kustiq_profile_id on metadata. Add the metadata key in Stripe, or set the email, then run a manual rematch from /dashboard/integrations.
Webhook signature mismatch #
The endpoint secret in our store drifted from Stripe’s. This happens after a Stripe-side rotate. Press Rotate secret in /dashboard/integrations to refresh both ends.
Webhook timestamp older than 5 minutes #
Server clock drift. Sync the host with NTP. Stripe’s t= timestamp is always in UTC seconds.
Workspace region differs from Stripe account region #
An EU workspace can connect a US Stripe account, but the data crosses regions. Move the workspace from Settings → Region, or accept the cross-region note shown at connect time.
Stripe integration requires Pro #
The Stripe Connect integration is gated to Pro ($119/mo). Upgrade from /pricing#pro; existing OAuth grants resume automatically.
Stripe account in restricted state #
Stripe restricted the account (KYC pending, payouts paused, or under review). Read access on subscriptions can be denied. Resolve the restriction in Stripe; sync resumes within 10 minutes.
FAQ
Is this the same Stripe integration that handles my Kustiq subscription?
Which Stripe events does Kustiq listen to?
Does Kustiq write anything to Stripe?
read_only by design, so Kustiq cannot create, update, refund, cancel, or disable any object on your Stripe account. If you need a write integration, build a workflow on your side that reads our churn-event webhook.Where does the Stripe data live?
Settings → Region before first connect; moving regions is a manual support request.Is the Stripe integration available on the free tier?
What happens to the data Kustiq stored if I disconnect?
Settings → Data → Erase Stripe-derived signals to purge.Does the integration touch any card data?
Changelog
- 2026-05-16 · v1.1 Pair-lock production-ready audit. BreadcrumbList position-1 fixed to “Home”. SoftwareApplication JSON-LD @id-graph linked to root
#organd#site. New per-page OG image at/docs/stripe/opengraph-image. FAQ trust-card reference converted to anchor link. Free-tier copy unified to 3 profiles a week. Eleven → 11 numeric consistency. - 2026-05-08 · v1.0 Initial release. Disambiguation banner against billing-docs collision. Pro-plan link on the lede. Trust section above Disconnect. Footer cross-link row. Last-verified badge.
- 2026-04-24 · v0.9 Backfill window picker added (30 / 90 / all-time). Customer match confidence raised from 80% to 90%.
- 2026-03-11 · v0.7 11th event added:
charge.dispute.created. Dispute signal feeds the score with a 7-day decay. - 2026-01-29 · v0.5 Test-mode wiring split out from live mode. Test events no longer affect live scores.
- 2025-12-04 · v0.1 Closed beta with three design partners.
Stripe wired. Engine scoring within 90 seconds.
4-minute OAuth connect, read-only by design. The integration backfills 30, 90, or all-time history on the first run. Available on the Pro plan ($119/mo).