CRM & External Integration
backend is the integration hub. The dominant CRM is
GoHighLevel (GHL); HubSpot, Slack, Stripe/Xero, Twilio, and several enrichment
providers are also wired in. Each integration is a service under
backend/app/services/<Name>Service.js with config in app/configs/.
GoHighLevel (GHL)
UI copy now says "LeadConnector" (frontend-wide rename); code/config keys remain
go_high_level/ghl.
The largest integration (GoHighLevelService.js, ~61 KB). It syncs contacts,
posts call/chat outcomes as notes, updates pipeline stages, triggers workflows,
and handles calendar/SMS/voice.
Mechanics:
- Inbound webhooks — contact updates / pipeline changes arrive via
goHighLevelRoutes.jsand are pushed onto a Redis-backedCrmSyncQueueService. - Outbound — cron jobs post activity back to GHL:
OutboundCallGhlSyncJob(1 min) — call transcripts → contact notes.AiCallGhlTranscriptSyncJob(5 min) — AI call transcripts + the recording attached to GHL Conversations as a playable inbound message (sendCallRecording, needs onlyconversations/message.write;.mp3URL suffix for the inline player).KnoxGhlSyncJob(nightly 03:00) — pipeline-stage sync + new-visitor backfill.- Post-call extras: outcome tags per
agent_key→post_call_tags(GhlPostCallTagsService, clobber-guarded) and a per-outbound-agentpost_call_summary_fieldcustom-field write.
- Resilience —
app/lib/ghlResilience.jswraps calls for retry/backoff. - v2 app — v2 is now the default for new installs
(
GO_HIGH_LEVEL_NEW_INSTALL_APP_VERSION=v2); token refresh stays per storedapp_version. Public marketplace-directory installs are stateless (install code handed to the SPA, agency + sub-account two-step,needs_mapping), and disconnect now fully uninstalls the app GHL-side (location, company-level, and agency installs). See GoHighLevel.
Nox also writes to GHL through its own action layer
(ms-ai knox-ghl-sync.service.ts) — see Nox Assistant.
HubSpot
HubspotService.js / PublicHubspotService.js — contact enrichment, deal-stage
sync, form submissions. Inbound via hubspotRoutes.js + webhookRoutes.js.
Slack
SlackService.js — notifications and message relay; ms-communication also does
Slack thread sync for chats (OAuth + event subscriptions with raw-body signature
verification).
Payments & accounting
Stripe (StripeService.js, checkout/billing) and Xero (XeroService.js, invoice
sync). Revenue reporting depends on paid_at being stamped on paid invoices and
currency stored per invoice.
Telephony
Twilio (calls/SMS/video, mostly via ms-communication) and ElevenLabs (AI voice,
via ms-ai).
Enrichment providers
Clearbit, Apollo, HappierLeads, Rb2b — B2B company/person data feeding the
identity graph. Tracked via ApolloRecordModel,
ClearbitSessionModel, HappierLeadsService.js, Rb2bService.js.
LeadContactSyncJob — the job that pushed enrichment-guessed contacts into
GHL/HubSpot — is disabled globally (commented out of SchedulerService).
Trade / field-service (Simpro + Tapi)
SimproService.js (connect, cost-centre mapping, in-call AI job creation, outbound
invoice-chasing) and TapiService.js (IMAP work-order emails → ms-ai field
extraction → Simpro). Phone search in Simpro must be digits-only.
SimproInvoiceChaseJob and TapiPollJob run on short cadences.
Recent: job creation now applies an AI-picked trade tag — ms-ai
POST /agents/pick-job-tags picks one best tag from the build's tag catalogue,
and the Tapi extractor accepts the tag vocabulary (an "AI-Booked" marker exists
but is disabled). ms-ai POST /elevenlabs/sync-simpro-tool keeps the voice
agent's job-booking tool config synced.
Webhooks (generic)
webhookRoutes.js + WebhookModel/WebhookLogModel/WebhookEventModel support
customer-registered outbound webhooks (HubSpot, Zapier, custom). Dualhook handles
WhatsApp onboarding (HMAC-verified). Post-call webhooks now ship
call_sentiment/transcript_text/a signed recording_url, delivery waits for
the ElevenLabs analysis with a PostCallWebhookFallbackJob exactly-once fallback,
and the new_user_identified event is revived — see
Webhooks.
ManyReach (Agent K beta)
ManyReachService.js pushes kk-tokenized prospects into a tenant's ManyReach
cold-email campaigns (routes under /knox/agent-k/manyreach/*, gated by
company.agent_k_beta_enabled); a CSV token-minting path covers any other
external sender. See ManyReach.
The sync queue pattern
Most CRM work flows through Redis-backed queues + cron sweepers rather than
synchronous calls, so a slow or failing CRM doesn't block request handling and work
is retried. Watch CrmSyncQueueService and the *GhlSyncJob family when debugging
sync gaps.