-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Hubspot integration #2839
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Hubspot integration #2839
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
WalkthroughAdds a HubSpot integration: env vars, OAuth install URL and callback, webhook receiver with signature verification, token refresh and persistence, contact/deal fetchers and Zod schemas/types, event handlers mapping HubSpot events to internal trackLead/trackSale flows, HubSpot app manifests/docs, and minor Prisma index syntax tweaks. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant Web as Web App
participant Redis
participant Prisma
participant HubSpot
rect rgba(200,220,255,0.14)
note over User,Web: Install initiation
User->>Web: Click "Install HubSpot"
Web->>Redis: SET hubspot:install:state:{state} -> workspaceId (TTL)
Web-->>User: Redirect to HubSpot authorize URL
end
rect rgba(200,255,200,0.14)
note over HubSpot,Web: OAuth callback
HubSpot-->>Web: GET /api/hubspot/callback?code&state
Web->>Redis: GET hubspot:install:state:{state} -> workspaceId
Web->>Prisma: Verify workspace & user ownership
Web->>HubSpot: POST /oauth/v1/token (exchange code)
Web->>Prisma: Save InstalledIntegration with credentials
Web-->>User: Redirect to workspace HubSpot settings
end
rect rgba(255,230,200,0.12)
note over Web: Errors -> structured responses
end
sequenceDiagram
autonumber
participant HS as HubSpot Webhooks
participant WA as Webhook Route
participant P as Prisma
participant TR as Token Refresh
participant DF as Data Fetchers
participant ET as Event Trackers
HS-->>WA: POST /api/hubspot/webhook (events)
WA->>WA: Verify X-HubSpot-Signature using HUBSPOT_CLIENT_SECRET
loop per event
WA->>P: Resolve InstalledIntegration by hub_id
WA->>TR: refreshAccessToken(installationId, credentials)
alt contact.created (objectTypeId "0-1")
WA->>DF: getHubSpotContact(contactId, accessToken)
WA->>ET: trackHubSpotLeadEvent(...)
else deal.created (objectTypeId "0-3")
WA->>DF: getHubSpotDeal(dealId, accessToken) -> getHubSpotContact(...)
WA->>ET: trackHubSpotLeadEvent(...)
else deal.dealstage change (propertyChange)
WA->>DF: getHubSpotDeal(dealId, accessToken) -> getHubSpotContact(...)
WA->>ET: trackHubSpotSaleEvent(...)
end
end
WA-->>HS: 200 OK
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches🧪 Generate unit tests
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🧹 Nitpick comments (1)
apps/web/lib/integrations/hubspot/track-lead.ts (1)
33-36: Improve observability context in error logInclude workspace id to correlate incidents across tenants.
Apply this diff:
- console.error(`[HubSpot] No dub_id found for contact ${objectId}.`); + console.error( + `[HubSpot] No dub_id found for contact ${objectId} (workspace ${workspace.id}).`, + );
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/web/lib/integrations/hubspot/track-lead.ts(1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-07-17T06:41:45.620Z
Learnt from: devkiran
PR: dubinc/dub#2637
File: apps/web/app/(ee)/api/singular/webhook/route.ts:0-0
Timestamp: 2025-07-17T06:41:45.620Z
Learning: In the Singular integration (apps/web/app/(ee)/api/singular/webhook/route.ts), the event names in the singularToDubEvent object have intentionally different casing: "Copy GAID" and "copy IDFA". This casing difference is valid and should not be changed, as these are the correct event names expected from Singular.
Applied to files:
apps/web/lib/integrations/hubspot/track-lead.ts
🧬 Code graph analysis (1)
apps/web/lib/integrations/hubspot/track-lead.ts (6)
apps/web/lib/types.ts (1)
WorkspaceProps(184-200)apps/web/lib/integrations/hubspot/types.ts (1)
HubSpotAuthToken(4-4)apps/web/lib/integrations/hubspot/schema.ts (1)
hubSpotLeadEventSchema(59-63)apps/web/lib/integrations/hubspot/get-contact.ts (1)
getHubSpotContact(4-39)apps/web/lib/api/conversions/track-lead.ts (1)
trackLead(29-353)apps/web/lib/integrations/hubspot/get-deal.ts (1)
getHubSpotDeal(4-37)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Vade Review
🔇 Additional comments (2)
apps/web/lib/integrations/hubspot/track-lead.ts (2)
17-19: Overall flow and validation look goodSchema-guarded parse and branching by objectTypeId are sensible.
Also applies to: 21-21, 55-55
42-52: Confirm data‑minimization for HubSpot rawBody (redact to identifiers?)
- rawBody from the HubSpot webhook is forwarded into the conversions pipeline and JSON.stringified (apps/web/lib/integrations/hubspot/track-lead.ts — rawBody: payload at ~lines 50 & 91; apps/web/lib/api/conversions/track-lead.ts — body: JSON.stringify(rawBody) at 249–250).
- Same pattern in HubSpot sale and Singular integrations (apps/web/lib/integrations/hubspot/track-sale.ts:77–78; apps/web/lib/integrations/singular/track-lead.ts:~61; apps/web/lib/integrations/singular/track-sale.ts:~64).
- If you want to redact rawBody to identifiers-only, confirm that change matches your logging/analytics retention and PII/debugging requirements and then update all above call sites to send identifiers-only instead of raw payloads.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
packages/hubspot-app/src/app/webhooks/webhooks-hsmeta.json (1)
6-8: Throughput/backpressure check for maxConcurrentRequests=10.Ensure the webhook handler is idempotent and quick to 2xx under burst loads; otherwise consider lowering concurrency or adding queueing.
packages/hubspot-app/src/app/app-hsmeta.json (1)
14-23: Right‑size scopes (principle of least privilege).If you aren’t writing contacts, drop
crm.objects.contacts.writeto reduce install friction; if you do write deals, addcrm.objects.deals.write. Pick one of the diffs below accordingly.- "requiredScopes": [ - "oauth", - "crm.objects.contacts.read", - "crm.objects.contacts.write", - "crm.objects.leads.read", - "crm.objects.deals.read" - ], + "requiredScopes": [ + "oauth", + "crm.objects.contacts.read", + "crm.objects.leads.read", + "crm.objects.deals.read" + ],or
- "requiredScopes": [ - "oauth", - "crm.objects.contacts.read", - "crm.objects.contacts.write", - "crm.objects.leads.read", - "crm.objects.deals.read" - ], + "requiredScopes": [ + "oauth", + "crm.objects.contacts.read", + "crm.objects.contacts.write", + "crm.objects.leads.read", + "crm.objects.deals.read", + "crm.objects.deals.write" + ],
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
packages/hubspot-app/src/app/app-hsmeta.json(1 hunks)packages/hubspot-app/src/app/webhooks/webhooks-hsmeta.json(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: api-tests
- GitHub Check: build
🔇 Additional comments (5)
packages/hubspot-app/src/app/webhooks/webhooks-hsmeta.json (2)
6-7: Prod webhook URL looks good; confirm env routing.Good removal of the ngrok URL. Please confirm your deploy process updates this per environment (e.g., staging/sandbox projects) so preview/dev traffic doesn't hit prod.
10-27: Validate subscription set vs. handlers and property internal name.Double‑check that your handlers cover contact/deal creation and that "dealstage" matches the internal property name you expect for Closed‑Won transitions.
packages/hubspot-app/src/app/app-hsmeta.json (3)
10-13: Redirect URIs are stable; verify backend config matches exactly.Make sure your OAuth install/callback code uses these exact URIs per environment to avoid HubSpot mismatch errors.
24-28: Permitted URLs check.If you plan any client‑side (HubSpot UI) calls beyond
api.hubapi.com, add them here; server‑to‑server calls from dub.co don’t need to be listed.
30-33: Docs/live support readiness.Confirm the documentation URL is published before app review/listing.
Summary by CodeRabbit
New Features
Documentation
Chores
Refactor