{"record":{"id":"2861a9ab72664cc9","repo":"calcom/cal.diy","slug":"video-integration-ctx-integrationslug-is-not","errorCode":null,"errorMessage":"Video integration \"${ctx.integrationSlug}\" is not connected. Please connect the integration in your settings first.","messagePattern":"Video integration \"(.+?)\" is not connected\\. Please connect the integration in your settings first\\.","errorType":"http","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"apps/api/v2/src/platform/bookings/2024-08-13/services/booking-location-integration.service.ts","lineNumber":195,"sourceCode":"      bookingId: ctx.existingBooking.id,\n      newReferencesToCreate: [newReference],\n    });\n\n    if (videoCallUrl) {\n      await this.calendarSyncService.syncCalendarEvent(ctx.existingBooking.id, bookingLocation);\n    }\n\n    return this.updateBookingWithVideoLocation(ctx, videoCallUrl, bookingLocation, evt);\n  }\n\n  private async handleVideoApiIntegration(ctx: IntegrationHandlerContext): Promise<BookingLocationResponse> {\n    const credential = await this.bookingVideoService.findVideoCredentialForIntegration(\n      ctx.integrationSlug,\n      ctx.booking.user?.credentials || []\n    );\n\n    if (!credential) {\n      throw new BadRequestException(\n        `Video integration \"${ctx.integrationSlug}\" is not connected. Please connect the integration in your settings first.`\n      );\n    }\n\n    await this.bookingVideoService.deleteOldVideoMeetingIfNeeded(ctx.existingBooking.id);\n\n    const evt = await this.calendarSyncService.buildCalEventFromBookingData(\n      ctx.booking,\n      ctx.internalLocation,\n      credential.id\n    );\n    const meetingResult = await createMeeting(credential, evt);\n\n    if (!meetingResult.createdEvent) {\n      this.logger.error(\n        `Failed to create video meeting with ${ctx.integrationSlug}`,\n        JSON.stringify({ success: meetingResult.success, type: meetingResult.type })\n      );","sourceCodeStart":177,"sourceCodeEnd":213,"githubUrl":"https://github.com/calcom/cal.diy/blob/176037d0afbe572f870a3c702985e7cd83fe6c0c/apps/api/v2/src/platform/bookings/2024-08-13/services/booking-location-integration.service.ts#L177-L213","documentation":"Thrown by handleVideoApiIntegration (the default branch covering Zoom, Webex, Whereby, etc.) when bookingVideoService.findVideoCredentialForIntegration returns null. That method scans the booking host's credentials for one matching the integration slug; no match means the host never connected that video app, so there is no credential to create the meeting with.","triggerScenarios":"PATCH booking location to any non-special integration slug (zoom, whereby-video, webex-video, whatsapp-video, etc.) when the booking host user has no stored credential of that type.","commonSituations":"User installed the app on a different Cal.com account; credential deleted when the user disconnected the app; OAuth token fully expired/revoked so the credential row was removed; misspelled integration slug that maps to nothing connected.","solutions":["Have the booking host connect the integration in Cal.com Settings > Apps (complete the OAuth flow).","If previously connected, reconnect to re-establish the credential after a token revocation.","Confirm the integration slug sent in the request matches a connected app (see apiToInternalintegrationsMapping for valid slugs).","Use an integration the host has actually connected, or fall back to cal-video."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Before PATCHing to a video integration, check the host has a connected credential.\nconst integrations = await api.get('/v2/connected-apps'); // or equivalent credential check\nconst connected = integrations.some((i) => i.slug === integrationSlug);\nif (!connected) throw new Error(`Integration ${integrationSlug} is not connected by the booking host`);","typeGuard":"function hasVideoCredential(credentials: { type: string }[] | null | undefined, slug: string): boolean {\n  return !!credentials && credentials.some((c) => c.type.includes(slug));\n}","tryCatchPattern":"try {\n  await api.patch(`/v2/bookings/${uid}/location`, { location: { type: 'integration', integration: slug } });\n} catch (err) {\n  if (err.status === 400 && /is not connected/.test(err.message)) {\n    // prompt the host to connect the app, or fall back to cal-video\n  }\n  throw err;\n}","preventionTips":["Ensure the booking host completes the OAuth flow for the integration before booking.","Verify the integration slug against the connected apps list (apiToInternalintegrationsMapping).","Reconnect integrations promptly when tokens are revoked."],"tags":["integration","credentials","oauth","video"],"backgroundTag":null,"analyzedSha":"176037d0afbe572f870a3c702985e7cd83fe6c0c","analyzedAt":"2026-08-12T19:12:41.464Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}