Skip to content

feat(demo-booking): send demo requests and booking decisions to a sales-channel webhook - #10015

Closed
waleedlatif1 wants to merge 1 commit into
stagingfrom
feat/demo-request-slack
Closed

waleedlatif1 wants to merge 1 commit into
stagingfrom
feat/demo-request-slack

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Summary

  • New notifyDemoRequest posts /demo events to DEMO_REQUEST_WEBHOOK_URL (bearer DEMO_REQUEST_WEBHOOK_TOKEN), so the sales channel gets one card per request instead of a forwarded email
  • The form route sends demo_request.submitted after its record is saved; the Cal.com booking webhook sends demo_request.booking with the decision, start time and attendee
  • Declined bookings are never sent: no form vouched for them, which is what a bot booking the public link looks like
  • Both sends run in after(), so they never slow the visitor or the Cal.com ack, and a failure is logged and dropped
  • Both env vars are optional; unset sends nothing and behavior is unchanged

Type of Change

  • New feature

Testing

biome on the changed files; type-check and audits in CI

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing (new tests pass the test-audit authoring gate)
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

@vercel

vercel Bot commented Nov 13, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
docs Skipped Skipped Nov 13, 2026 9:27pm UTC

Request Review

@greptile-apps

greptile-apps Bot commented Nov 13, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge, with the earlier non-blocking duplicate-notification concern still open.

Findings

  1. P2 Booking notifications repeat ▶

Summary

Adds optional sales-channel webhook events for demo requests and booking decisions.

  • The sales channel can receive each saved demo request.
  • The sales channel can see confirmed and pending demo bookings.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Demo form] --> B[Save booker record]
  B --> C[Return success]
  B --> D[After response: email and submitted event]
  E[Signed Cal.com request] --> F[Review booking]
  F --> G{Declined?}
  G -->|Yes| H[Acknowledge without sales event]
  G -->|No| I[After response: booking event]
  D --> J[Configured sales webhook]
  I --> J
Loading

Reviews (2) · Last reviewed commit: "feat(demo-booking): send demo requests a..." · Reviewed by Greptile

Comment on lines +102 to +106
if (decision !== 'declined') {
after(() =>
notifyDemoRequest({
type: 'demo_request.booking',
bookingUid: uid,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Booking notifications repeat

Every repeated Cal.com delivery sends demo_request.booking again for the same bookingUid. claimDemoBooker remembers the original lookup, but it does not stop another notification. An unverified booking stays pending on every delivery, so each retry sends another sales event and can create duplicate cards or manual review work.

Add a separate notification claim keyed by bookingUid to filter repeated deliveries.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 6 files

Confidence score: 3/5

  • Repeated Cal.com deliveries for the same bookingUid can schedule duplicate sales notifications in apps/sim/app/api/demo-requests/bookings/route.ts. Only schedule a notification when this request creates the claim.
  • In apps/sim/lib/demo-booking/notify.ts, leaving the response body untouched can keep the connection open until garbage collection. Cancel the body before checking the status.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/sim/lib/demo-booking/notify.ts">

<violation number="1" location="apps/sim/lib/demo-booking/notify.ts:57">
P3: The response body is never consumed or cancelled, so each send can hold its connection until GC. Cancel the body before checking the status, as the connector clients already do.</violation>
</file>

<file name="apps/sim/app/api/demo-requests/bookings/route.ts">

<violation number="1" location="apps/sim/app/api/demo-requests/bookings/route.ts:102">
P2: Repeated Cal.com deliveries for the same `bookingUid` can schedule another sales notification because `reviewDemoBookingRequest` returns the stored claim but this branch does not distinguish first from repeated processing. Deduplicate booking notifications by claim/booking ID before scheduling the webhook event.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Turn on auto-fix | Re-trigger cubic


// A declined booking had no form submission behind it, which is what a bot
// booking the public link looks like, so the sales channel never hears of it.
if (decision !== 'declined') {

@cubic-dev-ai cubic-dev-ai Bot Nov 13, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Repeated Cal.com deliveries for the same bookingUid can schedule another sales notification because reviewDemoBookingRequest returns the stored claim but this branch does not distinguish first from repeated processing. Deduplicate booking notifications by claim/booking ID before scheduling the webhook event.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At apps/sim/app/api/demo-requests/bookings/route.ts, line 102:

<comment>Repeated Cal.com deliveries for the same `bookingUid` can schedule another sales notification because `reviewDemoBookingRequest` returns the stored claim but this branch does not distinguish first from repeated processing. Deduplicate booking notifications by claim/booking ID before scheduling the webhook event.</comment>

<file context>
@@ -86,10 +89,27 @@ export const POST = withRouteHandler(async (request: NextRequest) => {
+
+  // A declined booking had no form submission behind it, which is what a bot
+  // booking the public link looks like, so the sales channel never hears of it.
+  if (decision !== 'declined') {
+    after(() =>
+      notifyDemoRequest({
</file context>
Fix with cubic

body: JSON.stringify(event),
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
})
if (!response.ok) {

@cubic-dev-ai cubic-dev-ai Bot Nov 13, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: The response body is never consumed or cancelled, so each send can hold its connection until GC. Cancel the body before checking the status, as the connector clients already do.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At apps/sim/lib/demo-booking/notify.ts, line 57:

<comment>The response body is never consumed or cancelled, so each send can hold its connection until GC. Cancel the body before checking the status, as the connector clients already do.</comment>

<file context>
@@ -0,0 +1,66 @@
+      body: JSON.stringify(event),
+      signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
+    })
+    if (!response.ok) {
+      logger.warn('Demo request webhook rejected the event', {
+        type: event.type,
</file context>
Suggested change
if (!response.ok) {
await response.body?.cancel()
if (!response.ok) {
Fix with cubic

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

Closing: this is moving into Sim workflows driven by Cal.com webhooks, which already carry the form's details in the booking notes, so the app doesn't need to send anything.

@waleedlatif1
waleedlatif1 deleted the feat/demo-request-slack branch November 13, 2026 21:39

This branch was previously deployed

1 inactive deployment
Preview — 5720f641 Deployed Nov 13, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant