Route refund requests from Gorgias using n8n

low complexityCost: $0-24/mo

Prerequisites

Prerequisites
  • n8n instance (cloud or self-hosted)
  • Gorgias account with REST API access (Settings → API → REST API)
  • Gorgias API credentials: your account email and API key
  • Your Gorgias domain (e.g., your-store.gorgias.com)

Why n8n?

n8n extends refund routing beyond what Gorgias Rules can do alone. You can check the order value before routing (sending high-value refunds to senior agents), log every refund request to a Google Sheet for reporting, or notify a Slack channel when a refund ticket arrives. Because n8n sits outside Gorgias, you can integrate with any external system as part of the routing decision.

Self-hosted n8n is completely free with unlimited executions. n8n Cloud starts at $24/mo. Refund ticket volume is typically 5-15% of total tickets, so this workflow is lightweight on executions.

How it works

  • Gorgias HTTP integration sends a webhook to n8n when a new ticket is created
  • Code node extracts and normalizes ticket text for keyword matching
  • IF node checks for refund-related keywords using OR logic
  • HTTP Request node fetches existing tags from the ticket (Gorgias replaces tags on update, so you must merge)
  • Code node merges the refund-request tag with existing tags
  • HTTP Request node updates the ticket with the merged tags and assigns to the Refund Team

Overview

This workflow listens for new Gorgias tickets via webhook, checks whether the ticket contains refund or return language, and if so assigns it to your refund team and applies a tag — all through the Gorgias API. Because n8n runs outside Gorgias, you can extend this workflow to also log refund requests to a spreadsheet, notify a Slack channel, or check the order value before routing.

Step 1: Create a Webhook trigger node

Add a Webhook node as the trigger:

  • HTTP Method: POST
  • Path: gorgias-refund-routing
  • Authentication: None

Copy the webhook URL — you'll register it in Gorgias next.

Step 2: Register the webhook in Gorgias

In Gorgias, go to Settings → Integrations → HTTP.

Click Add HTTP integration:

  • Name: n8n Refund Routing
  • URL: Your n8n webhook URL
  • Events: Ticket created
  • Content-Type: application/json

Save and enable the integration.

Webhook payload contents

Gorgias sends the full ticket object including id, subject, messages (array — customer's first message is messages[0]), status, tags, and the customer object with name and email.

Step 3: Extract ticket text

Add a Code node to pull out the searchable text:

const ticket = $input.first().json;
const subject = (ticket.subject || '').toLowerCase();
const body = (ticket.messages?.[0]?.body_text || '').toLowerCase();
const combined = `${subject} ${body}`;
 
return [{
  json: {
    ticketId: ticket.id,
    subject: ticket.subject,
    existingTags: ticket.tags || [],
    text: combined,
  }
}];

Step 4: Detect refund intent with an IF node

Add an IF node to check for refund-related keywords:

  • Condition type: String
  • Value: {{ $json.text }}
  • Operation: Contains

Check for these keywords (use OR logic — any match triggers the true branch):

refund, money back, return, send back, exchange, cancel order, wrong item, damaged, defective, reimburse, credit back

Use the 'contains' operator, not 'equals'

The IF node should check if the combined text contains each keyword, not whether it equals it. A message like "I want to return the jacket I bought last week" contains the word "return" but doesn't equal it.

Step 5: Fetch existing tags before updating

The Gorgias API replaces the entire tags array on update — it doesn't append. Add an HTTP Request node to fetch the current ticket:

  • Method: GET
  • URL: https://your-store.gorgias.com/api/tickets/{{ $json.ticketId }}
  • Authentication: Basic Auth
    • Username: your Gorgias email
    • Password: your Gorgias API key

Then add a Code node to merge the new tag:

const currentTags = $input.first().json.tags || [];
const newTag = 'refund-request';
 
const merged = [...currentTags.map(t => t.name), newTag];
const unique = [...new Set(merged)];
 
return [{
  json: {
    ticketId: $('Code').first().json.ticketId,
    tags: unique.map(name => ({ name })),
  }
}];

Step 6: Assign team and apply tag via API

Add an HTTP Request node to update the ticket:

  • Method: PUT
  • URL: https://your-store.gorgias.com/api/tickets/{{ $json.ticketId }}
  • Authentication: Basic Auth (same credentials)
  • Body (JSON):
{
  "tags": {{ $json.tags }},
  "assignee_team": {
    "name": "Refund Team"
  }
}
Look up your team ID if name assignment fails

Some Gorgias API versions require a team ID rather than a name. Fetch your teams from GET /api/teams and use the numeric id field in the assignee_team object instead.

Step 7: Add error handling and activate

  1. Enable Retry On Fail on both HTTP Request nodes (2 retries, 5 second wait)
  2. Add an Error Workflow to notify you via email or Slack if routing fails
  3. Test by creating a Gorgias ticket with body text like "I'd like a refund for my order"
  4. Verify the tag appears and the ticket is assigned to the Refund Team
  5. Toggle the workflow to Active

To extend this workflow, add a Slack notification node after the tag step to alert your refund team in real time, or add a Google Sheets node to log every refund request for reporting.

Troubleshooting

Common questions

Why do I need to fetch existing tags before updating?

The Gorgias API PUT endpoint replaces the entire tags array — it does not append. If a ticket already has a billing tag and you PUT only refund-request, the billing tag disappears. Always GET the ticket first, merge your new tag with existing tags, then PUT the combined array.

Can I route based on order value, not just keywords?

Yes. After detecting refund intent, add an HTTP Request node to the Shopify Orders API to fetch the order total. Then use an IF node to route high-value refunds ($100+) to senior agents and low-value refunds to the standard refund team.

How do I avoid false positives from the word "return"?

The word "return" appears in non-refund contexts (e.g., "I'll return to your site later"). Use multi-word phrases like "return my order" or "return the item" alongside single keywords. Also, convert to lowercase in the Code node before matching to avoid case sensitivity issues.

Cost

  • n8n Cloud: Each ticket triggers ~4 node executions. 300 refund tickets/month = ~1,200 executions — well within the Starter plan.
  • 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.