Skip to content

feat: add request reschedule API v2 endpoint#28243

Closed
PeerRich wants to merge 2 commits into
mainfrom
devin/1772485875-request-reschedule-api-v2
Closed

feat: add request reschedule API v2 endpoint#28243
PeerRich wants to merge 2 commits into
mainfrom
devin/1772485875-request-reschedule-api-v2

Conversation

@PeerRich
Copy link
Copy Markdown
Member

@PeerRich PeerRich commented Mar 2, 2026

What does this PR do?

Adds a new POST /v2/bookings/:bookingUid/request-reschedule endpoint that allows requesting a reschedule for an existing booking, with an optional rescheduleReason message. This exposes the existing tRPC requestRescheduleHandler as a REST API v2 endpoint.

The endpoint cancels the current booking and sends the attendee an email with a link to reschedule.

Changes

  • Input DTO (RequestRescheduleInput_2024_08_13): Optional rescheduleReason string field
  • Output DTO (RequestRescheduleOutput_2024_08_13): Returns { status: "success" }
  • Service method: requestReschedule() in BookingsService_2024_08_13 — validates booking exists, delegates to requestRescheduleHandler
  • Controller endpoint: POST /:bookingUid/request-reschedule with BOOKING_WRITE permission, ApiAuthGuard + BookingUidGuard
  • Platform-libraries: Re-exports requestRescheduleHandler from tRPC and reschedule email classes for use in API v2
  • E2e tests: 4 test cases covering happy path with/without reason, rejected cancelled bookings (400), and non-existent UIDs (404)

⚠️ Items for reviewer attention

  1. Type mismatch: requestRescheduleHandler expects NonNullable<TrpcSessionUser> but receives ApiAuthGuardUser. At runtime the handler only uses fields present on both types (id, email, locale, profile, uuid, username, timeZone, name, phoneNumber), but this is a compile-time type error. Note: the same pre-existing mismatch exists for confirmBookingHandler calls at lines 1232 and 1266 of the same service file.

  2. Response does not include booking data: Unlike confirm/decline which return the updated booking, this endpoint returns only { status } because the underlying handler returns void. Should we fetch and return the (now-cancelled) booking for consistency?

  3. Redundant booking lookup: The service checks the booking exists, but BookingUidGuard and the handler itself also look up the booking internally.

Mandatory Tasks (DO NOT REMOVE)

  • I have self-reviewed the code (A decent size PR without self-review might be rejected).
  • I have updated the developer docs in /docs if this PR makes changes that would require a documentation change. N/A — no doc changes needed.
  • I confirm automated tests are in place that prove my fix is effective or that my feature works.

How should this be tested?

  1. Authenticate as a user who owns a booking (API key or OAuth access token)
  2. POST /v2/bookings/{bookingUid}/request-reschedule with header cal-api-version: 2024-08-13
    • Body: { "rescheduleReason": "Need to move this meeting" } (optional)
  3. Verify response: { "status": "success" }
  4. Verify the booking status is now CANCELLED with rescheduled: true
  5. Verify the attendee receives a reschedule request email with a reschedule link
  6. Verify BOOKING_CANCELLED webhook is triggered

E2e tests included:

  • Request reschedule with a reason → 200, booking cancelled with reason stored
  • Request reschedule without a reason → 200, booking cancelled
  • Request reschedule on already-cancelled booking → 400
  • Request reschedule on non-existent UID → 404

Checklist

  • I have read the contributing guide
  • My code follows the style guidelines of this project
  • I have commented my code, particularly in hard-to-understand areas
  • I have checked if my changes generate no new warnings (note: pre-existing type warnings in this file)
  • My PR is appropriately sized (8 files changed, 368 insertions)

Link to Devin Session: https://app.devin.ai/sessions/34dc36cca5a14662911130c2ea689d94
Requested by: @PeerRich

Add POST /v2/bookings/:bookingUid/request-reschedule endpoint that allows
requesting a reschedule for an existing booking with an optional reason message.

- Create RequestRescheduleInput_2024_08_13 DTO with optional rescheduleReason field
- Create RequestRescheduleOutput_2024_08_13 output type
- Add requestReschedule service method in BookingsService_2024_08_13
- Add controller endpoint with proper guards and Swagger docs
- Re-export requestRescheduleHandler from platform-libraries
- Export new input from platform-types index

Co-Authored-By: peer@cal.com <peer@cal.com>
@devin-ai-integration
Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI' or '@devin'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

Copy link
Copy Markdown
Contributor

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

Choose a reason for hiding this comment

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

No issues found across 6 files

- Test request reschedule with a reason message
- Test request reschedule without a reason
- Test that cancelled bookings cannot be rescheduled (400)
- Test that non-existent booking UIDs return 404
- Export reschedule email classes from platform-libraries for mocking

Co-Authored-By: peer@cal.com <peer@cal.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants