Thanks for the report, the symptom, the location-type A/B, and the repro all held up exactly as written, and you pointed us at the right file.
The bug is confirmed, but the discriminator isn't what's breaking it. Calendly sends location.type: "zoom", so the existing z.literal('zoom') matches — we verified this from the raw union error on real failing bookings, where every non-Zoom member reports "received": "zoom". zoomConferenceSchema is the member that passes the type check, then fails on two fields inside data:
- data.id is typed z.string(), but Zoom meeting IDs arrive as a number
- data.extra.intl_numbers_url is .optional(), but Calendly sends it as null (.optional() allows absent, not null)
Either failure collapses the union, and since location is required the whole payload is rejected and the event dropped. This is also why your phone-call case passed — those schemas have no data object, so neither field is reached.
So we won't merge the 'zoom' → 'zoom_conference' swap as-is: it leaves the two data fields broken, and replacing the literal would break the spelling we have live payloads for. Your point about the naming inconsistency is still worth covering, so we're accepting both:
type: z.enum(['zoom', 'zoom_conference']),
id: z.union([z.string(), z.number()]).optional(),
intl_numbers_url: z.string().url().nullish(),
Next steps: the engineering team is aware of the issue and will be in charge of fixing it. You'll need to update the integration on your bot once it's published, it won't apply to your installed version automatically. We'll comment here when it ships so you can verify against your own bookings.
If you can share your workspace or bot ID, we'll validate against your specific payloads before shipping. And if yours do send zoom_conference, that payload would be useful to see, but the z.enum covers it either way.