Skip to main content
Web Development15 min read

Next.js + Cal.com + n8n architecture: a site that books itself

Next.js + Cal.com + n8n: the stack that turns a brochure site into a booking machine. Embed, API v2, HMAC webhooks, bookingSuccessfulV2. Full architecture and 2026 pitfalls.

Next.js + Cal.com + n8n architecture: a site that books itself

Next.js + Cal.com + n8n architecture: a site that books itself

A brochure site without booking is just a brochure. Three bricks turn it into a lead machine.

A prospect arrives at your site at 10 PM. On a classic site, they fill out a form, then... they wait for your email tomorrow. They've already moved to a competitor. And a Calendly page compared yours to the one that answers "Now," at midnight.

Online booking is the highest-leverage conversion tool for service businesses. But most guides — and I audited them — stop at "use a plugin" or "add a Calendly link." No one shows the complete architecture: how Next.js, Cal.com, and n8n work together, without data leaks or phantom bookings.

This article codes the Next.js + Cal.com + n8n stack piece by piece: the embed that keeps users on your site, the v2 API for custom flows, HMAC-signed webhooks, and the bookingSuccessfulV2 event that fires an action in your app the instant a booking is made. At the end, the full stack, the pitfalls table, and a 30-minute slot to apply it to your domain.


Why this stack, not a plugin

The top 10 results for "online booking" are vendors: Mobirise (AI generator), Wegic, Rendevoo, botnation. Or SaaS listicles (HubSpot, 18 tools). Only one — simplebo — talks technique seriously, but stays at the brochure level.

The Next.js + Cal.com + n8n stack wins at three levels a plugin can't cover:

  1. The run, not the label. You control the journey, the URL, the SEO, the tracking. You're not locked into an SaaS-generated page.
  2. The full booking lifecycle. Not just "create a reservation": reminders, reschedule, no-show, CRM notification. That's where n8n comes in.
  3. Your data stays yours. You control who gets what (email, Slack, CRM), and where (your own infra).

A WordPress plugin shows a "Book" button. This stack turns the site into a system that absorbs demand, schedules, notifies, and follows up — without a human in the loop.

User journey: visit -> booking -> confirmationA visitor arrives, sees your slots, books inside the embed, and a webhook confirmation fires automatically.


The three bricks, and their roles

BrickRoleDoes NOT do
Next.jsThe site, SEO, UX, embed, API routesCalendar, timezones, emails
Cal.comThe booking engine (embeddable, open source)Post-booking business logic
n8nAutomation (workflows, webhooks, CRM, Slack, email)Site display logic

Separation of concerns is the architecture's core. Next.js stays light: it displays indexable content (SSR/SSG) and embeds the widget. Cal.com handles all calendar complexity (timezones, availability, email reminders). n8n orchestrates what happens after the booking.

Why not do everything in Next.js? Because scheduling and automation will change independently of your site. You'll redesign the homepage — not the reminder logic. Separating the three prevents rewriting booking every time you refactor.


Step 1 — Embed Cal.com in Next.js

Cal.com provides three packages: @calcom/embed-core (vanilla JS), @calcom/embed-snippet (lightweight), and @calcom/embed-react (React component + TypeScript). For a Next.js site, it's the React one.

Installation

npm install @calcom/embed-react

The component

import Cal from "@calcom/embed-react";

export default function BookingSection() {
  return (
    <Cal
      calLink="your-team/discovery-call"
      style={{ width: "100%", height: "600px" }}
      config={{
        theme: "light",
        hideEventTypeDetails: false,
        layout: "month_view",
      }}
    />
  );
}

Listening to events

import { getCalApi, type EmbedEvent } from "@calcom/embed-react";

useEffect(() => {
  (async () => {
    const cal = await getCalApi({ namespace: "inline" });
    cal("on", {
      action: "bookingSuccessfulV2",
      callback: (e: EmbedEvent<"bookingSuccessfulV2">) => {
        const data = e.detail.data;
        console.log("Booking created:", {
          title: data.title,
          startTime: data.startTime,
          endTime: data.endTime,
        });
      },
    });
    return () => cal("off", {
      action: "bookingSuccessfulV2",
      callback: myCallback,
    });
  })();
}, []);

What the embed does for you

  • Keeps the user on your site — no redirect to a separate Cal.com page.
  • Namespaced event communication — parent and iframe communicate via a message system. Multiple embeds coexist on a page without interfering (namespaces).
  • Instruction queue — commands are queued while the iframe isn't ready, then executed. No commands lost during initialization.
  • Theme and brandingconfig lets you align colors and layout. For full control, wrap in an isolated iframe.

Cal component and embed eventsThe Cal component from @calcom/embed-react: calLink, style, config. bookingSuccessfulV2 events bubble up to the parent via the namespace.


Step 2 — Post-booking: Cal.com webhooks to n8n

The embed runs client-side. For reliable server-side action (create a CRM lead, send an email, notify Slack), you need a webhook.

Pitfall #1: the n8n Cal.com Trigger and the v1 API

The n8n Cal.com Trigger node long relied on Cal.com's v1 API. This API is deprecated. Depending on your n8n version, the node may point at dead endpoints and fail silently. The v2 migration is incoming, but until then, the robust solution is:

Create a generic n8n Webhook node and register it as the callback URL in Cal.com.

Pitfall #2: HMAC signature

A webhook is a public URL. Anyone can call it. Cal.com signs each payload with an HMAC-SHA256 of your secret, sent in the X-Cal-Signature-256 header. You must verify this signature before processing the data.

Next.js webhook route example

// app/api/webhooks/cal/route.ts
import { createHmac } from "crypto";

export async function POST(request: Request) {
  const body = await request.json();
  const signature = request.headers.get("X-Cal-Signature-256");

  const expectedSig = createHmac("sha256", process.env.CAL_WEBHOOK_SECRET!)
    .update(JSON.stringify(body))
    .digest("hex");

  if (signature !== expectedSig) {
    return new Response("Unauthorized", { status: 401 });
  }

  const { triggerEvent, payload } = body;
  switch (triggerEvent) {
    case "BOOKING_CREATED":
      await handleBookingCreated(payload);
      break;
    case "BOOKING_CANCELLED":
      await handleBookingCancelled(payload);
      break;
    case "BOOKING_RESCHEDULED":
      await handleBookingRescheduled(payload);
      break;
  }
  return new Response("OK");
}

n8n webhook events

Cal.com covers the full lifecycle. Configure webhooks in /settings/developer/webhooks and pick the triggers that matter:

EventWhen it fires
BOOKING_CREATEDNew booking confirmed
BOOKING_RESCHEDULEDAttendee changed the time
BOOKING_CANCELLEDBooking cancelled
MEETING_STARTEDVideo call started
MEETING_ENDEDVideo call ended
RECORDING_READYRecording available

The payload includes: attendee info, event details, and your custom metadata.

HMAC-verified Cal.com webhooks to n8nCal.com signs the payload with X-Cal-Signature-256. The n8n webhook verifies HMAC, then the automation chain starts.


Step 3 — End-to-end n8n workflow

Once the webhook is received and verified, n8n orchestrates. A typical SME workflow:

  1. Webhook (receives BOOKING_CREATED, verified HMAC).
  2. Transform: map Cal.com fields to your CRM schema (name, email, date, message).
  3. HTTP Request: POST to your CRM (HubSpot, Pipedrive, or custom API).
  4. Slack/Email: notify the team in real-time, plus confirmation email and scheduled reminders.

This chain runs without human intervention. You capture the booking in the CRM, your team is notified instantly, and no-shows are handled by automatic reminders.

Self-hosting = full control

All bricks are open source. You can host Cal.com and n8n on your own infra. In that case, the webhook passes directly from Cal.com to n8n — the data never leaves your infrastructure. It's the most sovereign setup, with an infrastructure cost to maintain.

Embed + webhook = both gains

  • Client-side (embed): immediate UX, no latency. The bookingSuccessfulV2 event shows confirmation or triggers a CTA in the page.
  • Server-side (webhook): reliable automation, preserved even if the tab is closed. The source of truth for CRM and notifications.

Don't use the client event for critical automation. It depends on an open browser. The webhook, fired by Cal.com server-side, always runs.

n8n workflow: booking -> CRM -> notificationn8n Webhook receives the booking -> transforms -> POST to CRM -> notifies Slack/email. A complete chain without a human.


API v2: when the embed isn't enough

For full control, Cal.com's v2 API replaces the embed. You build your own form with your business rules, and Cal.com handles the heavy lifting.

v2 API calls

const res = await fetch("https://api.cal.com/v2/bookings", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${API_KEY}`,
    "cal-api-version": "2024-08-13",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    eventTypeId,
    start: startISO,
    attendee: { name, email, timeZone },
    metadata: {}, // your context
  }),
});

The cal-api-version header is mandatory. It stabilizes the API for versioning.

The metadata field

metadata is your ally. You attach app-specific context: user ID, order number, source, segment. This context survives the booking and appears in webhooks — you link each booking to a business situation, without parallel state.

Embed vs v2 API?

CriteriaEmbed (@calcom/embed-react)API v2
Setup timeFastMedium
Custom form / pre-dataLimitedFull
Keeps user on-siteYesYes
Maintenance costLowHigher
When to chooseSME that wants to move fastApp with specific business rules

The 2026 pitfalls table

PitfallImpactFix
n8n Cal.com Trigger = v1 APISilent workflow failureGeneric n8n Webhook + HMAC
HMAC signature not verifiedAnyone can post fake bookingsX-Cal-Signature-256 verified, else 401
Missing cal-api-version (v2 API)Call rejectedHeader cal-api-version: 2024-08-13
Multiple embeds without namespaceCrossed eventsDistinct namespace per instance
Relying on client event for CRMLoss if tab is closedServer webhook as source of truth
COEP credentialless on Next.jsCal.com iframe blockedTest embed in production env

The last point matters: if you combine the Cal.com embed with strict security headers (COEP credentialless), the iframe may be blocked. Test the embed in your production environment, not just locally.

Mind map of the Next.js + Cal.com + n8n stackNext.js (site, embed, API routes) + Cal.com (booking engine) + n8n (post-booking automation). Separated, but connected by HMAC webhooks.


Implementation checklist

  1. Create Cal.com account and event type (30-min call).
  2. npm install @calcom/embed-react.
  3. Integrate the Cal component into your booking section.
  4. Listen to bookingSuccessfulV2 for post-booking UX.
  5. Create an empty n8n workflow, start with a Webhook node.
  6. Copy the n8n production URL (or create an app/api/webhooks/cal/route.ts).
  7. In /settings/developer/webhooks Cal.com, register the URL and select triggers.
  8. Enable and verify the HMAC payload signature.
  9. Add nodes: Transform -> HTTP Request (CRM) -> Slack/Email.
  10. Test in staging with a dummy booking, verify CRM + notification.
  11. Measure booking rate (clear CTA before the embed).
  12. Iterate on no-show reminders and reschedule.

What the stack does NOT do

  1. Replace marketing. Friction disappears, not the need for traffic.
  2. Answer emails. Automation handles the booking, not the relationship.
  3. Guarantee conversion. A vague CTA or slow page kills the booking, even with a perfect embed.
  4. Be a one-size-fits-all. A consulting site gains from Cal.com; a healthcare provider with medical records needs more.

Conclusion

The Next.js + Cal.com + n8n stack isn't about gadgets. It's the way to make a modern site (SEO, UX, indexing) work together with a reliable booking engine, and automation that absorbs and follows every booking.

Three levels, three deliverables:

  • Embed @calcom/embed-react — keeps visitors, shows your slots.
  • HMAC webhook — transmits the booking to your server, securely.
  • n8n workflow — CRM, notifications, reminders, follow-up.

If you have a brochure site that "presents but doesn't book," that's exactly the gap this stack fills. The missing piece in your conversion isn't design — it's often a booking that gets made at midnight, without you.

Book a call — 30 min: we look at your site, the 3 leaks, and tell you if the embed suffices or if you need the v2 API + n8n. No commitment.

References: Cal.com Embed overview (calcom-cal-com.mintlify.app) / Cal.com embed-react (mintlify.wiki) / Cal.com API v2 bookings (nextfuture.io.vn) / Cal.com API webhooks (blog.elest.io)

Tags

#Next.js#Cal.com#n8n#Booking#Webhooks#Automation#Architecture#SME#2026

Share this article

LinkedInX

FAQ

Can I embed Cal.com in a Next.js site without outsourcing?

Yes. The @calcom/embed-react package provides a React component (Cal) and a getCalApi function. The embed handles calendar sync, timezones, and notifications. Parent and iframe communicate via namespaced events, executed through an instruction queue. For full control of the booking flow, use the v2 API instead of the embed.

Are Cal.com webhooks secure with n8n?

Yes, if you verify the HMAC signature. Cal.com sends an X-Cal-Signature-256 header. Reject any request whose signature does not match the HMAC-SHA256 of your secret. Also create a generic n8n Webhook node, which is more reliable than the n8n Cal.com Trigger node that relied on the deprecated v1 API.

How do I trigger an action in my app after a booking is made?

Listen for the bookingSuccessfulV2 event from the embed (Cal("on", { action: "bookingSuccessfulV2" })). For reliable server-side automation, use the webhook. Combine both: client event for immediate UX, webhook server for CRM and notifications.

Should I use the embed or the Cal.com v2 API?

Depends. The embed is fast to set up, keeps users in your site, and handles the heavy lifting. The v2 API (/v2/bookings with cal-api-version: 2024-08-13 header and Bearer token) gives full control: custom forms, pre-data collection with metadata, embedded flow. For an SME that wants to move fast: embed. For an app with specific business rules: v2 API.

Where should I host Cal.com webhooks if I have Next.js on Vercel?

Two options. (1) Alongside the app: an app/api/webhooks/cal/route.ts in Next.js, verifying X-Cal-Signature-256 then calling n8n. (2) Directly to n8n if you expose it. The most robust: generic n8n webhook + HMAC, since the n8n Cal.com Trigger node may depend on the deprecated v1 API. Test in staging before connecting production.

30-min site audit

Does your site book meetings — or just present you?

We open your URL together, mark the 3 leaks, and tell you whether a fix is enough or a rebuild is required.

  • 30 min
  • No commitment
  • Action plan
William Aklamavo

Web development and automation expert, passionate about technological innovation and digital entrepreneurship.

Take action with BOVO Digital

This article sparked ideas? Book 30 minutes: we scope the next deliverable, no commitment.

Our Website & SaaS service

Related articles