Client concerns were missed
Messages could arrive without a consistent record or follow-through process.
Built entirely in GoHighLevel
I created a support ticket system that gives every client concern a visible owner, a clear status, and an automated path to resolution.
The challenge
Concerns were coming in, but there was no shared board, no consistent ownership, and no reliable way to make sure every issue was followed through.
Messages could arrive without a consistent record or follow-through process.
There was no single view of open concerns, their status, or who was responsible.
I built a structured board with ownership, stages, notifications, and automated updates.
The process
The detailed workflow steps are documented further down. This view shows the operating logic: how a request enters, how GHL decides what to do, what the board stages control, and how replies reconnect to the right ticket.
Intake
GHL creates or matches the contact, captures the concern, and starts the Intake router.
Decision
Add the message to the existing ticket, notify its owner, send Email 5, and move it to In Progress if it was waiting.
Generate a ticket number, create a new opportunity, copy the form fields, send Email 1, then tag and route it.
Board
Reply handling
The Reply handler locates the latest Support ticket, returns it to In Progress when appropriate, and alerts the assigned owner.
Inside GoHighLevel
The system is built from native GHL objects: one pipeline, two field sets, one form, five emails, and eight focused workflows. Each piece has one clear job.
Opportunities
The opportunity is the ticket and its stage is the status.
Contact fields
The form writes here first, then the New sequence copies the data to the opportunity.
Opportunity fields
Every ticket keeps its own information, even when the same client submits again.
Form
The single entry point that creates or matches the contact and starts the Intake router.
Email templates
Each uses the opportunity ticket number and Reply-To support inbox so replies return to the same process.
Routing
An If/Else branch tags the concern and notifies the same support team.
Custom fields
The support form writes into contact fields first. The New sequence immediately copies that data onto opportunity fields so every ticket keeps its own issue, category, updates, and resolution.
Contact fields
| Field | Type | Merge key |
|---|---|---|
| Request Category | Dropdown | {{contact.request_category}} |
| Support Type | Dropdown | {{contact.support_type}} |
| Describe Your Issue | Multi-line text | {{contact.describe_your_issue}} |
| Attachment URL | Text | {{contact.attachment_url}} |
| Support Ticket Number scratchpad | Text | {{contact.support_ticket_number}} |
Opportunity fields
| Field | Type | Merge key | Filled by |
|---|---|---|---|
| Ticket Number | Text | {{opportunity.ticket_number}} | New sequence |
| Ticket Category | Text | {{opportunity.ticket_category}} | Copied from contact |
| Ticket Support Type | Text | {{opportunity.ticket_support_type}} | Copied from contact |
| Ticket Issue | Multi-line text | {{opportunity.ticket_issue}} | Copied from contact |
| Ticket Attachment URL | Text | {{opportunity.ticket_attachment_url}} | Copied from contact |
| Ticket Additional Info Needed | Multi-line text | {{opportunity.ticket_additional_info_needed}} | Support agent |
| Ticket Resolution | Multi-line text | {{opportunity.ticket_resolution}} | Support agent |
| Ticket Date Resolved | Date | {{opportunity.ticket_date_resolved}} | Resolved sequence |
Custom value
company_nameThe business name used across all emails.Custom value
support_slaThe promised response time, updated in one place.Important: GHL generates merge keys from the exact field name. After creating every field, I confirm the generated key before using it in emails or workflows.
The workflows
Each workflow is small enough to troubleshoot on its own. Stage changes trigger the right sequence, while the router and reply handler keep tickets connected.
Front door
Ticket creation
Stage automation
Stage automation
Stage automation
Stage automation
Cross-stage
Timer
Required settings
These are easy to miss because the first ticket works without them. The failure only appears when the same client submits again.
Settings → Objects → Opportunities → enable multiple opportunities per contact in the same pipeline.
Turn it on in the New sequence so Create Opportunity opens a new card instead of updating the previous one.
The same client can return with another concern, and reopened tickets can fire In Progress again.
Match by email or phone so the team sees one complete client history without duplicate contacts.
Quality check
The setup was not considered finished until the complete client journey worked, including repeat submissions and replies.
The outcome
The system replaced scattered concerns with a shared operating view that the team can oversee from intake to resolution.
Every concern is captured
Requests become trackable tickets instead of loose messages.
Ownership is visible
The team can see who is responsible and what needs attention.
Follow-through is built in
Stage-based updates and reminders keep both team and client informed.
History stays intact
Every ticket keeps its own concern, updates, and resolution.