CRM Relational Mesh: Building Bidirectional Contact Relationships in GoHighLevel
Key Results
- 13 bidirectional relationship types automated (Family, Professional, Community, Care)
- POC delivered in 1 day with 7/7 test scenarios passing
- 45 CRM platforms evaluated to find the optimal architecture
- Bridge architecture saved client from $10,000+/year CRM migration
The Challenge
ZCARE Medicare Agency has over 1,600 contacts, and the relationships between them are complicated. A single doctor might be connected to 50+ patients. A family unit might include a spouse, adult children, a caregiver, and someone holding power of attorney — each one a separate contact record with a distinct relationship to the policyholder. The agency tracks 13 different relationship types across four categories: Family, Professional, Community, and Care.
GoHighLevel (GHL), their primary CRM, can’t do this. There’s no native way to link contacts with many-to-many relationships. You can’t pull up a contact and see their spouse, their doctor, their caregiver, their agent — all on one screen. The agency’s previous CRM, RadiusBob ($170/month), had relationship features but no API access, which meant the data was locked inside.
What they needed sounds simple but isn’t: when you mark Contact A as Contact B’s spouse, that same relationship should show up automatically on Contact B’s record. Without that two-way sync, the team would have to create every single relationship twice. With 1,600+ contacts, that’s a recipe for missed connections and inconsistent data.
The Solution
I built a bidirectional relational mesh — n8n for orchestration, Supabase for the relationship database, and GoHighLevel as the front end. The approach adds relationship capabilities on top of GHL instead of replacing it.
Supabase holds the relationship graph in three tables: contacts, relationships, and relationship types. n8n workflows watch GoHighLevel for relationship changes via custom fields and webhooks, then sync those changes both directions. Custom fields in GHL display the relationship data right on the contact record, so the team doesn’t need to leave their CRM.
The trickiest engineering problem was preventing infinite loops. When Contact A gets linked to Contact B, the system creates the reciprocal link on B. But that update to B could trigger another sync back to A, which triggers another sync to B, and so on forever. I solved this with two safeguards: source tagging (every sync event carries an origin tag) and a 10-second timestamp threshold (any change within 10 seconds of a sync gets recognized as system-generated and ignored).
Before writing a single line of code, I spent time evaluating 45 CRM platforms across five price tiers. The question was straightforward: would moving to a different CRM solve this problem more simply? I looked at everything from Salesforce down to niche Medicare tools. The answer: nothing under $10,000/year offered the right mix of relationship management, automation capability, and pricing. Building a bridge on top of GHL was the smarter move.
The Implementation
I had a working proof of concept within one day. It passed all 7 test scenarios: creating a relationship, confirming the reciprocal appears automatically, changing a relationship type, deleting from either side, and handling simultaneous edits.
Each GHL contact gets 6 custom fields for relationship data. The n8n workflow reads these fields, looks up the linked contact in Supabase, creates or updates the relationship record, and writes the reciprocal back to the other contact. The full round-trip — someone adds a relationship on one contact, the reciprocal shows up on the other — takes under 5 seconds.
The 13 relationship types cover the full range of Medicare contact networks:
- Family: Spouse, Parent/Child, Sibling, Extended Family
- Professional: Doctor/Patient, Agent/Client, Attorney/Client
- Community: Neighbor, Church Member, Friend, Referral Source
- Care: Caregiver/Care Recipient, POA Holder/Principal
I ran into two GHL platform limits that forced architectural decisions. First, the Associations API caps out at 10 association types. The agency needs 13+, so the extras have to route through custom fields rather than native associations. Second, GHL doesn’t allow iframe embedding in contact card widgets, which killed the idea of an embedded React dashboard for visualizing relationships.
The CRM evaluation was a separate deliverable. I compiled a detailed report on all 45 platforms — pricing, features, API capabilities, relationship support. I gave it to the client for free as part of the advisory engagement. Sometimes the most valuable thing you can tell a client is “don’t migrate.”
The Results
This project was part technical build, part strategic advisory, and part scope management (the client tried to expand scope three times — we kept it focused).
- 13 relationship types work bidirectionally — add a relationship on one contact, the reciprocal appears on the other within seconds
- POC in one day, 7 out of 7 test scenarios passing. That validated the architecture before committing to the full build
- 45 CRM platforms evaluated in a detailed market analysis. The research alone saved the agency from an expensive migration that wouldn’t have solved their problem
- The bridge approach kept their GHL investment intact and added the specific capability they were missing. No $10,000+/year licensing bill for a new CRM
- Loop prevention works — tested against rapid sequential edits, bulk imports, and concurrent users
I’m not going to pretend this was purely an altruistic call. But recommending against a profitable migration project — and backing that recommendation with a 45-platform analysis — built more trust than any sales pitch could. The client knows I’ll tell them the truth about what they need, even when the truth is “keep what you have and build a targeted fix.”
This is an ongoing engagement. The relational mesh is live for Phase 1. Next up: relationship visualization dashboards and a deeper RadiusBob data migration as the agency grows.