Auto-close stale Gorgias tickets using n8n

medium complexityCost: $0-24/mo

Prerequisites

Prerequisites
  • 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 /tickets endpoint filtered to pending status
  • 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}/messages and close via PUT /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: pending
    • limit: 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 }}

CaseValueRoute to
1send_follow_upFollow-up message nodes
2closeClose 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" }] }
Add a Wait node for precise timing

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 }}"
}
Watch for API rate limits

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

  1. Create a test ticket in Gorgias, reply as an agent, and manually set updated_datetime to 49 hours ago (or wait)
  2. Run the workflow manually and verify the follow-up message appears
  3. Wait for the close cycle and confirm the ticket closes
  4. 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.