Opening Problem Statement
Meet Sarah, a busy customer support manager juggling hundreds of support tickets daily between Zendesk and HubSpot. Every few hours, she manually copies ticket updates from Zendesk into HubSpot to keep her sales and support teams aligned. This repetitive task takes Sarah over two hours each day and often introduces errors, such as mismatched contact information or missing ticket updates. These mistakes delay responses, frustrate customers, and cost her company time and money.
Sarah’s challenge is clear: she needs a reliable, automated way to sync ticket and contact data between Zendesk and HubSpot that runs regularly without manual intervention.
What This Automation Does
This n8n workflow is designed specifically to sync updated Zendesk tickets to HubSpot and ensure contacts are created or updated seamlessly in HubSpot with matching external IDs back in Zendesk. Here’s what happens when this workflow runs every 5 minutes:
- It fetches all Zendesk tickets updated since the last run, ensuring no ticket update is missed.
- For each ticket, it retrieves requester user data from Zendesk to get accurate contact details.
- It checks if a ticket already exists in HubSpot (by external ID) and updates the ticket’s name and description accordingly.
- If no ticket exists, it creates a new ticket in HubSpot and links it to the associated contact.
- It creates or updates the corresponding contact in HubSpot with requester email and name and syncs the HubSpot contact ID back to Zendesk as an external ID.
- Finally, it updates the Zendesk ticket and contact records with HubSpot ticket and contact external IDs, maintaining bi-directional data consistency.
With this automation, Sarah saves hours per week, eliminates tedious manual copying errors, and keeps both teams fully informed with up-to-date customer support tickets.
Prerequisites ⚙️
- n8n Account – You need an active n8n account (Cloud or self-hosted). Self-hosting is supported and recommended for heavy workflows (see Hostinger for self-hosting).
- Zendesk Account with API access – For retrieving and updating tickets and users.
- HubSpot Account with API OAuth2 – To create/update tickets and contacts via HubSpot API.
- Configured API credentials for Zendesk and HubSpot OAuth2 in n8n’s Credentials Manager.
- A basic understanding of Zendesk ticket fields like
requester_idand HubSpot ticket/contact objects.
Step-by-Step Guide to Build This Workflow
Step 1: Schedule the Workflow to Run Every 5 Minutes
In n8n, click + New Node → Search and select Cron.
Set the trigger to run every 5 minutes. This node will start the flow periodically to check for updated tickets.
You should see a cron node configured with every 5 minutes interval.
Common Mistake: Forgetting to save the cron settings makes the workflow not trigger regularly.
Step 2: Get Last Execution Timestamp
Add a Function Item node named “Get last execution timestamp.” This retrieves and stores the last run time using static workflow data.
Copy-paste this JavaScript code inside the node:
// Code here will run once per input item.
const staticData = getWorkflowStaticData('global');
if(!staticData.lastExecution){
staticData.lastExecution = new Date().toISOString();
}
item.executionTimeStamp = new Date().toISOString();
item.lastExecution = staticData.lastExecution;
return item;
This ensures the workflow fetches tickets only updated since its last execution, reducing API calls and data processing.
Common Mistake: Not using staticData causes the workflow to always pull tickets updated since workflow start, leading to redundant processing.
Step 3: Fetch Zendesk Tickets Updated Since Last Run
Add a Zendesk node named “Get tickets updated after last execution.” Set operation to getAll with a query:
updated>={{ $json["lastExecution"] }}Sort results by updated_at descending to process newest updates first.
This pulls only tickets changed after the last successful sync.
Common Mistake: Incorrect query syntax prevents any data retrieval.
Step 4: Retrieve User Data of Each Ticket Requester
Add another Zendesk node “Get user data of Ticket requester,” configured to get user by requester_id, which is fetched from the ticket data.
This node enriches the ticket info with requester name and email.
Common Mistake: Forgetting to map the requester_id dynamically results in empty user data.
Step 5: Keep Only Essential User Data
Add a Set node named “Only keep needed data.” Configure it to keep just the following fields:
- id (user id)
- contactExternalId (external_id of the user)
- contactEmail
- contactName
This slimmed-down dataset will be merged later to enrich ticket data.
Common Mistake: Failing to enable “Keep Only Set” causes original data bloat.
Step 6: Merge Ticket Data with User Data
Add a Merge node “Add user data” to join each ticket with its requester details using mergeByKey on requester_id and id.
You’ll see ticket and user info combined for downstream HubSpot operations.
Common Mistake: Using incorrect property names for merge keys causes merge failure.
Step 7: Check If Ticket Already Exists in HubSpot
Add an If node named “Ticket Exists” to check if the Zendesk ticket has an external_id value. This indicates if the ticket was already synced.
Configure condition: external_id is not empty.
This branches processing into Update or Create ticket flows.
Common Mistake: Misconfiguring this condition leads to duplicate tickets.
Step 8: Update Existing HubSpot Ticket
On the true branch of the If node, add a HubSpot node “Update existing ticket.” Set resource to ticket and operation to update.
Use external_id as the HubSpot ticket ID and map ticket name and description fields from Zendesk ticket data.
This keeps HubSpot tickets current with Zendesk updates.
Common Mistake: Using wrong ticketId value causes update failure.
Step 9: Create or Update HubSpot Contact
From the false branch of If, or after updating the ticket, add a HubSpot node “Create or update contact.” Configure it to create/update a contact using requester’s email.
This ensures contact records exist for linking tickets.
Common Mistake: Omitting email mapping causes contact creation errors.
Step 10: Update External Id in Zendesk for Contact
After contact creation/update, add a Zendesk node “Update External Id in Zendesk for contact.” Set operation to update user, and update external_id with the HubSpot contact VID.
This links Zendesk users to HubSpot contacts for bi-directional reference.
Common Mistake: Incorrect user ID mapping prevents correct updates.
Step 11: Create New HubSpot Ticket
After syncing contact, add a HubSpot node “Create new Ticket.” Set it to create a ticket in pipeline 0 and stage 1, populating name and description from Zendesk ticket.
Associate the ticket to the linked contact VID.
Common Mistake: Forgetting to associate contact causes orphan tickets in HubSpot.
Step 12: Update Zendesk Ticket with HubSpot External Id
After ticket creation, add a Zendesk node “Update Zendesk ticket with External Id.” Update the Zendesk ticket’s externalId with the new HubSpot ticket ID.
This keeps external ID references valid for future runs.
Common Mistake: Incorrect ticket ID usage breaks references.
Step 13: Update Last Execution Timestamp
Finally, add a Function Item node “Set new last execution timestamp.” This updates the static workflow data with the current execution timestamp.
Use this JavaScript:
const staticData = getWorkflowStaticData('global');
staticData.lastExecution = $item(0).$node["Get last execution timestamp"].executionTimeStamp;
return item;
Common Mistake: Forgetting to update static data prevents incremental syncing.
Customizations ✏️
- Adjust Ticket Sync Frequency: Change the
Cronnode interval from every 5 minutes to any desired period, e.g., every 10 or 15 minutes, based on your API limits and sync needs. - Map Custom Ticket Fields: In HubSpot “Update existing ticket” and “Create new Ticket” nodes, add custom fields to
updateFieldsoradditionalFieldsto sync more detailed ticket metadata. - Filter Tickets by Status or Priority: Modify the Zendesk “Get tickets updated after last execution” node’s
queryparameter to filter tickets by status (e.g., open, pending) or priority to narrow your sync scope. - Expand Contact Data Sync: Enhance the “Only keep needed data” node to include more user properties like phone number or tags and map these into HubSpot contacts.
- Handle Errors Gracefully: Use node settings like “Continue On Fail” (already on for update ticket) or add
Error Triggernodes to send alerts or retries in case of sync failures.
Troubleshooting 🔧
Problem: “Failed to fetch Zendesk tickets” or empty ticket list
Cause: Incorrect API credentials or malformed query syntax in the Zendesk node.
Solution: Recheck Zendesk API credentials under n8n Credentials, and test the query manually in Zendesk API explorer. Fix any syntax errors in the query field.
Problem: “HubSpot ticket update fails with 404 not found”
Cause: The external_id sent as ticketId does not match any HubSpot ticket.
Solution: Ensure the external_id field in Zendesk actually corresponds to an existing HubSpot ticket ID. Debug by logging output between nodes.
Problem: “Contact creation/update does not reflect in HubSpot”
Cause: Missing or incorrect email field mapping in the “Create or update contact” node.
Solution: Verify mapping is set to contactEmail or correct email JSON path. Confirm HubSpot API credentials are valid.
Problem: “External IDs not syncing back to Zendesk”
Cause: Misconfigured update field mappings or wrong IDs used for Zendesk ticket or user update nodes.
Solution: Double-check JSON paths, especially $node["Ticket Exists"].json["requester_id"] and ticket/user IDs being updated. Use the n8n execution log to trace values.
Pre-Production Checklist ✅
- Verify n8n credentials for Zendesk and HubSpot are active and authorized.
- Test the workflow with a small batch of tickets updated recently in Zendesk.
- Confirm the last execution timestamp logic correctly fetches incremental ticket updates.
- Ensure HubSpot tickets update/create as expected with proper contact associations.
- Backup current contact and ticket data outside n8n in case of rollback.
Deployment Guide
Activate your workflow by toggling it on in n8n. The cron node will trigger execution every 5 minutes automatically without any user intervention.
Monitor the workflow runs periodically through the n8n execution log and retry failed executions as needed.
For advanced setups, consider implementing logging webhooks or notifications upon failures for proactive monitoring.
FAQs
Q: Can I replace Zendesk with another support platform?
A: Possibly, but this workflow uses Zendesk-specific API fields (like requester_id and external_id). Replacing Zendesk would require adapting API queries and node configurations.
Q: Does this workflow consume many API credits?
A: It depends on your ticket volume and frequency. Syncing every 5 minutes is moderate, but adjusting the cron interval can help manage API usage.
Q: Is my customer data secure when syncing between Zendesk and HubSpot?
A: Yes, data is transmitted securely over HTTPS using official API credentials with OAuth2 and API tokens managed in n8n’s secure credentials system.
Q: Can this workflow handle large ticket volumes?
A: It is designed for moderate volumes. For very large enterprise scale, consider segmenting ticket queries or increasing server resources if self-hosted.
Conclusion
By following this guide, you have built a powerful automation that syncs support tickets and contacts between Zendesk and HubSpot seamlessly every 5 minutes. Sarah’s hours of manual copying are now saved, and errors eliminated, letting her focus on delivering better customer experiences.
This specific workflow improves data accuracy and team alignment by maintaining consistent ticket states and contact records across platforms.
Next, consider automating notifications to Slack when tickets update or enriching contacts with data from other sources like CRM or marketing platforms.
Keep experimenting and refining your automations to unlock even more efficiency in your support operations!