deploy: harden lead and call notification delivery

This commit is contained in:
DMleadgen 2026-04-20 19:54:10 -06:00
parent 656b78bf8e
commit 78ddcb9146
Signed by: matt
GPG key ID: C2720CF8CD701894
3 changed files with 50 additions and 22 deletions

View file

@ -36,16 +36,31 @@ export async function POST(request: Request) {
const url = new URL(request.url) const url = new URL(request.url)
const summaryText = buildPhoneCallSummary(detail) const summaryText = buildPhoneCallSummary(detail)
const notificationResult = await sendPhoneCallSummaryEmail({ let notificationResult:
detail: { | { status: "pending" | "sent" | "failed" | "disabled"; error?: string }
...detail, | undefined
call: {
...detail.call, try {
summaryText, notificationResult = await sendPhoneCallSummaryEmail({
detail: {
...detail,
call: {
...detail.call,
summaryText,
},
}, },
}, adminUrl: url.origin,
adminUrl: url.origin, })
}) } catch (notificationError) {
console.error("Failed to send phone call summary email:", notificationError)
notificationResult = {
status: "failed",
error:
notificationError instanceof Error
? notificationError.message
: "Unknown phone call notification error.",
}
}
const result = await fetchMutation(api.voiceSessions.completeSession, { const result = await fetchMutation(api.voiceSessions.completeSession, {
sessionId: detail.call.id, sessionId: detail.call.id,
@ -58,10 +73,13 @@ export async function POST(request: Request) {
? String(body.recordingError) ? String(body.recordingError)
: undefined, : undefined,
summaryText, summaryText,
notificationStatus: notificationResult.status, notificationStatus: notificationResult?.status || "failed",
notificationSentAt: notificationSentAt:
notificationResult.status === "sent" ? Date.now() : undefined, notificationResult?.status === "sent" ? Date.now() : undefined,
notificationError: notificationResult.error, notificationError:
notificationResult?.status === "sent"
? undefined
: notificationResult?.error || "Phone call notification did not run.",
}) })
return NextResponse.json({ return NextResponse.json({

View file

@ -1,6 +1,19 @@
const GHL_API_BASE = "https://services.leadconnectorhq.com" const GHL_API_BASE = "https://services.leadconnectorhq.com"
const GHL_API_VERSION = "2021-07-28" const GHL_API_VERSION = "2021-07-28"
export function getGhlApiToken() {
return (
process.env.GHL_PRIVATE_INTEGRATION_TOKEN ||
process.env.GHL_API_TOKEN ||
""
).trim()
}
export function isGhlConfigured() {
const locationId = (process.env.GHL_LOCATION_ID || "").trim()
return Boolean(locationId && getGhlApiToken())
}
export async function createGHLContact(data: { export async function createGHLContact(data: {
email: string email: string
firstName?: string firstName?: string
@ -10,8 +23,8 @@ export async function createGHLContact(data: {
source?: string source?: string
tags?: string[] tags?: string[]
}) { }) {
const locationId = process.env.GHL_LOCATION_ID const locationId = (process.env.GHL_LOCATION_ID || "").trim()
const apiToken = process.env.GHL_API_TOKEN const apiToken = getGhlApiToken()
if (!locationId || !apiToken) { if (!locationId || !apiToken) {
console.warn("GHL credentials incomplete; skipping contact creation.") console.warn("GHL credentials incomplete; skipping contact creation.")

View file

@ -11,7 +11,7 @@ import {
sendTransactionalEmail, sendTransactionalEmail,
TO_EMAIL, TO_EMAIL,
} from "@/lib/email" } from "@/lib/email"
import { createGHLContact } from "@/lib/ghl" import { createGHLContact, isGhlConfigured } from "@/lib/ghl"
import { import {
createSmsConsentPayload, createSmsConsentPayload,
isValidConsentTimestamp, isValidConsentTimestamp,
@ -143,16 +143,10 @@ function getConfiguredTenantDomains() {
} }
function defaultDeps(): LeadSubmissionDeps { function defaultDeps(): LeadSubmissionDeps {
const ghlSyncEnabled = String(process.env.ENABLE_GHL_SYNC || "")
.trim()
.toLowerCase() === "true"
return { return {
storageConfigured: isConvexConfigured(), storageConfigured: isConvexConfigured(),
emailConfigured: isEmailConfigured(), emailConfigured: isEmailConfigured(),
ghlConfigured: ghlConfigured: isGhlConfigured(),
ghlSyncEnabled &&
Boolean(process.env.GHL_API_TOKEN && process.env.GHL_LOCATION_ID),
ingest: ingestLead, ingest: ingestLead,
updateLeadStatus: updateLeadSyncStatus, updateLeadStatus: updateLeadSyncStatus,
sendEmail: (to, subject, html, replyTo) => sendEmail: (to, subject, html, replyTo) =>
@ -635,6 +629,9 @@ export async function processLeadSubmission(
} }
} else { } else {
deps.logger.warn("GHL credentials incomplete; skipping Rocky GHL sync.") deps.logger.warn("GHL credentials incomplete; skipping Rocky GHL sync.")
warnings.push(
"GHL sync skipped: set GHL_PRIVATE_INTEGRATION_TOKEN (preferred) or GHL_API_TOKEN with GHL_LOCATION_ID."
)
} }
if (leadId) { if (leadId) {