Skip to main content

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_prospects by 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_level set to new
  • source set 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:

  1. Queries sales_prospects where ghl_contact_id IS NULL and ghl_location_id IS NOT NULL
  2. For each prospect, creates a GHL contact via the GHL API
  3. Maps custom fields using ghl_integrations.custom_field_mapping
  4. On success, updates the prospect with:
    • ghl_contact_id -- The GHL contact identifier
    • ghl_synced_at -- Timestamp of the sync
    • ghl_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:

  1. GHL fires webhook on call completion (fires 2 hits per call -- Call Completed + Disposition workflows)
  2. ghl-call-webhook or ghl-sales-webhook receives the payload
  3. Deduplication check on external_call_id prevents double-insertion
  4. Call record created in sales_calls with disposition inferred from transcript/notes
  5. If transcript is longer than 100 characters, summarize-sales-call is auto-triggered
  6. Claude AI generates a summary, sets disposition, engagement_level, and next_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:

ColumnPurpose
location_idGHL location/account identifier
api_tokenBearer token for GHL API authentication
custom_field_mappingJSON mapping of Client Portal fields to GHL custom fields

Campaigns link to GHL accounts via sales_campaigns.ghl_location_id.

Troubleshooting

ProblemLikely CauseFix
Sync fails silentlyInvalid or expired api_tokenRefresh token in ghl_integrations
Duplicate calls appearingDedup not workingCheck external_call_id is being sent in webhook payload
Custom fields not mappingMapping mismatchVerify custom_field_mapping JSON matches GHL field IDs
Prospects not syncingMissing ghl_location_idEnsure campaign has ghl_location_id set

See Debugging GHL Issues for more detail.