Auto-close stale Gorgias tickets using n8n
Install this workflow
Download the n8n workflow JSON and import it into your n8n instance.
auto-close-stale.n8n.jsonPrerequisites
- n8n instance (cloud or self-hosted)
- Gorgias account with REST API access
- Gorgias API credentials: account email and API key
Why n8n?
n8n gives you full control over the auto-close logic that Gorgias Rules can't offer. You can check external systems before closing (CRM lookup, order status), apply precise timing rather than Gorgias's periodic evaluation, and route different ticket types through different close paths. Self-hosted n8n is completely free with unlimited executions.
The trade-off is setup complexity. You need an n8n instance, API credentials, and a multi-step workflow. If all you need is a basic "close after 48 hours with no reply" flow, Gorgias native Rules are simpler. n8n makes sense when you need external data checks, custom timing, or integration with Slack/spreadsheets as part of the close process.
How it works
- Schedule Trigger runs the workflow every hour, keeping ticket closures close to the 48-hour mark without overloading the Gorgias API
- HTTP Request node fetches pending tickets from the Gorgias
/ticketsendpoint filtered topendingstatus - Code node calculates hours since last update, checks for agent-last-message, excludes VIP/escalated tickets, and separates tickets into "send follow-up" and "close" buckets
- Switch node routes tickets to the appropriate action — follow-up message or close
- HTTP Request nodes send the follow-up via
POST /tickets/{id}/messagesand close viaPUT /tickets/{id}
Step 1: Set up a Schedule trigger
Add a Schedule Trigger node:
- Interval: Every 1 hour
- Time zone: Your support team's primary time zone
Running hourly ensures tickets get closed reasonably close to the 48-hour mark without hammering the Gorgias API.
Step 2: Fetch pending tickets from Gorgias
Add an HTTP Request node to pull tickets waiting on a customer reply:
- Method: GET
- URL:
https://your-store.gorgias.com/api/tickets - Authentication: Basic Auth (Gorgias email + API key)
- Query parameters:
status:pendinglimit:50
{
"method": "GET",
"url": "https://your-store.gorgias.com/api/tickets",
"authentication": "basicAuth",
"qs": {
"status": "pending",
"limit": 50
}
}Step 3: Filter to stale tickets
Add a Code node to identify tickets that are past the 48-hour threshold:
const now = new Date();
const FOLLOW_UP_HOURS = 48;
const CLOSE_HOURS = 72; // 48h + 24h after follow-up
const results = [];
for (const item of $input.all()) {
const ticket = item.json;
const tickets = ticket.data || [ticket];
for (const t of tickets) {
const updatedAt = new Date(t.updated_datetime);
const hoursSinceUpdate = (now - updatedAt) / (1000 * 60 * 60);
// Check if last message is from an agent
const messages = t.messages || [];
const lastMessage = messages[messages.length - 1];
const lastIsAgent = lastMessage?.source?.type === 'helpdesk';
if (!lastIsAgent) continue;
const tags = (t.tags || []).map(tag => tag.name || tag);
const isVip = tags.includes('vip') || tags.includes('escalated');
if (isVip) continue;
const followUpSent = tags.includes('auto-close-sent');
if (!followUpSent && hoursSinceUpdate >= FOLLOW_UP_HOURS) {
results.push({
json: {
ticketId: t.id,
action: 'send_follow_up',
customerName: t.requester?.firstname || 'there',
subject: t.subject,
hoursSinceUpdate: Math.round(hoursSinceUpdate),
}
});
} else if (followUpSent && hoursSinceUpdate >= CLOSE_HOURS) {
results.push({
json: {
ticketId: t.id,
action: 'close',
subject: t.subject,
hoursSinceUpdate: Math.round(hoursSinceUpdate),
}
});
}
}
}
return results;Step 4: Route by action type
Add a Switch node to separate follow-up and close actions:
Value: {{ $json.action }}
| Case | Value | Route to |
|---|---|---|
| 1 | send_follow_up | Follow-up message nodes |
| 2 | close | Close ticket nodes |
Step 5: Send the follow-up message
For the send_follow_up route, add an HTTP Request node:
- Method: POST
- URL:
https://your-store.gorgias.com/api/tickets/{{ $json.ticketId }}/messages - Authentication: Basic Auth
- Body (JSON):
{
"body_text": "Hi {{ $json.customerName }},\n\nJust checking in — did our previous reply resolve your question? If you still need help, simply reply to this message and we'll pick things right back up.\n\nIf we don't hear from you, we'll close this ticket shortly to keep things tidy. You can always reach out again anytime.\n\nBest,\nThe Support Team",
"channel": "email",
"from_agent": true,
"source": {
"type": "helpdesk",
"from": {
"name": "Support Team",
"address": "support@yourstore.com"
}
}
}Then add a second HTTP Request to tag the ticket:
- Method: PUT
- URL:
https://your-store.gorgias.com/api/tickets/{{ $json.ticketId }} - Body:
{ "tags": [{ "name": "auto-close-sent" }] }
If you want exact 48-hour follow-ups rather than hourly batch processing, use a webhook trigger on ticket updates plus a Wait node set to 48 hours. The Wait node holds the execution and resumes after the delay. This is more precise but uses more n8n executions.
Step 6: Close the ticket
For the close route, add an HTTP Request node:
- Method: PUT
- URL:
https://your-store.gorgias.com/api/tickets/{{ $json.ticketId }} - Body:
{
"status": "closed",
"tags": [
{ "name": "auto-closed" }
]
}Step 7: Add error handling and notifications
Add Retry On Fail to all HTTP Request nodes (2 retries, 30-second delay).
Optionally, connect an Error Trigger node to a Slack or email notification so you know if the workflow fails:
{
"text": "Auto-close workflow failed: {{ $json.error.message }}"
}The Gorgias API has rate limits (typically 2 requests/second on standard plans). If you process many tickets per run, add a Wait node (1 second) between API calls to avoid hitting the limit.
Step 8: Activate and test
- Create a test ticket in Gorgias, reply as an agent, and manually set
updated_datetimeto 49 hours ago (or wait) - Run the workflow manually and verify the follow-up message appears
- Wait for the close cycle and confirm the ticket closes
- Toggle the workflow to Active
Troubleshooting
Common questions
How often should the schedule trigger run?
Every hour is a good default. It keeps closures within an hour of the threshold without hammering the API. For teams with aggressive SLAs who want tighter timing, every 30 minutes works but doubles your execution count. Running more frequently than every 15 minutes provides negligible benefit for auto-close workflows.
Will this conflict with Gorgias native Rules running at the same time?
It can. If you have both n8n and Gorgias Rules auto-closing tickets, you may get duplicate follow-up messages or race conditions. Pick one approach for auto-close and disable the other. If you want Gorgias Rules for simple cases and n8n for complex ones, use tags to partition — have Gorgias Rules add a simple-close tag and have n8n skip tickets with that tag.
What happens if the Gorgias API is down during a scheduled run?
n8n's "Retry On Fail" setting (recommended on all HTTP Request nodes) will retry failed API calls 2-3 times with a delay. If the API is still down, the workflow fails and the next hourly run will pick up the same tickets. No tickets are lost — they just get processed on the next successful run.
Cost
- n8n Cloud: ~4-6 node executions per processed ticket. 200 auto-closes/month = ~1,000 executions.
- Self-hosted: Free.
Looking to scale your AI operations?
We build and optimize automation systems for mid-market businesses. Let's discuss the right approach for your team.