Monitor CSAT scores and alert Slack on detractors using a Claude Code skill

low complexityCost: Usage-based

Prerequisites

Compatible agents

This skill works with any agent that supports the Claude Code skills standard, including Claude Code, Claude Cowork, OpenAI Codex, and Google Antigravity.

Prerequisites
  • One of the agents listed above
  • Gorgias account with Satisfaction Surveys enabled and actively collecting responses
  • Slack Incoming Webhook configured for your CSAT alerts channel
Environment Variables
# Your Gorgias subdomain (e.g. yourstore)
GORGIAS_DOMAIN=your_value_here
# Gorgias account email for API authentication
GORGIAS_EMAIL=your_value_here
# Gorgias API key from Settings > REST API
GORGIAS_API_KEY=your_value_here
# Slack Incoming Webhook URL for CSAT alerts
SLACK_WEBHOOK_URL=your_value_here

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:

  • "Check for low CSAT scores in the last 2 hours and alert Slack"
  • "Show me a summary of today's CSAT scores without sending any alerts"
  • "Alert on scores of 3 or below instead of just 1-2"
  • "Which agents had the most detractor scores this week?"

The skill contains workflow guidelines, API reference materials, and a Slack 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 wider score threshold, a summary instead of individual alerts, a different lookback window — the agent adapts without you touching any code.

How it works

The skill directory has three parts:

  1. SKILL.md — workflow guidelines telling the agent what steps to follow, which env vars to use, and what pitfalls to avoid
  2. references/ — Gorgias API patterns (satisfaction surveys endpoint, ticket details) so the agent calls the right APIs
  3. templates/ — a Slack Block Kit template so alerts 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 posted.

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., /csat-alert), 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/csat-alert/{templates,references}

This creates the layout:

.claude/skills/csat-alert/
├── SKILL.md                          # workflow guidelines + config
├── templates/
│   └── slack-alert.md                # Block Kit template for Slack alerts
└── references/
    └── gorgias-surveys-api.md        # Gorgias satisfaction surveys API

Step 2: Write the SKILL.md

Create .claude/skills/csat-alert/SKILL.md:

---
name: csat-alert
description: Check recent Gorgias satisfaction survey scores and alert Slack when a customer gives a low rating, so detractors get immediate follow-up.
disable-model-invocation: true
allowed-tools: Bash, Read
---
 
## Goal
 
Fetch recent satisfaction survey responses from Gorgias, identify low scores (1-2 out of 5 by default), and post a formatted Slack alert for each detractor. Tag the ticket in Gorgias for tracking.
 
## Configuration
 
Read these environment variables:
 
- `GORGIAS_DOMAIN` — your Gorgias subdomain (required)
- `GORGIAS_EMAIL` — Gorgias account email for API auth (required)
- `GORGIAS_API_KEY` — Gorgias API key (required)
- `SLACK_WEBHOOK_URL` — Slack Incoming Webhook URL (required)
 
Default lookback window: 2 hours. Default low-score threshold: 2 (alert on scores 1-2). The user may request different values.
 
## Workflow
 
1. Validate that all required env vars are set. If any are missing, print which ones and exit.
2. Fetch recent satisfaction surveys from Gorgias. See `references/gorgias-surveys-api.md` for the endpoint and response format.
3. For each survey with a score at or below the threshold, fetch the full ticket to get customer name, email, subject, and assigned agent.
4. Post a Slack alert using the template in `templates/slack-alert.md`.
5. Tag the ticket with `csat-low` to track which tickets triggered alerts.
6. Track already-alerted survey IDs in a local JSON file to avoid duplicate alerts across runs.
7. Print a summary of alerts sent.
 
## Important notes
 
- The Gorgias `PUT /tickets/{id}` endpoint REPLACES the entire tags array. Fetch current tags first, merge `csat-low`, then PUT the combined list.
- The satisfaction surveys endpoint returns surveys, not tickets. Each survey has a `ticket_id` you need to fetch separately for context.
- Rate limit: Gorgias allows roughly 2 requests per second. Add delays if processing many surveys.
- Store the alerted survey IDs file in the skill directory (e.g., `.alerted_surveys.json`). Keep it in `.gitignore`.
- 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:

SectionPurpose
GoalTells the agent what outcome to produce
ConfigurationWhich env vars to read and what defaults to use
WorkflowNumbered steps with pointers to reference files
Important notesNon-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/slack-alert.md

Create .claude/skills/csat-alert/templates/slack-alert.md:

# CSAT Alert Slack Template
 
Use this Block Kit structure for each low CSAT score alert.
 
## Block Kit JSON
 
```json
{
  "blocks": [
    {
      "type": "header",
      "text": {
        "type": "plain_text",
        "text": "Low CSAT Score: <score>/5"
      }
    },
    {
      "type": "section",
      "fields": [
        { "type": "mrkdwn", "text": "*Customer:* <customer_name>" },
        { "type": "mrkdwn", "text": "*Email:* <customer_email>" },
        { "type": "mrkdwn", "text": "*Subject:* <ticket_subject>" },
        { "type": "mrkdwn", "text": "*Agent:* <agent_name>" }
      ]
    },
    {
      "type": "actions",
      "elements": [
        {
          "type": "button",
          "text": { "type": "plain_text", "text": "Open Ticket" },
          "url": "https://<GORGIAS_DOMAIN>.gorgias.com/app/ticket/<ticket_id>"
        }
      ]
    }
  ]
}
```
 
## Notes
 
- Send via `POST` to the `SLACK_WEBHOOK_URL` with the JSON body above.
- Replace all `<placeholders>` with actual values from the survey and ticket data.
- If the survey includes a text comment, add it as an additional section block.

references/gorgias-surveys-api.md

Create .claude/skills/csat-alert/references/gorgias-surveys-api.md:

# Gorgias Satisfaction Surveys 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 satisfaction surveys
 
Fetch recent satisfaction survey responses.
 
**Request:**
 
```
GET /api/satisfaction-surveys?created_datetime__gte=<iso_datetime>&limit=50&order_by=created_datetime:desc
```
 
**Response shape:**
 
```json
{
  "data": [
    {
      "id": 5001,
      "score": 1,
      "body_text": "Waited 5 days and still no resolution",
      "ticket_id": 10384,
      "created_datetime": "2026-03-05T10:30:00+00:00"
    }
  ]
}
```
 
- `score` is 1-5 (1 = very dissatisfied, 5 = very satisfied).
- `body_text` may be null if the customer didn't leave a comment.
- Use `ticket_id` to fetch the full ticket for customer and agent context.
 
## Get a single ticket
 
**Request:**
 
```
GET /api/tickets/{ticket_id}
```
 
**Response shape:**
 
```json
{
  "id": 10384,
  "subject": "Damaged item, no replacement sent",
  "status": "closed",
  "requester": {
    "id": 678,
    "name": "Priya Nair",
    "email": "priya@example.com"
  },
  "assignee_user": {
    "id": 42,
    "name": "Jordan M."
  },
  "tags": [
    { "name": "shipping" }
  ]
}
```
 
## Update a ticket (add tag)
 
**Request:**
 
```
PUT /api/tickets/{ticket_id}
Content-Type: application/json
```
 
**IMPORTANT:** The `tags` field REPLACES the entire array. Fetch current tags first, add `csat-low`, then PUT the merged list.
 
```json
{
  "tags": [
    { "name": "shipping" },
    { "name": "csat-low" }
  ]
}
```

Step 4: Test the skill

Invoke the skill conversationally:

/csat-alert

Claude 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:

Checking CSAT surveys from the last 2 hours...
Found 8 recent survey response(s)
 
  #15201  Score: 1/5  Customer: Maria S.
    Subject: Damaged item received
    -> Slack alert sent, tagged csat-low
 
  #15198  Score: 5/5  (above threshold, skipped)
  #15195  Score: 2/5  Customer: James T.
    Subject: Late delivery
    -> Slack alert sent, tagged csat-low
 
Done. Sent 2 Slack alert(s).

Because the agent generates code on the fly, you can also make ad hoc requests:

  • "Show me a summary of today's scores without alerting anyone" — the agent runs read-only
  • "Alert on scores of 3 or below" — the agent adjusts the threshold
  • "Which agents had the most detractor scores this week?" — the agent pivots to analysis
Adjust the lookback window to match your schedule

If you run the skill every hour, the default 2-hour lookback provides safe overlap. The state file prevents duplicate alerts, so overlapping windows are safe and ensure no survey slips through the cracks.

Step 5: Schedule it (optional)

Option A: Cron + Claude CLI

# Run every 30 minutes during business hours
*/30 8-18 * * 1-5 cd /path/to/your/project && claude -p "Run /csat-alert" --allowedTools 'Bash(*)' 'Read(*)'

Option B: GitHub Actions + Claude

name: CSAT Alert Monitor
on:
  schedule:
    - cron: '*/30 * * * *'  # Every 30 minutes
  workflow_dispatch: {}
jobs:
  alert:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: anthropics/claude-code-action@v1
        with:
          prompt: "Run /csat-alert"
          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 }}
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}

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).

State file doesn't persist on GitHub Actions

The .alerted_surveys.json file is stored locally. On GitHub Actions, each run starts fresh, so the lookback window itself acts as your deduplication boundary. Set the lookback to match your cron interval (e.g., 30-minute cron = 60-minute lookback for overlap).

Troubleshooting

When to use this approach

  • You want conversational flexibility — ad hoc queries like "which agents had low scores this week?" alongside scheduled monitoring
  • You want on-demand checks during team reviews, not just automated alerts
  • 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 real-time alerts (within seconds of a survey response) → use Gorgias Rules with a webhook
  • You want a visual workflow builder with no LLM usage → use n8n
  • You need alerts running 24/7 at zero cost → use the Gorgias native approach

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 score thresholds, summary reports instead of individual alerts, analysis by agent or time period. The reference files ensure it calls the right APIs even when improvising.

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. The Gorgias and Slack APIs themselves are free.

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.

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
  • Slack Incoming Webhook — free
  • 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.