From 5bea18fd5ed65424288f41f1dfb545675dd9f970 Mon Sep 17 00:00:00 2001
From: Amit Sharma <74371312+Amit91848@users.noreply.github.com>
Date: Wed, 28 Jan 2026 16:57:02 +0530
Subject: [PATCH] feat: hubspot rr skip (#27310)
* feat: hubspot show owner availability for round robin
* fix: translations
* fix: use app name variable for text
---
apps/web/public/static/locales/en/common.json | 2 +
packages/app-store/hubspot/_metadata.ts | 2 +-
packages/app-store/hubspot/api/add.ts | 4 +-
packages/app-store/hubspot/api/callback.ts | 6 +-
.../components/EventTypeAppCardInterface.tsx | 53 ++++-
packages/app-store/hubspot/index.ts | 2 +-
.../app-store/hubspot/lib/CrmService.test.ts | 219 +++++++++++++++++-
packages/app-store/hubspot/lib/CrmService.ts | 106 ++++++---
packages/app-store/hubspot/zod.ts | 5 +-
9 files changed, 347 insertions(+), 52 deletions(-)
diff --git a/apps/web/public/static/locales/en/common.json b/apps/web/public/static/locales/en/common.json
index 3d8f5c74ee..9a0e2dc522 100644
--- a/apps/web/public/static/locales/en/common.json
+++ b/apps/web/public/static/locales/en/common.json
@@ -4465,6 +4465,8 @@
"timestamp": "Timestamp",
"json": "JSON",
"hubspot_ignore_guests": "Do not create new records for guests added to the booking",
+ "crm_book_directly_with_attendee_owner": "If attendee exists in {{appName}}, book directly with the owner",
+ "crm_if_free_email_domain_skip_owner_check": "If attendee has a free email domain, skip the ownership check and round robin as normal",
"saml_idp_not_authoritative_error": "This SAML identity provider is not authorized to manage your account. Please sign in with your original login method.",
"audit_logs_organization_required": "You must be part of an organization to view audit logs.",
"audit_logs_booking_not_found_or_permission_denied": "Booking not found or you do not have permission to view its audit logs.",
diff --git a/packages/app-store/hubspot/_metadata.ts b/packages/app-store/hubspot/_metadata.ts
index b3738e2b15..d447302cbf 100644
--- a/packages/app-store/hubspot/_metadata.ts
+++ b/packages/app-store/hubspot/_metadata.ts
@@ -1,5 +1,5 @@
+import process from "node:process";
import type { AppMeta } from "@calcom/types/App";
-
import _package from "./package.json";
export const metadata = {
diff --git a/packages/app-store/hubspot/api/add.ts b/packages/app-store/hubspot/api/add.ts
index f0943dc7ad..1eb8ee847e 100644
--- a/packages/app-store/hubspot/api/add.ts
+++ b/packages/app-store/hubspot/api/add.ts
@@ -1,8 +1,6 @@
+import { WEBAPP_URL_FOR_OAUTH } from "@calcom/lib/constants";
import * as hubspot from "@hubspot/api-client";
import type { NextApiRequest, NextApiResponse } from "next";
-
-import { WEBAPP_URL_FOR_OAUTH } from "@calcom/lib/constants";
-
import getAppKeysFromSlug from "../../_utils/getAppKeysFromSlug";
import { encodeOAuthState } from "../../_utils/oauth/encodeOAuthState";
diff --git a/packages/app-store/hubspot/api/callback.ts b/packages/app-store/hubspot/api/callback.ts
index 61fe1fbdbc..1165b7585b 100644
--- a/packages/app-store/hubspot/api/callback.ts
+++ b/packages/app-store/hubspot/api/callback.ts
@@ -1,10 +1,8 @@
+import { WEBAPP_URL_FOR_OAUTH } from "@calcom/lib/constants";
+import { getSafeRedirectUrl } from "@calcom/lib/getSafeRedirectUrl";
import * as hubspot from "@hubspot/api-client";
import type { TokenResponseIF } from "@hubspot/api-client/lib/codegen/oauth/models/TokenResponseIF";
import type { NextApiRequest, NextApiResponse } from "next";
-
-import { WEBAPP_URL_FOR_OAUTH } from "@calcom/lib/constants";
-import { getSafeRedirectUrl } from "@calcom/lib/getSafeRedirectUrl";
-
import getAppKeysFromSlug from "../../_utils/getAppKeysFromSlug";
import getInstalledAppPath from "../../_utils/getInstalledAppPath";
import createOAuthAppCredential from "../../_utils/oauth/createOAuthAppCredential";
diff --git a/packages/app-store/hubspot/components/EventTypeAppCardInterface.tsx b/packages/app-store/hubspot/components/EventTypeAppCardInterface.tsx
index bc721e844b..54261c8be2 100644
--- a/packages/app-store/hubspot/components/EventTypeAppCardInterface.tsx
+++ b/packages/app-store/hubspot/components/EventTypeAppCardInterface.tsx
@@ -1,18 +1,18 @@
-import { usePathname } from "next/navigation";
-
-import { useAppContextWithSchema } from "@calcom/app-store/EventTypeAppContext";
import AppCard from "@calcom/app-store/_components/AppCard";
-import { CrmFieldType } from "@calcom/app-store/_lib/crm-enums";
import WriteToObjectSettings, {
BookingActionEnum,
} from "@calcom/app-store/_components/crm/WriteToObjectSettings";
+import { CrmFieldType } from "@calcom/app-store/_lib/crm-enums";
import useIsAppEnabled from "@calcom/app-store/_utils/useIsAppEnabled";
+import { useAppContextWithSchema } from "@calcom/app-store/EventTypeAppContext";
import type { EventTypeAppCardComponent } from "@calcom/app-store/types";
import { WEBAPP_URL } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
+import { SchedulingType } from "@calcom/prisma/enums";
+import { Alert } from "@calcom/ui/components/alert";
import { Switch } from "@calcom/ui/components/form";
import { Section } from "@calcom/ui/components/section";
-
+import { usePathname } from "next/navigation";
import type { appDataSchema } from "../zod";
import { WhenToWrite } from "../zod";
@@ -32,6 +32,8 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({
const overwriteContactOwner = getAppData("overwriteContactOwner") ?? false;
const onBookingWriteToEventObject = getAppData("onBookingWriteToEventObject") ?? false;
const onBookingWriteToEventObjectFields = getAppData("onBookingWriteToEventObjectFields") ?? {};
+ const roundRobinLeadSkip = getAppData("roundRobinLeadSkip") ?? false;
+ const ifFreeEmailDomainSkipOwnerCheck = getAppData("ifFreeEmailDomainSkipOwnerCheck") ?? false;
return (
+
+ {eventType.schedulingType === SchedulingType.ROUND_ROBIN ? (
+ <>
+
+
+ {
+ setAppData("roundRobinLeadSkip", checked);
+ if (checked) {
+ setAppData("enabled", checked);
+ }
+ }}
+ />
+
+
+ {roundRobinLeadSkip && (
+
+
+ {
+ setAppData("ifFreeEmailDomainSkipOwnerCheck", checked);
+ }}
+ />
+
+
+
+ )}
+ >
+ ) : null}
);
diff --git a/packages/app-store/hubspot/index.ts b/packages/app-store/hubspot/index.ts
index 5373eb04ef..8fd49c3469 100644
--- a/packages/app-store/hubspot/index.ts
+++ b/packages/app-store/hubspot/index.ts
@@ -1,3 +1,3 @@
+export { metadata } from "./_metadata";
export * as api from "./api";
export * as lib from "./lib";
-export { metadata } from "./_metadata";
diff --git a/packages/app-store/hubspot/lib/CrmService.test.ts b/packages/app-store/hubspot/lib/CrmService.test.ts
index b8ef0f3a56..bbe2bf2857 100644
--- a/packages/app-store/hubspot/lib/CrmService.test.ts
+++ b/packages/app-store/hubspot/lib/CrmService.test.ts
@@ -1,12 +1,10 @@
-import type { TFunction } from "i18next";
-
+import { setupAndTeardown } from "@calcom/testing/lib/bookingScenario/setupAndTeardown";
import type { CalendarEvent } from "@calcom/types/Calendar";
import type { CredentialPayload } from "@calcom/types/Credential";
import type { CRM } from "@calcom/types/CrmService";
-import { setupAndTeardown } from "@calcom/testing/lib/bookingScenario/setupAndTeardown";
+import type { TFunction } from "i18next";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import type { z } from "zod";
-
import { CrmFieldType, DateFieldType, WhenToWrite } from "../../_lib/crm-enums";
import type { appDataSchema } from "../zod";
@@ -18,6 +16,7 @@ const {
mockGetAppKeysFromSlug,
mockTrackingRepository,
mockBookingRepository,
+ mockCheckIfFreeEmailDomain,
}: {
mockHubspotClient: {
crm: {
@@ -28,7 +27,7 @@ const {
create: ReturnType;
getById: ReturnType;
update: ReturnType;
- };
+ };
};
objects: {
meetings: {
@@ -40,7 +39,7 @@ const {
};
};
associations: { batchApi: { create: ReturnType } };
- owners: { ownersApi: { getPage: ReturnType } };
+ owners: { ownersApi: { getPage: ReturnType; getById: ReturnType } };
};
oauth: { tokensApi: { createToken: ReturnType } };
setAccessToken: ReturnType;
@@ -48,6 +47,7 @@ const {
mockGetAppKeysFromSlug: ReturnType;
mockTrackingRepository: { findByBookingUid: ReturnType };
mockBookingRepository: { findBookingByUid: ReturnType };
+ mockCheckIfFreeEmailDomain: ReturnType;
} = vi.hoisted(() => {
const mockHubspotClient = {
crm: {
@@ -83,6 +83,7 @@ const {
owners: {
ownersApi: {
getPage: vi.fn(),
+ getById: vi.fn(),
},
},
},
@@ -107,7 +108,15 @@ const {
findBookingByUid: vi.fn(),
};
- return { mockHubspotClient, mockGetAppKeysFromSlug, mockTrackingRepository, mockBookingRepository };
+ const mockCheckIfFreeEmailDomain = vi.fn();
+
+ return {
+ mockHubspotClient,
+ mockGetAppKeysFromSlug,
+ mockTrackingRepository,
+ mockBookingRepository,
+ mockCheckIfFreeEmailDomain,
+ };
});
vi.mock("@hubspot/api-client", () => {
@@ -144,6 +153,10 @@ vi.mock("@calcom/features/bookings/repositories/BookingRepository", () => ({
},
}));
+vi.mock("@calcom/features/watchlist/lib/freeEmailDomainCheck/checkIfFreeEmailDomain", () => ({
+ checkIfFreeEmailDomain: mockCheckIfFreeEmailDomain,
+}));
+
import BuildCrmService from "./CrmService";
describe("HubspotCalendarService", () => {
@@ -284,6 +297,198 @@ describe("HubspotCalendarService", () => {
expect(result).toEqual([]);
});
+
+ describe("forRoundRobinSkip param is passed", () => {
+ it("should return contact with owner info when forRoundRobinSkip is true", async () => {
+ mockAppOptions({ roundRobinLeadSkip: true });
+
+ mockHubspotClient.crm.contacts.searchApi.doSearch.mockResolvedValueOnce({
+ results: [
+ {
+ id: "contact-1",
+ properties: {
+ email: "test@example.com",
+ hubspot_owner_id: "12345",
+ },
+ },
+ ],
+ });
+
+ mockHubspotClient.crm.owners.ownersApi.getById.mockResolvedValueOnce({
+ id: "12345",
+ email: "owner@example.com",
+ });
+
+ const result = await service.getContacts({
+ emails: "test@example.com",
+ forRoundRobinSkip: true,
+ });
+
+ expect(result).toEqual([
+ {
+ id: "contact-1",
+ email: "test@example.com",
+ ownerId: "12345",
+ ownerEmail: "owner@example.com",
+ recordType: "CONTACT",
+ },
+ ]);
+
+ expect(mockHubspotClient.crm.contacts.searchApi.doSearch).toHaveBeenCalledWith(
+ expect.objectContaining({
+ properties: ["hs_object_id", "email", "hubspot_owner_id"],
+ })
+ );
+
+ expect(mockHubspotClient.crm.owners.ownersApi.getById).toHaveBeenCalledWith(12345);
+ });
+
+ it("should return contact without ownerEmail when contact has no owner", async () => {
+ mockAppOptions({ roundRobinLeadSkip: true });
+
+ mockHubspotClient.crm.contacts.searchApi.doSearch.mockResolvedValueOnce({
+ results: [
+ {
+ id: "contact-1",
+ properties: {
+ email: "test@example.com",
+ hubspot_owner_id: null,
+ },
+ },
+ ],
+ });
+
+ const result = await service.getContacts({
+ emails: "test@example.com",
+ forRoundRobinSkip: true,
+ });
+
+ expect(result).toEqual([
+ {
+ id: "contact-1",
+ email: "test@example.com",
+ ownerId: null,
+ ownerEmail: undefined,
+ recordType: "CONTACT",
+ },
+ ]);
+
+ expect(mockHubspotClient.crm.owners.ownersApi.getById).not.toHaveBeenCalled();
+ });
+
+ it("should skip owner lookup for free email domains when ifFreeEmailDomainSkipOwnerCheck is enabled", async () => {
+ mockAppOptions({ roundRobinLeadSkip: true, ifFreeEmailDomainSkipOwnerCheck: true });
+ mockCheckIfFreeEmailDomain.mockResolvedValueOnce(true);
+
+ mockHubspotClient.crm.contacts.searchApi.doSearch.mockResolvedValueOnce({
+ results: [
+ {
+ id: "contact-1",
+ properties: {
+ email: "user@gmail.com",
+ },
+ },
+ ],
+ });
+
+ const result = await service.getContacts({
+ emails: "user@gmail.com",
+ forRoundRobinSkip: true,
+ });
+
+ expect(result).toEqual([
+ {
+ id: "contact-1",
+ email: "user@gmail.com",
+ },
+ ]);
+
+ expect(mockCheckIfFreeEmailDomain).toHaveBeenCalledWith({ email: "user@gmail.com" });
+ expect(mockHubspotClient.crm.contacts.searchApi.doSearch).toHaveBeenCalledWith(
+ expect.objectContaining({
+ properties: ["hs_object_id", "email"],
+ })
+ );
+ expect(mockHubspotClient.crm.owners.ownersApi.getById).not.toHaveBeenCalled();
+ });
+
+ it("should include owner lookup for business email domains even when ifFreeEmailDomainSkipOwnerCheck is enabled", async () => {
+ mockAppOptions({ roundRobinLeadSkip: true, ifFreeEmailDomainSkipOwnerCheck: true });
+ mockCheckIfFreeEmailDomain.mockResolvedValueOnce(false);
+
+ mockHubspotClient.crm.contacts.searchApi.doSearch.mockResolvedValueOnce({
+ results: [
+ {
+ id: "contact-1",
+ properties: {
+ email: "user@company.com",
+ hubspot_owner_id: "45678",
+ },
+ },
+ ],
+ });
+
+ mockHubspotClient.crm.owners.ownersApi.getById.mockResolvedValueOnce({
+ id: "45678",
+ email: "owner@company.com",
+ });
+
+ const result = await service.getContacts({
+ emails: "user@company.com",
+ forRoundRobinSkip: true,
+ });
+
+ expect(result).toEqual([
+ {
+ id: "contact-1",
+ email: "user@company.com",
+ ownerId: "45678",
+ ownerEmail: "owner@company.com",
+ recordType: "CONTACT",
+ },
+ ]);
+
+ expect(mockCheckIfFreeEmailDomain).toHaveBeenCalledWith({ email: "user@company.com" });
+ expect(mockHubspotClient.crm.contacts.searchApi.doSearch).toHaveBeenCalledWith(
+ expect.objectContaining({
+ properties: ["hs_object_id", "email", "hubspot_owner_id"],
+ })
+ );
+ });
+
+ it("should handle owner lookup API error gracefully", async () => {
+ mockAppOptions({ roundRobinLeadSkip: true });
+
+ mockHubspotClient.crm.contacts.searchApi.doSearch.mockResolvedValueOnce({
+ results: [
+ {
+ id: "contact-1",
+ properties: {
+ email: "test@example.com",
+ hubspot_owner_id: "99999",
+ },
+ },
+ ],
+ });
+
+ mockHubspotClient.crm.owners.ownersApi.getById.mockRejectedValueOnce(new Error("Owner not found"));
+
+ const result = await service.getContacts({
+ emails: "test@example.com",
+ forRoundRobinSkip: true,
+ });
+
+ expect(result).toEqual([
+ {
+ id: "contact-1",
+ email: "test@example.com",
+ ownerId: "99999",
+ ownerEmail: undefined,
+ recordType: "CONTACT",
+ },
+ ]);
+ });
+ });
});
describe("createContacts", () => {
diff --git a/packages/app-store/hubspot/lib/CrmService.ts b/packages/app-store/hubspot/lib/CrmService.ts
index b32ba58cba..56ed0b5da4 100644
--- a/packages/app-store/hubspot/lib/CrmService.ts
+++ b/packages/app-store/hubspot/lib/CrmService.ts
@@ -1,4 +1,17 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
+
+import { BookingRepository } from "@calcom/features/bookings/repositories/BookingRepository";
+import { checkIfFreeEmailDomain } from "@calcom/features/watchlist/lib/freeEmailDomainCheck/checkIfFreeEmailDomain";
+import getLabelValueMapFromResponses from "@calcom/lib/bookings/getLabelValueMapFromResponses";
+import { getLocation } from "@calcom/lib/CalEventParser";
+import { WEBAPP_URL } from "@calcom/lib/constants";
+import { HttpError } from "@calcom/lib/http-error";
+import logger from "@calcom/lib/logger";
+import { PrismaTrackingRepository } from "@calcom/lib/server/repository/PrismaTrackingRepository";
+import prisma from "@calcom/prisma";
+import type { CalEventResponses, CalendarEvent } from "@calcom/types/Calendar";
+import type { CredentialPayload } from "@calcom/types/Credential";
+import type { Contact, ContactCreateInput, CRM, CrmEvent } from "@calcom/types/CrmService";
import * as hubspot from "@hubspot/api-client";
import type { BatchInputPublicAssociation } from "@hubspot/api-client/lib/codegen/crm/associations";
import type { PublicObjectSearchRequest } from "@hubspot/api-client/lib/codegen/crm/contacts";
@@ -7,22 +20,9 @@ import type {
SimplePublicObjectInput,
} from "@hubspot/api-client/lib/codegen/crm/objects/meetings";
import type { z } from "zod";
-
-import { getLocation } from "@calcom/lib/CalEventParser";
-import getLabelValueMapFromResponses from "@calcom/lib/bookings/getLabelValueMapFromResponses";
-import { WEBAPP_URL } from "@calcom/lib/constants";
-import { HttpError } from "@calcom/lib/http-error";
-import logger from "@calcom/lib/logger";
-import prisma from "@calcom/prisma";
-import type { CalendarEvent, CalEventResponses } from "@calcom/types/Calendar";
-import type { CredentialPayload } from "@calcom/types/Credential";
-import type { CRM, ContactCreateInput, Contact, CrmEvent } from "@calcom/types/CrmService";
-
import { CrmFieldType, DateFieldType } from "../../_lib/crm-enums";
import getAppKeysFromSlug from "../../_utils/getAppKeysFromSlug";
import refreshOAuthTokens from "../../_utils/oauth/refreshOAuthTokens";
-import { BookingRepository } from "@calcom/features/bookings/repositories/BookingRepository";
-import { PrismaTrackingRepository } from "@calcom/lib/server/repository/PrismaTrackingRepository";
import type { HubspotToken } from "../api/callback";
import type { appDataSchema } from "../zod";
@@ -336,11 +336,11 @@ class HubspotCalendarService implements CRM {
hs_meeting_title: event.title,
hs_meeting_body: this.getHubspotMeetingBody(event),
hs_meeting_location: getLocation({
- videoCallData: event.videoCallData,
- additionalInformation: event.additionalInformation,
- location: event.location,
- uid: event.uid,
- }),
+ videoCallData: event.videoCallData,
+ additionalInformation: event.additionalInformation,
+ location: event.location,
+ uid: event.uid,
+ }),
hs_meeting_start_time: new Date(event.startTime).toISOString(),
hs_meeting_end_time: new Date(event.endTime).toISOString(),
hs_meeting_outcome: "RESCHEDULED",
@@ -364,7 +364,6 @@ class HubspotCalendarService implements CRM {
return this.hubspotClient.crm.objects.meetings.basicApi.archive(uid);
};
-
private hubspotAuth = async (credential: CredentialPayload) => {
const appKeys = await getAppKeysFromSlug("hubspot");
if (typeof appKeys.client_id === "string") this.client_id = appKeys.client_id;
@@ -375,11 +374,7 @@ class HubspotCalendarService implements CRM {
let currentToken = credential.key as unknown as HubspotToken;
const isTokenValid = (token: HubspotToken) =>
- token &&
- token.tokenType &&
- token.accessToken &&
- token.expiryDate &&
- token.expiryDate > Date.now();
+ token && token.tokenType && token.accessToken && token.expiryDate && token.expiryDate > Date.now();
const refreshAccessToken = async (refreshToken: string) => {
try {
@@ -488,12 +483,25 @@ class HubspotCalendarService implements CRM {
await this.hubspotCancelMeeting(uid);
}
- async getContacts({ emails }: { emails: string | string[] }): Promise {
+ async getContacts({
+ emails,
+ includeOwner,
+ forRoundRobinSkip,
+ }: {
+ emails: string | string[];
+ includeOwner?: boolean;
+ forRoundRobinSkip?: boolean;
+ }): Promise {
const auth = await this.auth;
await auth.getToken();
const emailArray = Array.isArray(emails) ? emails : [emails];
+ const shouldIncludeOwner = includeOwner || forRoundRobinSkip;
+
+ const skipDueToFreeEmail =
+ forRoundRobinSkip && (await this.shouldSkipAttendeeIfFreeEmailDomain(emailArray[0]));
+
const publicObjectSearchRequest: PublicObjectSearchRequest = {
filterGroups: emailArray.map((attendeeEmail) => ({
filters: [
@@ -505,7 +513,10 @@ class HubspotCalendarService implements CRM {
],
})),
sorts: ["hs_object_id"],
- properties: ["hs_object_id", "email"],
+ properties:
+ shouldIncludeOwner && !skipDueToFreeEmail
+ ? ["hs_object_id", "email", "hubspot_owner_id"]
+ : ["hs_object_id", "email"],
limit: 10,
after: 0,
};
@@ -514,6 +525,27 @@ class HubspotCalendarService implements CRM {
.doSearch(publicObjectSearchRequest)
.then((apiResponse) => apiResponse.results);
+ if (shouldIncludeOwner && !skipDueToFreeEmail) {
+ return await Promise.all(
+ contacts.map(async (contact) => {
+ const ownerId = contact.properties.hubspot_owner_id;
+ let ownerEmail: string | undefined;
+
+ if (ownerId) {
+ ownerEmail = await this.getOwnerEmailFromId(ownerId);
+ }
+
+ return {
+ id: contact.id,
+ email: contact.properties.email,
+ ownerId,
+ ownerEmail,
+ recordType: "CONTACT",
+ };
+ })
+ );
+ }
+
return contacts.map((contact) => {
return {
id: contact.id,
@@ -598,9 +630,7 @@ class HubspotCalendarService implements CRM {
}
private async getContactOwnerId(contactId: string): Promise {
- const contact = await this.hubspotClient.crm.contacts.basicApi.getById(contactId, [
- "hubspot_owner_id",
- ]);
+ const contact = await this.hubspotClient.crm.contacts.basicApi.getById(contactId, ["hubspot_owner_id"]);
return contact.properties.hubspot_owner_id ?? null;
}
@@ -623,6 +653,24 @@ class HubspotCalendarService implements CRM {
this.log.error("Error fetching contact owner, skipping owner update:", error);
}
}
+
+ private async getOwnerEmailFromId(ownerId: string): Promise {
+ try {
+ const owner = await this.hubspotClient.crm.owners.ownersApi.getById(parseInt(ownerId, 10));
+ return owner.email ?? undefined;
+ } catch (error) {
+ this.log.error("Error fetching owner by ID:", error);
+ return undefined;
+ }
+ }
+
+ private async shouldSkipAttendeeIfFreeEmailDomain(attendeeEmail: string): Promise {
+ const appOptions = this.getAppOptions();
+ if (!appOptions.ifFreeEmailDomainSkipOwnerCheck) return false;
+
+ const response = await checkIfFreeEmailDomain({ email: attendeeEmail });
+ return response;
+ }
}
/**
diff --git a/packages/app-store/hubspot/zod.ts b/packages/app-store/hubspot/zod.ts
index 27a26818ba..ea8b1628bc 100644
--- a/packages/app-store/hubspot/zod.ts
+++ b/packages/app-store/hubspot/zod.ts
@@ -1,10 +1,9 @@
import { z } from "zod";
-
import { writeToBookingEntry } from "../_lib/crm-schemas";
import { eventTypeAppCardZod } from "../eventTypeAppCardZod";
+export { CrmFieldType, DateFieldType, WhenToWrite } from "../_lib/crm-enums";
export { writeToBookingEntry, writeToRecordEntrySchema } from "../_lib/crm-schemas";
-export { CrmFieldType, WhenToWrite, DateFieldType } from "../_lib/crm-enums";
export const appDataSchema = eventTypeAppCardZod.extend({
ignoreGuests: z.boolean().optional(),
@@ -13,6 +12,8 @@ export const appDataSchema = eventTypeAppCardZod.extend({
overwriteContactOwner: z.boolean().optional(),
onBookingWriteToEventObject: z.boolean().optional(),
onBookingWriteToEventObjectFields: z.record(z.string(), writeToBookingEntry).optional(),
+ roundRobinLeadSkip: z.boolean().optional(),
+ ifFreeEmailDomainSkipOwnerCheck: z.boolean().optional(),
});
export const appKeysSchema = z.object({