Google Meet Integration
Video conferencing escalation for employed solvers using Google Workspace
Google Meet Integration
SavvySolve supports Google Meet as a video conferencing option for employed solvers (W-2 employees). When chat and screen sharing aren't sufficient to resolve a customer's issue, employed solvers can escalate to a face-to-face video call with a single click. The system automatically generates a unique Meet link and sends it to the customer via SMS.
This integration addresses a core insight from the PRD: some technical problems require visual demonstration or screen sharing that goes beyond what our built-in tools can provide. Google Meet offers enterprise-grade video quality and reliability for these complex support scenarios.
Google Meet is only available to employed solvers (W-2) who have a Google Workspace email configured. Contract solvers (1099) use the built-in screen sharing functionality.
Solver Employment Types
SavvySolve distinguishes between two types of solvers based on their employment relationship:
export const solverEmploymentEnum = pgEnum("solver_employment", [
"employed", // W-2 employees with Google Workspace access
"contract", // 1099 contractors using built-in tools only
]);This distinction drives feature availability. Employed solvers have access to company Google Workspace accounts, which enables the Calendar API integration needed to generate Meet links programmatically. Contract solvers, operating as independent contractors, use the platform's native screen sharing capabilities instead.
The employment type is stored on the solver profile alongside their Google email:
export const solvers = pgTable("solvers", {
// ...other fields
employment: solverEmploymentEnum("employment")
.notNull()
.default("contract"),
googleEmail: varchar("google_email", { length: 255 }),
});How Meet Link Generation Works
The Meet integration uses Google Calendar API to create calendar events with attached conference data. When a solver requests a Meet link, the system creates a temporary calendar event on the solver's Google Workspace calendar, and Google automatically provisions a Meet conference room.
export async function generateMeetLink(
solverEmail: string,
customerName: string,
sessionId: string
): Promise<MeetLinkResult> {
const calendar = getCalendarClient();
const event = await calendar.events.insert({
calendarId: solverEmail,
conferenceDataVersion: 1,
requestBody: {
summary: `SavvySolve Support Session - ${customerName}`,
description: `Support session ID: ${sessionId}`,
conferenceData: {
createRequest: {
requestId: `savvysolve-${sessionId}-${Date.now()}`,
conferenceSolutionKey: {
type: "hangoutsMeet",
},
},
},
},
});
const meetLink = event.data.conferenceData?.entryPoints?.find(
(ep) => ep.entryPointType === "video"
)?.uri;
return { success: true, meetLink };
}The service account authenticates via a base64-encoded JSON key stored in the GOOGLE_SERVICE_ACCOUNT_KEY environment variable. This approach avoids storing sensitive credentials in files while allowing deployment across different environments.
Fallback Strategy
If the Calendar API fails for any reason (service outage, quota limits, misconfiguration), the system falls back to https://meet.google.com/new. This URL allows the solver to manually create a meeting room, ensuring video calls remain possible even during API issues.
export function getFallbackMeetLink(): string {
return "https://meet.google.com/new";
}tRPC API Reference
The Meet router provides two procedures for the frontend to interact with:
meet.canUseMeet
Checks whether the current solver is eligible to use Google Meet. This query runs on component mount to determine whether to render the Meet button.
canUseMeet: protectedProcedure.query(async ({ ctx }) => {
const { solver } = await getSolverForUser(ctx.auth.userId);
if (solver.employment !== "employed") {
return { canUse: false, reason: "Google Meet is only available for employed solvers" };
}
if (!solver.googleEmail) {
return { canUse: false, reason: "Google Workspace email not configured" };
}
if (!isMeetConfigured()) {
return { canUse: false, reason: "Google Meet integration not configured" };
}
return { canUse: true };
});meet.createMeetLink
Creates a new Meet link for a session, stores it in the database, broadcasts a system message via Ably, and sends the link to the customer via SMS.
Input:
sessionId(string, UUID) - The session to create a Meet link for
Response:
success(boolean) - Whether the operation completedmeetLink(string) - The generated or fallback Meet URLisExisting(boolean) - True if returning a previously created linkusedFallback(boolean) - True if the fallback URL was used
The procedure performs several validations:
- Verifies the solver is employed (W-2)
- Confirms Google email is configured
- Checks session exists and belongs to this solver
- Returns existing link if session already has one
Database Schema
Sessions store the Meet link once created:
export const sessions = pgTable("sessions", {
// ...other fields
meetLink: text("meet_link"),
});This allows the link to persist across page refreshes and enables the customer session view to display the Meet link if one exists.
Frontend Component
The MeetButton component handles the UI interaction. It only renders for employed solvers with proper configuration:
export function MeetButton({ sessionId, existingMeetLink }: MeetButtonProps) {
const { data: canUseMeet, isLoading } = trpc.meet.canUseMeet.useQuery();
const createMeetLink = trpc.meet.createMeetLink.useMutation({
onSuccess: (data) => {
if (data.meetLink) {
setMeetLink(data.meetLink);
window.open(data.meetLink, "_blank", "noopener,noreferrer");
}
},
});
// Only render if solver can use Meet
if (!canUseMeet?.canUse) return null;
// Button changes from "Start Google Meet" to "Open Meet" after creation
}The button appears in the session header alongside other session controls. When clicked for the first time, it:
- Calls the
createMeetLinkmutation - Opens the Meet link in a new tab
- The customer receives an SMS with the join link
Subsequent clicks simply reopen the existing link.
SMS Notification
When a Meet link is created, the customer receives an SMS notification:
export async function sendMeetLink(
to: string,
sessionId: string,
meetLink: string,
solverName: string
): Promise<SendSmsResult> {
const body = `${solverName} has started a video call for your support session. Join here: ${meetLink}`;
return sendSms(to, body, sessionId);
}This ensures customers without the session view open still receive the video call invitation promptly.
Configuration
Environment Variables
| Variable | Description |
|---|---|
GOOGLE_SERVICE_ACCOUNT_KEY | Base64-encoded service account JSON credentials |
Google Cloud Setup
- Create a Google Cloud project
- Enable the Google Calendar API
- Create a service account with domain-wide delegation
- Download the JSON key and base64-encode it
- Grant the service account calendar access to solver email accounts
The service account needs domain-wide delegation configured in Google Workspace Admin Console to create events on behalf of users.
Testing Strategy
The Meet integration is tested at multiple levels:
Unit tests (lib/google/meet.test.ts) verify:
- Meet link generation returns expected format
- Fallback link is returned on API failure
- Configuration detection works correctly
Router tests (server/routers/meet.test.ts) verify:
- Authorization checks for employment type
- Session ownership validation
- Existing link returns without regeneration
- Fallback behavior when API fails
The tests mock the Google Calendar API using Vitest's mocking capabilities to avoid making real API calls during CI.