import redis from '../redis.js'; import { getCredential, WhatsAppCredentials } from './credential-store.js'; // Call this at customer onboarding when they connect their WhatsApp Business number export async function registerWhatsAppNumber( customerId: string, phoneNumberId: string ): Promise { await redis.set(`wa_phone_id:${phoneNumberId}`, customerId); } export async function unregisterWhatsAppNumber(phoneNumberId: string): Promise { await redis.del(`wa_phone_id:${phoneNumberId}`); } export async function resolveCustomerFromPhoneNumberId( phoneNumberId: string ): Promise { return redis.get(`wa_phone_id:${phoneNumberId}`); } // WhatsApp Cloud API webhook payload types interface WhatsAppWebhookEntry { id: string; changes: Array<{ value: { messaging_product: string; metadata: { display_phone_number: string; phone_number_id: string; }; messages?: WhatsAppInboundMessage[]; statuses?: WhatsAppStatus[]; }; field: string; }>; } export interface WhatsAppInboundMessage { from: string; id: string; timestamp: string; text?: { body: string }; type: string; } interface WhatsAppStatus { id: string; status: string; timestamp: string; recipient_id: string; } export interface RoutedWebhookEvent { customerId: string; phoneNumberId: string; message: WhatsAppInboundMessage; credentials: WhatsAppCredentials; } // Parse the incoming webhook and return one routed event per message export async function routeWhatsAppWebhook( body: Record ): Promise { const events: RoutedWebhookEvent[] = []; if (body.object !== 'whatsapp_business_account') return events; const entries = (body.entry as WhatsAppWebhookEntry[]) ?? []; for (const entry of entries) { for (const change of entry.changes) { if (change.field !== 'messages') continue; const { phone_number_id } = change.value.metadata; const messages = change.value.messages ?? []; if (messages.length === 0) continue; // Resolve which customer owns this phone number const customerId = await resolveCustomerFromPhoneNumberId(phone_number_id); if (!customerId) { console.warn(`[webhook-router] Unroutable WhatsApp message to phone_number_id=${phone_number_id}`); continue; } // Load that customer's WhatsApp credentials const credentials = await getCredential(customerId, 'whatsapp'); if (!credentials) { console.error(`[webhook-router] No WhatsApp credentials for customerId=${customerId}`); continue; } for (const message of messages) { events.push({ customerId, phoneNumberId: phone_number_id, message, credentials }); } } } return events; }