diff --git a/apps/api/v1/pages/api/bookings/_post.ts b/apps/api/v1/pages/api/bookings/_post.ts index 9b6628d04a..fc173abf90 100644 --- a/apps/api/v1/pages/api/bookings/_post.ts +++ b/apps/api/v1/pages/api/bookings/_post.ts @@ -222,6 +222,13 @@ async function handler(req: NextApiRequest) { }; if (isSystemWideAdmin) userId = req.body.userId || userId; + if (req.body.eventTypeId !== undefined && typeof req.body.eventTypeId !== "number") { + throw new HttpError({ + statusCode: 400, + message: "Bad request, eventTypeId must be a number", + }); + } + if (isOrganizationOwnerOrAdmin) { const accessibleUsersIds = await getAccessibleUsers({ adminUserId: userId, diff --git a/apps/api/v1/test/lib/bookings/_post.test.ts b/apps/api/v1/test/lib/bookings/_post.test.ts index 9aa9b516d7..0afe571a68 100644 --- a/apps/api/v1/test/lib/bookings/_post.test.ts +++ b/apps/api/v1/test/lib/bookings/_post.test.ts @@ -25,6 +25,44 @@ vi.mock("@calcom/lib/server/i18n", () => { }; }); +describe("POST /api/bookings - eventTypeId validation", () => { + test("String eventTypeId should return 400", async () => { + const { req, res } = createMocks({ + method: "POST", + body: { + eventTypeId: "invalid-string", + }, + }); + + await handler(req, res); + + expect(res._getStatusCode()).toBe(400); + expect(JSON.parse(res._getData())).toEqual( + expect.objectContaining({ + message: "Bad request, eventTypeId must be a number", + }) + ); + }); + + test("Number eventTypeId should not trigger validation error", async () => { + const { req, res } = createMocks({ + method: "POST", + body: { + eventTypeId: 123, + }, + }); + + await handler(req, res); + + const statusCode = res._getStatusCode(); + const responseData = JSON.parse(res._getData()); + + if (statusCode === 400) { + expect(responseData.message).not.toBe("Bad request, eventTypeId must be a number"); + } + }); +}); + describe.skipIf(true)("POST /api/bookings", () => { describe("Errors", () => { test("Missing required data", async () => {