Auto-close stale Gorgias tickets using a Claude Code skill
Install this skill
Download the skill archive and extract it into your .claude/skills/ directory.
auto-close-stale.skill.zipPrerequisites
This skill works with any agent that supports the Claude Code skills standard, including Claude Code, Claude Cowork, OpenAI Codex, and Google Antigravity.
- One of the agents listed above
- Gorgias account with REST API access
Why a Claude Code skill?
The other approaches in this guide are deterministic: they run the same logic every time, the same way. An Claude Code skill is different. You tell Claude what you want in plain language, and the skill gives it enough context to do it reliably.
That means you can say:
- "Close stale tickets that haven't had a reply in 48 hours"
- "Preview what would be closed this week — don't actually close anything"
- "Close everything older than 5 days except VIP tickets"
- "Send follow-ups to stale tickets but skip anything tagged billing"
The skill contains workflow guidelines, API reference materials, and a message template that the agent reads on demand. When you invoke the skill, Claude reads these files, writes a script on the fly, runs it, and reports results. If you ask for something different next time — a longer wait window, different exclusion tags, a dry-run preview — the agent adapts without you touching any code.
How it works
The skill directory has three parts:
SKILL.md— workflow guidelines telling the agent what steps to follow, which env vars to use, and what pitfalls to avoidreferences/— Gorgias API patterns (endpoints, request shapes, response formats) so the agent calls the right APIs with the right parameterstemplates/— a follow-up message template so closing messages are consistently formatted across runs
When invoked, the agent reads SKILL.md, consults the reference and template files as needed, writes a Python script, executes it, and reports what it did. The reference files act as guardrails — the agent knows exactly which endpoints to hit and what the responses look like, so it doesn't have to guess.
What is a Claude Code skill?
An Claude Code skill is a reusable command you add to your project that Claude Code can run on demand. Skills live in a .claude/skills/ directory and are defined by a SKILL.md file that tells the agent what the skill does, when to run it, and what tools it's allowed to use.
In this skill, the agent doesn't run a pre-written script. Instead, SKILL.md provides workflow guidelines and points to reference files — API documentation, message templates — that the agent reads to generate and execute code itself. This is the key difference from a traditional script: the agent can adapt its approach based on what you ask for while still using the right APIs and message formats.
Once installed, you can invoke a skill as a slash command (e.g., /auto-close-stale), or the agent will use it automatically when you give it a task where the skill is relevant. Skills are portable — anyone who clones your repo gets the same commands.
Step 1: Create the skill directory
mkdir -p .claude/skills/auto-close-stale/{templates,references}This creates the layout:
.claude/skills/auto-close-stale/
├── SKILL.md # workflow guidelines + config
├── templates/
│ └── closing-message.md # follow-up message template
└── references/
└── gorgias-tickets-api.md # Gorgias API patternsStep 2: Write the SKILL.md
Create .claude/skills/auto-close-stale/SKILL.md:
---
name: auto-close-stale
description: Find Gorgias tickets with no customer reply after 48 hours, send a follow-up message, and close tickets where the follow-up was already sent and 24 more hours have passed.
disable-model-invocation: true
allowed-tools: Bash, Read
---
## Goal
Find pending Gorgias tickets where the agent replied but the customer hasn't responded within a configurable window (default: 48 hours). Send a follow-up message to those tickets. On a subsequent run, close tickets that already received a follow-up and still have no customer reply after an additional 24 hours (72 hours total).
## Configuration
Read these environment variables:
- `GORGIAS_DOMAIN` — your Gorgias subdomain, e.g. "yourstore" (required)
- `GORGIAS_EMAIL` — Gorgias account email for API auth (required)
- `GORGIAS_API_KEY` — Gorgias API key (required)
Default thresholds: follow-up after 48 hours, close after 72 hours total. The user may request different windows.
## Workflow
1. Validate that all required env vars are set. If any are missing, print which ones and exit.
2. Fetch pending tickets from Gorgias filtered to `status=pending`. See `references/gorgias-tickets-api.md` for the endpoint and response format.
3. For each ticket, calculate hours since `updated_datetime`. Check that the last message is from an agent (source type `helpdesk`). Skip tickets tagged `vip`, `escalated`, or `priority`.
4. For tickets past the follow-up threshold (default 48h) that are NOT tagged `auto-close-sent`, send a follow-up message using the template in `templates/closing-message.md`, then tag the ticket `auto-close-sent`.
5. For tickets already tagged `auto-close-sent` that are past the close threshold (default 72h), set the ticket status to `closed` and add the `auto-closed` tag.
6. Print a summary of follow-ups sent and tickets closed.
## Important notes
- The Gorgias `PUT /tickets/{id}` endpoint REPLACES the entire tags array. You must GET the current tags first, merge your new tag in, then PUT the combined list. If you send only the new tag, all existing tags are removed.
- Rate limit: Gorgias allows roughly 2 requests per second. Add a small delay between API calls if processing many tickets.
- Always support a `--dry-run` flag that previews actions without making changes.
- Use the `requests` library for HTTP calls. Install with pip if needed.Understanding the SKILL.md
Unlike the script-based approach, this SKILL.md doesn't contain a Run: command pointing to a script. Instead, it provides:
| Section | Purpose |
|---|---|
| Goal | Tells the agent what outcome to produce |
| Configuration | Which env vars to read and what defaults to use |
| Workflow | Numbered steps with pointers to reference files |
| Important notes | Non-obvious context that prevents common mistakes |
The allowed-tools: Bash, Read setting lets the agent both read reference files and execute code. The agent writes its own script based on the workflow steps and reference materials.
Step 3: Add reference files
templates/closing-message.md
Create .claude/skills/auto-close-stale/templates/closing-message.md:
# Closing Follow-Up Message Template
Use this template when sending a follow-up message to a stale ticket before closing.
## Message Body
```
Hi {customer_name},
Just 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.
If we don't hear from you, we'll close this ticket shortly to keep things tidy. You can always reach out again anytime.
Best,
The Support Team
```
## API Payload
Send via `POST /api/tickets/{ticket_id}/messages`:
```json
{
"body_text": "<message body above with {customer_name} replaced>",
"channel": "email",
"from_agent": true,
"source": {
"type": "helpdesk",
"from": {
"name": "Support Team",
"address": "support@<GORGIAS_DOMAIN>.com"
}
}
}
```
## Notes
- Replace `{customer_name}` with `ticket.requester.firstname` or "there" if not available.
- The `from_agent: true` flag ensures the message shows as an agent reply, not a customer message.
- The `source.type` must be `helpdesk` so Gorgias counts this as an agent message.references/gorgias-tickets-api.md
Create .claude/skills/auto-close-stale/references/gorgias-tickets-api.md:
# Gorgias Tickets API Reference
## Authentication
All requests use HTTP Basic Auth:
- Username: `GORGIAS_EMAIL`
- Password: `GORGIAS_API_KEY`
- Base URL: `https://{GORGIAS_DOMAIN}.gorgias.com/api`
## List tickets
Fetch tickets filtered by status.
**Request:**
```
GET /api/tickets?status=pending&limit=50
```
**Response shape:**
```json
{
"data": [
{
"id": 12345,
"subject": "Question about return policy",
"status": "pending",
"updated_datetime": "2026-03-01T14:30:00+00:00",
"created_datetime": "2026-03-01T10:00:00+00:00",
"requester": {
"id": 678,
"firstname": "Sarah",
"email": "sarah@example.com"
},
"tags": [
{ "name": "shipping" }
],
"messages": [
{
"id": 99001,
"body_text": "Customer message here...",
"source": { "type": "email" },
"created_datetime": "2026-03-01T10:00:00+00:00"
},
{
"id": 99002,
"body_text": "Agent reply here...",
"source": { "type": "helpdesk" },
"created_datetime": "2026-03-01T11:00:00+00:00"
}
]
}
]
}
```
- Check `messages[-1].source.type == "helpdesk"` to confirm the last message is from an agent.
- Parse `updated_datetime` to calculate hours since last activity.
- Tags are objects with a `name` field.
## Send a message on a ticket
**Request:**
```
POST /api/tickets/{ticket_id}/messages
Content-Type: application/json
```
See `templates/closing-message.md` for the payload structure.
## Update a ticket (tags, status)
**Request:**
```
PUT /api/tickets/{ticket_id}
Content-Type: application/json
```
**IMPORTANT:** The `tags` field REPLACES the entire array. To add a tag without removing existing ones:
1. Read the current ticket to get existing tags
2. Merge your new tag into the list
3. PUT the combined array
**Body to close a ticket:**
```json
{
"status": "closed",
"tags": [
{ "name": "existing-tag-1" },
{ "name": "auto-closed" }
]
}
```
**Body to add a tag:**
```json
{
"tags": [
{ "name": "existing-tag-1" },
{ "name": "auto-close-sent" }
]
}
```Step 4: Test the skill
Invoke the skill conversationally:
/auto-close-staleClaude will read the SKILL.md, check the reference files, write a script, install any missing dependencies, run it, and report the results. A typical run looks like:
Fetching pending tickets from Gorgias...
Found 24 pending ticket(s)
Sent follow-up: #14201 "Return policy question" (52h stale)
Sent follow-up: #14198 "Shipping delay" (49h stale)
Closed: #14185 "Order status inquiry" (74h stale, follow-up already sent)
Skipped: #14190 "VIP account issue" (tagged vip)
Done. Follow-ups sent: 2, Tickets closed: 1Because the agent generates code on the fly, you can also make ad hoc requests:
- "Preview what would be closed this week — don't actually close anything" — the agent runs in dry-run mode
- "Close everything older than 5 days except VIP tickets" — the agent adjusts the threshold
- "Send follow-ups to stale tickets but skip anything tagged billing" — the agent adds an exclusion
The first time you run the skill, ask Claude to do a dry run: "Run /auto-close-stale in dry-run mode." This previews which tickets would be affected without making any changes.
Step 5: Schedule it (optional)
Option A: Cron + Claude CLI
# Run every hour on the hour
0 * * * * cd /path/to/your/project && claude -p "Run /auto-close-stale" --allowedTools 'Bash(*)' 'Read(*)'Option B: GitHub Actions + Claude
name: Auto-Close Stale Tickets
on:
schedule:
- cron: '0 * * * *' # Every hour
workflow_dispatch: {} # Manual trigger for testing
jobs:
close:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: anthropics/claude-code-action@v1
with:
prompt: "Run /auto-close-stale"
allowed_tools: "Bash(*),Read(*)"
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
GORGIAS_DOMAIN: ${{ secrets.GORGIAS_DOMAIN }}
GORGIAS_EMAIL: ${{ secrets.GORGIAS_EMAIL }}
GORGIAS_API_KEY: ${{ secrets.GORGIAS_API_KEY }}Option C: Cowork Scheduled Tasks
Claude Desktop's Cowork supports built-in scheduled tasks. Open a Cowork session, type /schedule, and configure the cadence — hourly, daily, weekly, or weekdays only. Each scheduled run has full access to your connected tools, plugins, and MCP servers.
Scheduled tasks only run while your computer is awake and Claude Desktop is open. If a run is missed, Cowork executes it automatically when the app reopens. For always-on scheduling, use GitHub Actions (Option B) instead. Available on all paid plans (Pro, Max, Team, Enterprise).
0 * * * * runs at the top of every hour UTC. GitHub Actions cron may also have up to 15 minutes of delay. For time-sensitive closures, use cron on your own server instead.
Troubleshooting
When to use this approach
- You want conversational flexibility — dry-run previews, custom thresholds, ad hoc exclusions alongside scheduled closures
- You want on-demand closures during queue cleanup sessions, not just automated runs
- You're already using Claude Code and want skills that integrate with your workflow
- You want to run tasks in the background via Claude Cowork while focusing on other work
- You prefer guided references over rigid scripts — the agent adapts while staying reliable
When to switch approaches
- You need exact timing (close at precisely 48 hours, not within an hour) → use n8n with a Wait node
- You want a zero-cost, zero-dependency setup → use Gorgias native Rules
- You need closures running 24/7 without any LLM usage → use Gorgias Rules or n8n
Common questions
Why not just use a script?
A script runs the same way every time. The Claude Code skill adapts to what you ask — different wait windows, custom exclusion tags, dry-run previews, skip certain ticket types. The reference files ensure it calls the right APIs even when improvising, so you get flexibility without sacrificing reliability.
Does this use Claude API credits?
Yes. The agent reads skill files and generates code each time. Typical cost is $0.01-0.05 per invocation depending on how many tickets are processed. The Gorgias API itself is included in all paid plans.
Can I run this skill on a schedule without a server?
Yes. GitHub Actions (Option B in Step 5) runs Claude on a cron schedule using GitHub's infrastructure. The free tier includes 2,000 minutes/month.
What happens if a customer replies after being auto-closed?
Gorgias automatically reopens a ticket when a customer replies to a closed conversation. The ticket returns to your open queue with the full history intact. No context is lost.
Cost
- Claude API — $0.01-0.05 per invocation (the agent reads files and generates code)
- Gorgias API — included in all paid plans, no per-call cost
- GitHub Actions (if scheduled) — free tier includes 2,000 minutes/month
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.