* feat: add booking attendees endpoint to API v2
Co-Authored-By: rajiv@cal.com <sahalrajiv6900@gmail.com>
* feat: add rate limiting to booking attendees endpoint
Co-Authored-By: rajiv@cal.com <sahalrajiv6900@gmail.com>
* refactor: simplify attendees output to id, bookingId, name, email, timeZone
Co-Authored-By: rajiv@cal.com <sahalrajiv6900@gmail.com>
* test: add E2E tests for booking attendees endpoint
Co-Authored-By: rajiv@cal.com <sahalrajiv6900@gmail.com>
* chore: update bookings repository
* fixup: add pbac guards and update service logic
* chore: update openapi spec
* test: add rate limiting E2E test for booking attendees endpoint
Co-Authored-By: rajiv@cal.com <sahalrajiv6900@gmail.com>
* fix: tests
* fix: return 404 instead of 403 for non-existent booking in BookingPbacGuard
The BookingPbacGuard was returning 403 (Forbidden) for non-existent bookings
because doesUserIdHaveAccessToBooking returns false when a booking doesn't
exist, which the guard treated as an access denial.
Added an explicit booking existence check in the guard before the access
check, so non-existent bookings now correctly return 404 (Not Found) as
documented in the PR description.
Updated the E2E test to expect 404 for non-existent booking UIDs.
Issue identified by cubic.
Co-Authored-By: unknown <>
* fixup
* fix: return 404 instead of 403 for non-existent booking in attendees endpoint
BookingPbacGuard now checks booking existence before the access check,
returning 404 (Not Found) instead of 403 (Forbidden) for non-existent
booking UIDs. Updated the E2E test assertion and description to match.
Issue identified by cubic (confidence 9/10).
Co-Authored-By: unknown <>
* chore: implement PR feedback
* chore: update tests
* fixup
* chore: update endpoint decsription
* feat: endpoint to retrieve specific attendee
* chore: update e2e tests
* chore: implement cubic feedback
* fix: update test to expect 403 for non-existent booking UID (BookingPbacGuard behavior)
Co-Authored-By: rajiv@cal.com <sahalrajiv6900@gmail.com>
* fix: merge conflicts
* feat: endpoint to get attendees
* chore: update findByUidIncludeEventTypeAttendeesAndUser method
* chore: implement PR feedback
* fix: e2e tests
* chore: update e2e tests
* fixup fixup
* fix: remove phoneNumber assertion since it's optional and not provided in test
* chore: implement PR feedback
* fix: keep the same output shape for get attendees and get attendee endpoint
* chore: update openapi spec
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: bot_apk <apk@cognition.ai>
* fix: ensure default calendars
* test: add E2E tests for delegation credential controller and update tasker config
- Add E2E tests to verify ensureDefaultCalendars is called when enabling delegation credentials
- Update calendars tasker config to use medium-1x machine for retry on OOM
- Set minimum retry backoff to 60 seconds (1 minute between retries)
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* fix: update tasker config to use small-2x machine with outOfMemory retry on medium-1x
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* fix: update E2E tests to properly spy on service instance and use valid workspace platform slug
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* ci: add CALCOM_SERVICE_ACCOUNT_ENCRYPTION_KEY to E2E API v2 workflow
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* fix: add encryption key to E2E test file for delegation credentials
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* revert: remove CALCOM_SERVICE_ACCOUNT_ENCRYPTION_KEY from workflow (moved to test file)
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* fix: move encryption key to setEnvVars.ts for E2E tests
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* fix: use valid format for service account encryption key
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* fix: encrypt service account key in E2E test for delegation credentials
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* fix: mock updateDelegationCredentialEnabled to bypass Google API call in E2E tests
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* fix: get service from app.get() after initialization for proper spy setup in E2E tests
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* fix: use jest.mock() to mock toggleDelegationCredentialEnabled and bypass Google API calls in E2E tests
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* fix: use Service.prototype pattern for spying on ensureDefaultCalendars in E2E tests
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* fix: move spy setup to beforeAll before app.init() for proper NestJS interception
Co-Authored-By: morgan@cal.com <morgan@cal.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* fix: add guest limits and rate limiting to booking-guests endpoint
- Add ArrayMaxSize(10) validation to limit guests per request to 10
- Add aggressive rate limiting (5 requests/minute) via @Throttle decorator
- Add total guest limit check (max 30 guests per booking) to prevent abuse
- Update API documentation to reflect new limits
This prevents scammers from using the endpoint to send spam emails
to hundreds of guests through our system.
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* docs: update openapi.json with guest limits and rate limiting info
Co-Authored-By: morgan@cal.com <morgan@cal.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-02-02 11:49:25 +02:00
MorganGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* chore: ensure default calendars with trigger.dev apiv2
* test: add unit and e2e tests for CalendarsTasker integration
- Add unit tests for CalendarsTasker.dispatch when enableAsyncTasker is true
- Add e2e test to verify ensureDefaultCalendarsForUser is called when creating membership
- Mock CalendarsTasker and ConfigService in unit tests
- Test both async (Trigger.dev) and sync (Bull queue) paths
- Fix missing return types on helper functions in e2e tests
- Add *.spec.ts to biome test file exceptions for noExcessiveLinesPerFunction rule
Co-Authored-By: morgan@cal.com <morgan@cal.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
The UpdateInputAddressLocation_2024_08_13 and related location types were
referenced via getSchemaPath() but not registered with @ApiExtraModels,
causing them to be missing from the generated OpenAPI spec.
This fix adds @ApiExtraModels decorator to the BookingLocationController
to register all location types used in the UpdateBookingLocationInput.
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-17 00:22:19 +02:00
MorganGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* docs: improve beforeEventBuffer and afterEventBuffer descriptions in API v2
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* fixup! docs: improve beforeEventBuffer and afterEventBuffer descriptions in API v2
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* Documentation edits made through Mintlify web editor
* Documentation edits made through Mintlify web editor
---------
Co-authored-by: mintlify[bot] <109931778+mintlify[bot]@users.noreply.github.com>
2026-01-15 16:28:10 +00:00
Keith WilliamsGitHubmintlify[bot] <109931778+mintlify[bot]@users.noreply.github.com>
* clean-up nav
* Documentation edits made through Mintlify web editor
* Documentation edits made through Mintlify web editor
* further clean up
* add oauth in sidebar
* --
* land in v2
* land in v2
* Documentation edits made through Mintlify web editor
* Documentation edits made through Mintlify web editor
* cleanup
* Documentation edits made through Mintlify web editor
* deprecated v1
---------
Co-authored-by: Syed Ali Shahbaz <alishahbaz7@gmail.com>
Co-authored-by: mintlify[bot] <109931778+mintlify[bot]@users.noreply.github.com>
* chore: tag deprecated platform oauth endpoints in api v2
* fixup! chore: tag deprecated platform oauth endpoints in api v2
* fixup! fixup! chore: tag deprecated platform oauth endpoints in api v2
* chore: fix docs.json mintlify
* chore: fix docs.json mintlify
Platform organizations don't have public-facing subdomains, so non-managed
users in platform orgs should get cal.com URLs instead of the platform
org subdomain.
- Updated EventTypeUser type to include isPlatform field
- Modified buildBookingUrl to check isPlatform before using org slug
- Added unit test for platform org users
Co-authored-by: Morgan <33722304+ThyMinimalDev@users.noreply.github.com>
* feat(api): add bookingUrl field to event types API v2 response
Add a new bookingUrl field to EventTypeOutput_2024_06_14 that contains
the full, correct booking URL for each event type. This fixes the issue
where companion app and Chrome extension were hardcoding cal.com URLs
instead of using organization subdomains.
Changes:
- Add bookingUrl field to EventTypeOutput_2024_06_14 type definition
- Update repository to include organization data when fetching users
- Add buildBookingUrl method to compute URL using getOrgFullOrigin
- Include bookingUrl in getResponseEventType return object
The booking URL is computed using the first user's organization slug
(if any) to generate the correct subdomain URL (e.g., i.cal.com/keith/30min
for organization users instead of cal.com/keith/30min).
* fix: include organization data in getEventTypeByIdWithHosts
Update getEventTypeByIdWithHosts to use usersInclude to fetch
organization slug data, ensuring bookingUrl is computed correctly
for the GET /v2/event-types/{eventTypeId} endpoint.
* test: add unit tests and E2E assertions for bookingUrl field
* fix(api-v2): correct bookingUrl format for org users and fix double slashes
Fix issues with bookingUrl field in event types API v2 response:
- Remove trailing slashes from base URLs to prevent double slashes
- Use profile.username instead of user.username for organization users
(profile contains clean username without org suffix)
- Include user profiles in repository queries to access profile data
- Create local org-domains utility to replace @calcom/features dependency
which isn't available in API v2 runtime
Changes:
- Add apps/api/v2/src/lib/org-domains.ts with getOrgFullOrigin function
adapted from @calcom/features/ee/organizations/lib/orgDomains
- Update event-types.repository.ts to include profiles in usersInclude
- Update buildBookingUrl() to prioritize profile data when available
- Update unit tests to cover organization user profile scenarios
Fixes:
- Double slashes in URLs (e.g., http://localhost:3000//user/slug)
- Incorrect username format for org users (e.g., owner1-acme instead
of owner1)
- Missing organization subdomain in booking URLs (e.g., should be
http://acme.localhost:3000/owner1/30min not
http://localhost:3000/owner1-acme/30min)
* deslop ai code
* handle empty username in both code and write test for it, use select instead of include
* feat(api-v2): reuse core org domain logic for event type bookingUrl
Export getOrgFullOrigin and subdomainSuffix from @calcom/platform-libraries/organizations
to reuse existing core logic instead of duplicating it in API v2. This ensures consistency
across the codebase and reduces maintenance burden.
- Export getOrgFullOrigin and subdomainSuffix from platform-libraries/organizations
- Update output-event-types.service to import from @calcom/platform-libraries/organizations
- Remove duplicate org-domains.ts file from API v2
- Update test mocks to use platform-libraries import path
- buildBookingUrl method now uses core getOrgFullOrigin function
This addresses feedback to reuse core code rather than introducing duplicate logic.
* test(api-v2): exclude bookingUrl from output comparison in e2e test
* refactor(api-v2): reuse core logic for event type bookingUrl
Replace duplicated username/org extraction logic in buildBookingUrl with
core functions. Use getBookerBaseUrlSync from @calcom/platform-libraries/organizations
for base URL generation, and add enrichUserWithProfile method that follows
the same pattern as core's UserRepository.enrichUsersWithTheirProfiles.
The enrichment logic is applied synchronously since profiles are already
fetched by the repository, avoiding the need to make the service async.
This ensures consistency with core patterns while maintaining the existing
synchronous API contract.
- Replace getOrgFullOrigin with getBookerBaseUrlSync
- Add enrichUserWithProfile method following core enrichment pattern
- Simplify buildBookingUrl to use enriched user data
- Update tests to mock getBookerBaseUrlSync and verify enrichment flow
* trailing slash cubic comment
* address review comments
* address review comments 2
* better code
* Updated the test to give the user an organization
* address review comments again
* Revert "address review comments again"
This reverts commit 622ea3fc8dcd7f5c3113614afcfc86beadecca0e.
* allow both the full UserWithProfile and the partial EventTypeUser (from select queries) to use the same getUserMainProfile() method, eliminating code duplication without changing the performance-optimized repository queries.
* reveiw points
* fix(api): remove OAuth client ID suffix from email in booking API responses
Fixes#25494 | Linear: CAL-6843
When managed users create or receive bookings, their emails were being returned with an internal OAuth client ID suffix (e.g., bob+cuid123@example.com). This suffix is used internally for user identification but should not be exposed in API responses.
Changes:
- Add cleanOAuthEmailSuffix() helper using CUID regex pattern
- Clean email suffix in hosts[], attendees[], bookingFieldsResponses.email, bookingFieldsResponses.guests[], and reassignedTo.email
- Pattern consistent with google-calendar.service.ts implementation
Affected output methods:
- getOutputBooking
- getOutputRecurringBooking
- getOutputSeatedBooking
- getOutputRecurringSeatedBooking
- getOutputReassignedBooking
- getHost
* refactor(api): preserve original email, add displayEmail field
Per team discussion, keep original email unchanged to avoid breaking changes for platform customers.
Add displayEmail field with CUID suffix removed for display purposes
* feat(api): add displayEmail to booking output DTOs
Add displayEmail property to BookingAttendee, BookingHost and ReassignedToDto for API documentation and type safety
* test(api): add e2e tests for displayEmail fields in managed user bookings
Add tests to verify that displayEmail fields correctly strip CUID suffix from OAuth managed user emails in booking API responses:
- Test host displayEmail returns email without CUID suffix
- Test attendee displayEmail returns email without CUID suffix
- Test bookingFieldsResponses.displayEmail returns clean email
- Test displayGuests array returns emails without CUID suffix
* false positive breaking change
* false positive breaking change
* test(api): update existing e2e tests to expect displayEmail field
* fix(api): add missing displayEmail to seated booking test assertions
The seated booking tests were missing displayEmail in the attendee
assertions for the second booking test and cancel-as-host test,
causing CI test failures
---------
Co-authored-by: cal.com <morgan@cal.com>
Co-authored-by: Morgan <33722304+ThyMinimalDev@users.noreply.github.com>
* feat: api v2 add missing event type fields for advanced settings
Add 9 event type fields to API v2 that were available in tRPC but missing from the platform API:
- disableCancelling: disable cancelling for guests/organizer
- disableRescheduling: disable rescheduling for guests/organizer
- canSendCalVideoTranscriptionEmails: send Cal Video transcription emails
- autoTranslateInstantMeetingTitleEnabled: auto-translate instant meeting titles
- interfaceLanguage: preferred booking interface language
- allowReschedulingPastBookings: allow rescheduling past events
- allowReschedulingCancelledBookings: allow booking via reschedule link
- customReplyToEmail: custom reply-to email for confirmations
- showOptimizedSlots: optimize time slot arrangement
Updated output/input schemas, transformation services, and E2E tests.
* fix(api-v2): add proper OpenAPI types for nullable event type fields
Add explicit type and nullable properties to @ApiPropertyOptional decorators
for fields with `boolean | null` or `string | null` types. Without these,
Swagger was generating incorrect "type": "object" instead of the correct types.
Fixed fields:
- disableCancelling: type: Boolean, nullable: true
- disableRescheduling: type: Boolean, nullable: true
- interfaceLanguage: type: String, nullable: true
- allowReschedulingCancelledBookings: type: Boolean, nullable: true
- customReplyToEmail: type: String, nullable: true
- showOptimizedSlots: type: Boolean, nullable: true
* refactor: customReplyToEmail was intentionally excluded from this PR. The web UI
restricts this field to only allow the user's own verified emails via a
dropdown, but implementing the same validation in the API requires additional
business logic. This will be addressed in a separate PR with proper email
ownership validation.
* feat(api-v2): add validation for interfaceLanguage field
Add @IsIn validation to interfaceLanguage field to only accept supported
locales. This ensures API v2 matches the web UI behavior where users can
only select from a predefined dropdown of supported languages.
Changes:
- Add SUPPORTED_LOCALES constant to @calcom/platform-constants
- Add @IsIn([...SUPPORTED_LOCALES]) validation to create/update DTOs
- Add E2E tests for invalid locale rejection (400 error)
- Add cross-reference comments in i18n.json and api.ts to keep in sync
* docs(api): add default values to event type input field documentation
Added default value documentation to @DocsPropertyOptional decorators
for the new event type fields in API v2 (2024_06_14):
- disableCancelling: false
- disableRescheduling: false
- canSendCalVideoTranscriptionEmails: true
- autoTranslateInstantMeetingTitleEnabled: false
- allowReschedulingPastBookings: false
- allowReschedulingCancelledBookings: false
- showOptimizedSlots: false
This improves API documentation by clearly communicating default
values to API consumers in the OpenAPI spec.
* feat(api-v2): refactor event type settings to object types for future extensibility
- Convert disableRescheduling from boolean to object with disabled and minutesBefore properties
- Convert disableCancelling from boolean to object with disabled property
- Move canSendCalVideoTranscriptionEmails into CalVideoSettings as sendTranscriptionEmails
- Remove autoTranslateInstantMeetingTitleEnabled (Enterprise-only feature)
- Add DisableRescheduling_2024_06_14 and DisableCancelling_2024_06_14 input/output types
- Add transformation methods for new object types in input and output services
- Update E2E tests for new API contract
BREAKING CHANGE: disableRescheduling and disableCancelling now accept objects instead of booleans
* fix(api-v2): prevent clearing calVideoSettings when only sendTranscriptionEmails is provided
Only include calVideoSettings in transformed output if it has properties,
avoiding unintentional reset of existing settings during updates.
2026-01-07 16:03:01 +02:00
MorganGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* feat(api): add team event-types webhooks controller
- Add TeamsEventTypesWebhooksController for managing webhooks on team event types
- Add IsTeamEventTypeWebhookGuard for authorization
- Add TeamEventTypeWebhooksService for business logic
- Register new controller in TeamsEventTypesModule
- Enable unsafeParameterDecoratorsEnabled in biome.json for NestJS support
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* test(api): add e2e tests for team event-types webhooks controller
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* fix(api): restrict team event-type webhooks to admins/owners only
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* fix(api): use regular imports instead of type imports for DI and DTOs
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* fix(api): use regular imports for DI in guard file
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* fix: circular depndency in modules
* delete teams in test
* fix roles guard
* fix biome
* fix guard
* resolve type import
* resolve review feedback
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>