This page shows the complete data flow for every Sympana operation. If you’re unsure why a field is empty, which variable to use, or where data lives — start here.Documentation Index
Fetch the complete documentation index at: https://docs.sympana.com/llms.txt
Use this file to discover all available pages before exploring further.
Voice call data flow
Outbound call: GHL → Sympana → Voice Provider → GHL
GHL workflow reaches Place Call action
extras.locationId— which GHL locationextras.contactId— which contact to calldata.connection_id— which Sympana connection to usedata.contact_phone— the phone number to calldata.contact_name— the contact’s full namedata.contact_first_name,data.contact_last_name,data.contact_email
Sympana resolves everything
- Finds the GHL installation for that location
- Loads the selected voice connection
- Verifies the connection is active
- Loads the Retell or Vapi API key
- Chooses the phone number (or uses Smart Selection rotation)
- Resolves dynamic variables (contact fields, custom fields, static values)
- Loads enabled functions for the connection
Sympana sends call to voice provider
- From number (your outbound number)
- To number (contact’s phone)
- Agent/assistant ID
- Dynamic variables (injected into the agent prompt)
- Function definitions (what tools the agent can use)
- Webhook URL (where the provider sends results)
AI agent has the conversation
Call ends, provider sends webhook
- Call ID, status, direction
- Full transcript
- Recording URL
- Call duration
- Disconnection reason
- Call summary and sentiment (AI-generated)
- Custom analysis data (if post-call analysis is configured)
Where to find voice data in GHL workflows
After the Call Completed trigger fires, all data is available undertriggerData. Here are the field paths you use in GHL workflow actions:
Most commonly used fields
| GHL field path | What it contains | Example value |
|---|---|---|
triggerData.call_summary | AI summary of the call | ”Customer confirmed interest in the premium plan” |
triggerData.call_transcript | Full word-for-word transcript | ”Agent: Hi John…” |
triggerData.sentiment | Caller sentiment | ”Positive”, “Negative”, “Neutral” |
triggerData.call_successful | Whether the call achieved its goal | true / false |
triggerData.user_spoke | Whether a real person answered (false = voicemail) | true / false |
triggerData.call_duration | Call length in seconds | 180 |
triggerData.call_details.recording_url | Link to the call recording | URL |
triggerData.call_details.disconnection_reason | Why the call ended | ”customer_hung_up”, “voicemail_reached” |
triggerData.call_details.direction | Inbound or outbound | ”outbound” |
Contact fields
| GHL field path | What it contains |
|---|---|
triggerData.contactId | GHL contact ID |
triggerData.customer_name | Full name |
triggerData.contact_first_name | First name |
triggerData.contact_last_name | Last name |
triggerData.phone | Contact phone |
triggerData.email | Contact email |
Custom analysis fields
If your voice agent extracts structured data (configured in Retell post-call analysis), it appears in multiple formats:| GHL field path | Format | Best for |
|---|---|---|
triggerData.custom_analysis_json | JSON string | Storing in a custom field |
triggerData.custom_analysis_text | Human-readable text | Adding to notes or SMS |
triggerData.custom_analysis_flat | Flat key-value pairs | Branching with If/Else on specific values |
triggerData.custom_analysis_data | Original structure | Advanced processing |
Agent and call metadata
| GHL field path | What it contains |
|---|---|
triggerData.call_id | Unique call identifier |
triggerData.agent_name | Sympana connection name |
triggerData.retell_agent_name | Provider agent name |
triggerData.call_analysis_json | Full provider analysis as JSON |
triggerData.call_details.provider | ”retell” or “vapi” |
triggerData.call_details.from_phone | Number the call was placed from |
triggerData.call_details.to_phone | Number that was called |
triggerData.call_details.completed_at | ISO timestamp of call end |
triggerData.identity_status | How the contact was matched |
Messaging data flow
Inbound message: Contact → GHL → Sympana → AI → GHL
Contact sends a message
Sympana fires Message Received trigger
GHL workflow processes
- Check channel filters (SMS only? WhatsApp only?)
- Check contact tags (has
ai_msg_enabled?) - If conditions pass → Send AI Message action
Sympana processes the AI message
- Loads the selected messaging connection
- Checks Contact Access rules (allowed/blocked/handoff tags)
- Checks if the conversation is paused or handed off
- Checks for opt-out keywords
- Calls Retell or Vapi chat with the message + dynamic variables
- Gets the AI response
Where to find messaging data in GHL workflows
Message Received trigger fields
| GHL field path | What it contains | Example |
|---|---|---|
triggerData.contactId | GHL contact ID | ”abc123” |
triggerData.phone | Contact phone number | ”+15551234567” |
triggerData.customer_name | Contact full name | ”John Doe” |
triggerData.contact_first_name | First name | ”John” |
triggerData.contact_last_name | Last name | ”Doe” |
triggerData.channel | Message channel | ”sms”, “whatsapp”, “instagram”, “facebook”, “webchat”, “email” |
triggerData.message_body | The message text | ”I’d like to schedule an appointment” |
triggerData.conversation_id | GHL conversation ID | ”conv_xyz” |
triggerData.message_id | Message ID | ”msg_abc” |
triggerData.connection_name | Sympana connection name | ”SMS Support Agent” |
Handoff Requested trigger fields
| GHL field path | What it contains |
|---|---|
triggerData.contactId | GHL contact ID |
triggerData.phone | Contact phone |
triggerData.customer_name | Contact name |
triggerData.channel | Which channel |
triggerData.handoff_reason | Why handoff was triggered |
triggerData.handoff_keyword_matched | The keyword that matched |
triggerData.last_message | The message that triggered handoff |
triggerData.conversation_id | GHL conversation ID |
triggerData.connection_name | Sympana connection name |
triggerData.message_count | Total messages in the conversation |
triggerData.ai_reply_count | How many AI replies were sent |
Function data flow
When the AI agent uses a function during a call or message conversation:Where data is stored
| Data | Where it lives |
|---|---|
| Call recordings | Voice provider (Retell/Vapi) — access via recording_url |
| Call transcripts | Passed through Call Completed trigger — not stored by Sympana |
| Call metadata | Sympana calls table + voice provider dashboard |
| GHL contact data | GoHighLevel — accessed through Get Contact function |
| Appointments | GoHighLevel calendars — managed through appointment functions |
| Message history | GHL Conversations — Sympana sends AI replies through GHL |
| Trigger events | Sympana ghl_trigger_events table (for debugging) |
| OAuth tokens | Sympana vault (encrypted) |
Common field path mistakes
Using 'transcript' instead of 'call_transcript'
Using 'transcript' instead of 'call_transcript'
triggerData.call_transcript, not triggerData.transcript. If your GHL action shows an empty value, check the exact field path.Using 'summary' instead of 'call_summary'
Using 'summary' instead of 'call_summary'
triggerData.call_summary, not triggerData.summary.Accessing recording_url at the wrong level
Accessing recording_url at the wrong level
triggerData.call_details.recording_url, NOT triggerData.recording_url.Custom analysis is empty
Custom analysis is empty
custom_analysis_* fields will be empty.user_spoke is false on completed calls
user_spoke is false on completed calls
user_spoke = false means the call went to voicemail. The call still “completed” — the voicemail just played. Use user_spoke to distinguish real conversations from voicemails.
