This is about creating a Voice Agent AI, that helps users, and connects them to appropriate resources in Utah REIA
BusinessJavaScript · HTMLGitHub @UtahREIAOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full README ↗AI-powered voice assistant for Utah's largest real estate investor association. Routes investors to the right vendors, educators, and resources through live voice calls, readiness surveys, and investor profile matching.
| Resource | URL |
|---|---|
| Voice Agent Page | https://utahreia.org/voice-agent-ai-page |
| Vercel Deployment | https://voice-agent-ai-nu.vercel.app |
| Property Listings | https://utahreia.org/property-listing |
Caller → index.html (GHL Funnel)
├── /api/context — loads liveContext (vendors, educators, events, tools)
├── /api/member-lookup — checks if returning member, injects profile + last call
└── Vapi Web SDK (ESM from CDN: @vapi-ai/[email protected])
│
▼
Vapi Assistant (claude-haiku-4-5)
│
┌──────────┼──────────┐
│ │ │
/api/intake /api/vendors /api/education
/api/caller-history
│
▼
/api/ghl-sync (post-call)
┌──────────┼──────────┐
│ │ │
Supabase GHL Webhook GHL v2 API
voice_agent (workflow) (custom fields)
_calls
Voice-Agent-AI/
├── api/
│ ├── context.js # Pre-call liveContext loader — queries ghl_upcoming_events for strategy-matched events
│ ├── member-lookup.js # Returning member recognition by phone — returns profile + last_call data
│ ├── intake.js # Map 1 routing — stage/strategy/blocker classification
│ ├── vendors.js # Map 2 vendor matching with haversine zip code filtering
│ ├── education.js # Map 3 education track matching
│ ├── caller-history.js # Past call history for returning callers (mid-call tool)
│ ├── ghl-sync.js # Post-call pipeline — Supabase + GHL sync + vendor notification payload
│ ├── member-history.js # Deep history lookup (tools, events, profile)
│ ├── member-profile.js # Mid-call member lookup tool (fallback if phone not entered pre-call)
│ ├── sync-ghl-objects.js # Dual handler: POST = GHL webhook receiver, GET = nightly event sync
│ ├── sync-educator.js # Educator sync to ghl_educators_mentors
│ ├── supabase.js # Supabase client helper
├── .github/
│ └── workflows/
│ └── sync-ghl-objects.yml # GitHub Actions backup sync (runs nightly at 9:15 PM MDT)
├── public/
│ ├── index.html # Voice agent widget (live agent)
│ ├── index-new.html # Voice agent widget (V2 agent)
│ └── dashboard.html # Chris metrics dashboard
├── index.html # Voice agent widget page
├── vercel.json # Vercel deployment config
├── package.json # Must include "type": "module" for ESM support on Vercel
└── README.md
| Resource | Value |
|---|---|
| Supabase Project ID | kttzxjddtkgsitzehiid |
| Supabase URL | https://kttzxjddtkgsitzehiid.supabase.co |
| GHL Location ID | DNirEjy0ejVwbHsaBYrn |
| Vapi Assistant ID | 92018c4f-f382-41b9-80e0-c46e8f2b505a |
| Vapi Voice | ElevenLabs Xi53u0N6awPQcGCxrwD3 (Harmonie Borden clone) |
| Vapi Server URL | https://voice-agent-ai-nu.vercel.app/api/ghl-sync |
| Vapi End Call Message | Mahalo. |
Model: claude-haiku-4-5-20251001 | Max Tokens: 150
Tools (all synchronous — async OFF):
| Tool | Endpoint | Purpose |
|---|---|---|
getIntakeRouting | /api/intake | Map 1 — classifies investor, returns routing action |
getVendorMatch | /api/vendors | Map 2 — matches vendors by need + zip distance |
getEducationMatch | /api/education | Map 3 — matches education track + educator |
getCallerHistory | /api/caller-history | Returns past call history for returning callers |
endCall | Built-in | Ends the call. End Call Message set to "Mahalo." |
Structured Outputs (22 fields):
callerName, callerEmail, callerPhone, profileType, investorStage, strategies, blocker, goals, summary, recommendedNextStep, tier, vendorMatches, toolMatches, educatorMatch, bookingRequired, alreadyTried, handoffChannel, stackSummary, commercialAssetTypes, wantsMentorConnection, wantsProfessionalConnections, wantsOffMarketDeals
/api/context loads liveContext (vendors, educators, courses, tools, events with strategy tags, property listing URL)/api/member-lookup checks if the number matches a contact in SupabasefirstMessage is set dynamically:
@vapi-ai/[email protected]), with fallbacksMeaningful call filter (member-lookup.js):
Skips calls with stack_summary containing: "no recommendations", "intake was in progress", "ended before", "call ended", "not delivered", "unable to", "no result", "did not complete", "incomplete". Only picks calls with a clean summary > 30 chars, matched educator, or matched vendors.
All routing uses live Supabase tables — no hardcoded logic in JS files.
This is the beginning of the README. Read the rest at the original. Read the full README ↗