Scheduling integrations do not usually break on the first request.
They break after the booking exists.
The user gets an email. The host has Google Calendar connected. Your app sends its own ICS file. Then somebody reschedules or cancels and suddenly there are two calendar events, or one event refuses to disappear.
That is not a generic "calendar APIs are hard" problem.
It is a workflow identity problem.
The specific workflow
The narrow Cal.com flow I care about is:
- Get available slots
- Create a booking
- Fetch the booking
- Reschedule it
- Cancel it
- Verify the calendar and webhook side effects still point at the same booking
In API terms, the happy path looks like this:
GET /v2/slots
POST /v2/bookings
GET /v2/bookings/{bookingUid}
POST /v2/bookings/{bookingUid}/reschedule
POST /v2/bookings/{bookingUid}/cancel
That is the test.
Not just "can I create a booking?"
The real question is:
slot -> booking -> calendar event -> reschedule -> cancel
Do all of those still refer to the same thing?
The bug shape
Here is the kind of bug this flow catches.
Your app creates a booking through Cal.com. The attendee has a connected Google Calendar. Cal.com syncs the event into Google.
But your app also sends custom emails with its own ICS attachment.
If the ICS UID from the Booking API and the synced Google Calendar event identity do not line up, the user can end up with two events:
event from Cal.com sync
event from your custom ICS invite
Then cancellation gets messy because your app cancels one identity while the other one remains in the calendar.
This is the kind of integration bug that is easy to miss if you only test POST /bookings in isolation.
What I would assert
For a scheduling API, I want the test to preserve identity across the whole lifecycle.
The assertions should be closer to this:
booking created -> booking uid exists
calendar reference exists -> external event id is attached
reschedule uses same booking identity
cancel removes or updates the same calendar event
webhook events describe the same lifecycle
And if your product sends custom ICS files, there is one extra check:
Booking API iCalUID matches the calendar event your user will update/cancel
That last part is where teams usually learn the hard way that a "successful booking" does not mean a safe scheduling integration.
Why static mocks miss it
A static mock can return:
POST /bookings -> 201
That is not enough.
It cannot easily prove that a later reschedule call still points at the booking created two steps earlier. It cannot prove that your cancellation code is updating the same calendar event your invite email created. It cannot prove that webhook handlers and calendar references agree about the booking identity.
The state between calls is the product.
Where FetchSandbox fits
FetchSandbox has a Cal.com sandbox flow for the booking lifecycle:
https://fetchsandbox.com/cal-com/test-booking-lifecycle-locally
The broader Cal.com sandbox is here:
https://fetchsandbox.com/cal-com
The workflow is intentionally narrow because that is where integration bugs hide: slots, booking creation, booking lookup, reschedule, cancel, and the events around those changes.
You can also connect your IDE to FetchSandbox through MCP:
{
"mcpServers": {
"fetchsandbox": {
"command": "npx",
"args": ["-y", "fetchsandbox-mcp"]
}
}
}
Then ask an agent something like:
Use FetchSandbox MCP to run the Cal.com booking lifecycle workflow.
Explain which identifiers my app should preserve across create, reschedule, cancel, and calendar sync.
That is the direction I think API testing should move:
not just docs,
not just static responses,
but runnable workflow behavior from inside the developer's own environment.
For Cal.com-style integrations, the useful question is simple:
Can my app create, move, and cancel a booking without leaving calendar ghosts behind?
That should be testable before production users find it.
Top comments (0)