GHL Import Workflow
Step-by-step guide for importing prospect data from GoHighLevel into Client Portal and syncing it back to GHL for outbound calling.
Overview
The GHL import flow moves data in both directions:
Step 1: CSV Import
Upload a prospect CSV file via the admin UI at /admin/sales/ghl-import/:batchId.
Expected CSV columns:
- Company name, contact name, email, phone, title
- LinkedIn URL (optional)
- Source and notes (optional)
The upload creates a new import batch and inserts all rows into the ghl_import_staging table with status = 'pending'.
Step 2: Staging Review
Once uploaded, records land in ghl_import_staging. The admin UI shows:
- Matched records -- Records that match existing
sales_prospectsby email or phone - Unmatched records -- New prospects not yet in the system
- Duplicate records -- Records that duplicate other rows in the same batch
Review each record and resolve any conflicts before approving.
Step 3: Approve Records
Approved records are converted into sales_prospects entries. This creates the prospect in the Client Portal database with:
engagement_levelset tonewsourceset to the import batch source- All contact fields mapped from the staging record
Rejected records remain in staging with status = 'rejected' for audit purposes.
Step 4: GHL Sync
The sync-prospects-to-ghl edge function pushes unsynced prospects to the GoHighLevel API.
What it does:
- Queries
sales_prospectswhereghl_contact_id IS NULLandghl_location_id IS NOT NULL - For each prospect, creates a GHL contact via the GHL API
- Maps custom fields using
ghl_integrations.custom_field_mapping - On success, updates the prospect with:
ghl_contact_id-- The GHL contact identifierghl_synced_at-- Timestamp of the syncghl_location_id-- The GHL location/account
GHL API details:
- Base URL:
https://services.leadconnectorhq.com - API Version:
2021-07-28 - Auth: Bearer token from
ghl_integrations.api_token
Trigger sync manually:
curl -X POST \
https://<supabase-url>/functions/v1/sync-prospects-to-ghl \
-H "Authorization: Bearer <service-role-key>"
Step 5: Webhook Auto-Logging
Once prospects exist in GHL, calls made through GHL automatically log back to Client Portal via webhooks.
Webhook flow:
- GHL fires webhook on call completion (fires 2 hits per call -- Call Completed + Disposition workflows)
ghl-call-webhookorghl-sales-webhookreceives the payload- Deduplication check on
external_call_idprevents double-insertion - Call record created in
sales_callswith disposition inferred from transcript/notes - If transcript is longer than 100 characters,
summarize-sales-callis auto-triggered - Claude AI generates a summary, sets
disposition,engagement_level, andnext_follow_up_at
See Call Ingestion Flow for full details on webhook processing and AI summarization.
GHL Integration Configuration
Each GHL account is configured in the ghl_integrations table:
| Column | Purpose |
|---|---|
location_id | GHL location/account identifier |
api_token | Bearer token for GHL API authentication |
custom_field_mapping | JSON mapping of Client Portal fields to GHL custom fields |
Campaigns link to GHL accounts via sales_campaigns.ghl_location_id.
Troubleshooting
| Problem | Likely Cause | Fix |
|---|---|---|
| Sync fails silently | Invalid or expired api_token | Refresh token in ghl_integrations |
| Duplicate calls appearing | Dedup not working | Check external_call_id is being sent in webhook payload |
| Custom fields not mapping | Mapping mismatch | Verify custom_field_mapping JSON matches GHL field IDs |
| Prospects not syncing | Missing ghl_location_id | Ensure campaign has ghl_location_id set |
See Debugging GHL Issues for more detail.