# Zendesk

> Interact with Zendesk Support via CLI - search tickets, view details, analyze metrics, manage users/organizations, and update tickets. All responses are saved locally for efficient jq querying. All Zendesk content is screened for prompt injection (regex, semantic, and LLM-based) and wrapped with security markers before reaching the LLM.

- **Type:** Skill
- **Install:** `agentstack add skill-andmarios-zendesk-skill-zendesk-skill`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [andmarios](https://agentstack.voostack.com/s/andmarios)
- **Installs:** 0
- **Category:** [AI & ML](https://agentstack.voostack.com/c/ai-and-ml)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [andmarios](https://github.com/andmarios)
- **Source:** https://github.com/andmarios/zendesk-skill

## Install

```sh
agentstack add skill-andmarios-zendesk-skill-zendesk-skill
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Zendesk CLI Skill

A command-line interface for comprehensive Zendesk API integration. Run commands via `uv run zd-cli ` in the skill directory.

> **Running commands**
>
> - **Installed (recommended):** `uvx zd-cli `
> - **Development (cloned repo):** `uv run zd-cli ` from the repo directory
>
> Never use bare `python3 zd-cli` — dependencies won't be available. All examples below use `uv run zd-cli`; substitute `uvx zd-cli` if running outside the repo.

## Quick Start

```bash
# Test authentication
uv run zd-cli me

# Search tickets
uv run zd-cli search "status:open priority:urgent"

# Get ticket details
uv run zd-cli ticket-details 12345

# Query saved response (path shown in command output)
uv run zd-cli query /zd-cli-/ticket_details_xxx.json -q comments_slim
```

## Key Concepts

### Save First, Query Later

All API responses are automatically saved to `/zd-cli-/` (system temp directory) with:
- **Metadata**: Command, parameters, timestamp, item count
- **Structure**: Auto-extracted schema showing field types
- **Suggested queries**: Command-specific jq queries
- **Data**: Full API response

**Workflow pattern:**
1. Run a command (e.g., `uv run zd-cli ticket-details 12345`)
2. Response saved to a JSON file (path shown in output)
3. Use `uv run zd-cli query  -q ` to extract specific data
4. Avoid re-fetching - work with stored files

### Why This Matters

Zendesk API responses can be very large (comments with HTML, many custom fields). By saving locally and using jq:
- Context window is preserved (only extract what's needed)
- No redundant API calls
- Complex analysis can use multiple queries on same data

## Command Reference

### Ticket Commands

| Command | Description | Example |
|---------|-------------|---------|
| `search` | Search tickets with query | `uv run zd-cli search "status:open"` |
| `ticket` | Get ticket by ID | `uv run zd-cli ticket 12345` |
| `ticket-details` | Get ticket + all comments | `uv run zd-cli ticket-details 12345` |
| `linked-incidents` | Get incidents linked to problem | `uv run zd-cli linked-incidents 12345` |
| `attachment` | Download attachment file | `uv run zd-cli attachment --ticket 12345 ` |

### Write Operations

All write commands (`create-ticket`, `add-note`, `add-comment`) support **Markdown formatting** by default. Content is converted to HTML for reliable rendering in Zendesk Agent Workspace. Use `--plain-text` to send as plain text instead.

| Command | Description | Example |
|---------|-------------|---------|
| `update-ticket` | Update ticket properties | `uv run zd-cli update-ticket 12345 --status pending` |
| `create-ticket` | Create new ticket (Markdown) | `uv run zd-cli create-ticket "Subject" "**Bold** description"` |
| `add-note` | Add internal note (Markdown) | `uv run zd-cli add-note 12345 "**Investigation:** found the issue"` |
| `add-comment` | Add public comment (Markdown) | `uv run zd-cli add-comment 12345 "Here are the steps:\n- Step 1\n- Step 2"` |

### Metrics & Analytics

| Command | Description | Example |
|---------|-------------|---------|
| `ticket-metrics` | Get reply/resolution times | `uv run zd-cli ticket-metrics 12345` |
| `list-metrics` | List metrics for tickets | `uv run zd-cli list-metrics` |
| `satisfaction-ratings` | List CSAT ratings | `uv run zd-cli satisfaction-ratings --score bad` |
| `satisfaction-rating` | Get single rating | `uv run zd-cli satisfaction-rating 67890` |

### Views (Queue Management)

| Command | Description | Example |
|---------|-------------|---------|
| `views` | List available views | `uv run zd-cli views` |
| `view-count` | Get ticket count | `uv run zd-cli view-count 123` |
| `view-tickets` | Get tickets from view | `uv run zd-cli view-tickets 123` |

### Users & Organizations

| Command | Description | Example |
|---------|-------------|---------|
| `user` | Get user by ID | `uv run zd-cli user 12345` |
| `search-users` | Search users | `uv run zd-cli search-users "john@example.com"` |
| `org` | Get organization by ID | `uv run zd-cli org 67890` |
| `search-orgs` | Search organizations | `uv run zd-cli search-orgs "Acme"` |

### Authentication

| Command | Description | Example |
|---------|-------------|---------|
| `auth login` | Configure Zendesk API token credentials | `uv run zd-cli auth login` |
| `auth login-oauth` | OAuth 2.0 login (opens browser) | `uv run zd-cli auth login-oauth --subdomain co` |
| `auth status` | Check auth configuration (token + OAuth) | `uv run zd-cli auth status` |
| `auth logout` | Remove API token credentials | `uv run zd-cli auth logout` |
| `auth logout-oauth` | Remove OAuth token | `uv run zd-cli auth logout-oauth` |
| `auth login-slack` | Configure Slack webhook | `uv run zd-cli auth login-slack` |
| `auth status-slack` | Check Slack configuration | `uv run zd-cli auth status-slack` |
| `auth logout-slack` | Remove Slack configuration | `uv run zd-cli auth logout-slack` |

### Slack Integration

| Command | Description | Example |
|---------|-------------|---------|
| `slack-report` | Send support report to Slack | `uv run zd-cli slack-report [analysis_file]` |
| `markdown-report` | Generate detailed markdown report | `uv run zd-cli markdown-report [analysis_file] -o report.md` |

### Configuration

| Command | Description | Example |
|---------|-------------|---------|
| `groups` | List support groups | `uv run zd-cli groups` |
| `tags` | List popular tags | `uv run zd-cli tags` |
| `sla-policies` | List SLA policies | `uv run zd-cli sla-policies` |
| `me` | Get current user (test auth) | `uv run zd-cli me` |

### Query Tool

| Command | Description | Example |
|---------|-------------|---------|
| `query` | Query saved JSON with jq | `uv run zd-cli query  -q comments_slim` |

## Search Query Syntax

The `search` command uses Zendesk's query language:

### Time Filters
- `created>2024-01-01` - Created after date
- `updated=2024-01-20` - Solved on or after date
- `created>1week` - Created in last week (relative)

### Status
- `status:open`
- `status:pending`
- `status:solved`
- `status:closed`
- `status1week
type:problem status --list
```

## Common Workflows

### Investigate a Ticket

```bash
# 1. Get full ticket details
uv run zd-cli ticket-details 12345
# -> Output includes: file_path (e.g., "/zd-cli-/12345/ticket_details_xxx.json")

# 2. Get ticket summary (use the file_path from step 1)
uv run zd-cli query  -q ticket_summary

# 3. Get conversation (truncated bodies)
uv run zd-cli query  -q comments_slim

# 4. Check for attachments
uv run zd-cli query  -q attachments
```

### Find Related Tickets

```bash
# Find all open tickets from same requester
uv run zd-cli search "requester:user@example.com status:open"

# If it's a problem ticket, find linked incidents
uv run zd-cli linked-incidents 12345
```

### Check Queue Health

```bash
# Get available views
uv run zd-cli views

# Check ticket count in queue
uv run zd-cli view-count 123

# Get tickets to triage
uv run zd-cli view-tickets 123
```

### Analyze CSAT

```bash
# Find negative ratings
uv run zd-cli satisfaction-ratings --score bad

# Query for details (use file_path from command output)
uv run zd-cli query  --jq '.data.satisfaction_ratings | map({ticket_id, score, comment})'

# Investigate specific case
uv run zd-cli ticket-details 
```

### Update Ticket Status

```bash
# Change status and add tag
uv run zd-cli update-ticket 12345 --status pending --tags "waiting-customer,tier2"

# Add internal note with Markdown formatting
uv run zd-cli add-note 12345 "**Escalated** to tier 2, waiting for response.\n\n- Root cause: config mismatch\n- Next steps: awaiting customer confirmation"

# Add plain text note (no Markdown conversion)
uv run zd-cli add-note 12345 "Simple plain text note" --plain-text
```

## Command Options

### Global Options

All commands support:
- `--output PATH` - Custom output file path
- `--help` - Show command help

### Search Options

```bash
uv run zd-cli search "query" [OPTIONS]
  --page, -p INT       Page number (default: 1)
  --per-page, -n INT   Results per page (default: 25, max: 100)
  --sort, -s TEXT      Sort field
  --order, -o TEXT     Sort order (asc/desc)
```

### Update Ticket Options

```bash
uv run zd-cli update-ticket TICKET_ID [OPTIONS]
  --status, -s TEXT     New status (open, pending, solved, closed)
  --priority, -p TEXT   New priority (low, normal, high, urgent)
  --assignee, -a TEXT   Assignee ID
  --subject TEXT        New subject
  --tags, -t TEXT       Tags (comma-separated)
  --type TEXT           Ticket type
```

### Satisfaction Ratings Options

```bash
uv run zd-cli satisfaction-ratings [OPTIONS]
  --score, -s TEXT      Filter: good, bad, offered, unoffered
  --start TEXT          Start time (Unix timestamp)
  --end TEXT            End time (Unix timestamp)
```

### Attachment Options

```bash
uv run zd-cli attachment [OPTIONS] URL
  --ticket, -t TEXT     Ticket ID (organizes download under ticket folder)
  --output, -o PATH     Custom output path (overrides --ticket)
```

## File Organization

### Output Path Hierarchy

Output paths are determined in this order:

1. **`--output PATH`** - Full custom path (highest priority)
   ```bash
   uv run zd-cli ticket 12345 --output ./my-ticket.json
   ```

2. **`--ticket ID`** - Organizes files under `/zd-cli-/{ticket_id}/`
   ```bash
   uv run zd-cli attachment --ticket 12345 
   # -> /zd-cli-/12345/attachments/filename.png
   ```

3. **Default** - Falls back to `/zd-cli-/`

### Ticket-Based Organization

When you use ticket-related commands (`ticket`, `ticket-details`, `ticket-metrics`, etc.), files are automatically organized by ticket ID:

```
/zd-cli-/
├── 12345/                          # Ticket 12345
│   ├── ticket_abc123_1234567890.json
│   ├── ticket_details_def456_1234567891.json
│   └── attachments/
│       └── screenshot.png
├── 67890/                          # Ticket 67890
│   └── ticket_details_ghi789_1234567892.json
└── search_xyz_1234567893.json      # Non-ticket commands at root
```

### Duplicate Filename Handling

When downloading attachments, if a file already exists with the same name, a numeric suffix is added:
- `screenshot.png`
- `screenshot_1.png`
- `screenshot_2.png`

## Configuration

### Authentication Setup

Two authentication methods are supported. Both can coexist — OAuth takes priority when a valid token is present.

**Subdomain**: First part of your Zendesk URL (e.g., `mycompany` from `mycompany.zendesk.com`)

#### Option A: OAuth 2.0 (recommended)

Requires an OAuth client configured in Zendesk Admin Center with redirect URL `http://127.0.0.1:8080/callback`.

```bash
uv run zd-cli auth login-oauth --subdomain yourcompany --client-id YOUR_ID --client-secret YOUR_SECRET
```

Opens a browser for authorization. For headless environments, add `--manual` to paste the code instead.

#### Option B: API Token (interactive)

```bash
uv run zd-cli auth login
# Prompts for email, token (hidden), and subdomain
```

#### Option C: API Token (non-interactive)

```bash
uv run zd-cli auth login --email "your@email.com" --token "your-token" --subdomain "yourcompany"
```

#### Option D: Environment Variables

```bash
export ZENDESK_EMAIL="your-email@company.com"
export ZENDESK_TOKEN="your-api-token"
export ZENDESK_SUBDOMAIN="yourcompany"
```

#### Getting an API Token

1. Go to **Admin Center** > **Apps and integrations** > **APIs** > **Zendesk API**
2. Ensure **Token Access** is enabled
3. Click **Add API token**, copy it (shown only once)

#### Check Auth Status

```bash
uv run zd-cli auth status
```

#### Verify Auth Works

```bash
uv run zd-cli me
```

#### Remove Credentials

```bash
uv run zd-cli auth logout       # Remove API token
uv run zd-cli auth logout-oauth  # Remove OAuth token
```

## Notes for Claude Code Users

### Interactive Authentication

The `zd-cli auth login` command supports both interactive and non-interactive modes:

- **Interactive mode**: Prompts for credentials securely (password hidden). This requires running in the user's terminal.
- **Non-interactive mode**: Pass credentials via flags for automation:
  ```bash
  uv run zd-cli auth login --email "you@example.com" --token "your-token" --subdomain "company"
  ```

### When Auth Is Not Configured

If credentials are not configured, commands will fail with a helpful error message. The `zd-cli auth status` command provides detailed guidance:

```bash
uv run zd-cli auth status
```

If not configured, it will show:
- Which environment variables are set (if any)
- Whether a config file exists
- Setup instructions for all authentication methods

### Proactive Auth Check

Before running Zendesk commands for a user, it's helpful to verify auth status first:

```bash
# Quick auth check
uv run zd-cli auth status

# If configured, test it works
uv run zd-cli me
```

## Slack Integration

### Setup

Configure Slack to receive support reports:

```bash
# Interactive mode
uv run zd-cli auth login-slack

# Non-interactive mode
uv run zd-cli auth login-slack --webhook "https://hooks.slack.com/services/..." --channel "#support-reports"
```

**Getting a Webhook URL:**
1. Go to your Slack workspace settings
2. Navigate to **Apps** → **Incoming Webhooks** (or create a new app)
3. Create a new webhook and copy the URL
4. The URL format: `https://hooks.slack.com/services/T.../B.../...`

### Sending Reports

```bash
# Send most recent analysis to configured channel
uv run zd-cli slack-report

# Send specific analysis file
uv run zd-cli slack-report /path/to/support_analysis.json

# Override channel
uv run zd-cli slack-report --channel "#different-channel"
```

### Report Content

The Slack report includes:
- **Overview**: Total tickets, messages, calls detected, unique customers
- **Response Metrics**: Average/median FRT, resolution time (when available)
- **Status Breakdown**: Open, pending, solved, closed counts with icons
- **Priority Breakdown**: Urgent, high, normal, low counts with icons
- **Customer Stats**: Tickets and messages per customer (by email domain)
- **Top Tickets**: Most active tickets by message count with call indicators

Note: Calls are detected on a best-effort basis by searching comment text for keywords like "call", "called", "phone", etc.

### Environment Variables

Alternatively, configure via environment variables:
```bash
export SLACK_WEBHOOK_URL="https://hooks.slack.com/services/..."
export SLACK_CHANNEL="#support-reports"
```

## Support Analytics Workflow

### Support Metrics Report

Generate a comprehensive support report with tickets per customer, messages per ticket, and call detection. **Default period is 2 weeks** unless otherwise specified:

```bash
# 1. Search for tickets in time range
uv run zd-cli search "created>2024-12-22 created -q ids_only | jq -r '.[]'); do
  uv run zd-cli ticket-details $ticket_id
done

# 3. Run analysis queries on stored data
uv run zd-cli query  -q conversation_stats
uv run zd-cli query  -q call_mentions
uv run zd-cli query  -q by_requester
```

### Available Analytics Queries

**Search Results** (`search`):
| Query | Description |
|-------|-------------|
| `by_requester` | Group tickets by requester with counts |
| `by_organization` | Group tickets by organization |
| `top_requesters` | Top 10 requesters by ticket count |
| `top_organizations` | Top 10 organizations by ticket count |

**Ticket Details** (`ticket-details`):
| Query | Description |
|-------|-------------|
| `messages_by_author` | Count messages per author |
| `conversation_stats` | Total messages, public/private, unique authors |
| `call_mentions` | Find comments mentioning calls/phone* |
| `channel_analysis` | Analyze communication channels |

*Note: Calls are detected on a best-effort basis by searching comment text for keywords like "call", "called", "phone", "spoke", etc.

**Ticket Metrics** (`ticket-metrics`):
| Query | Description |
|-------|-------------|
| `kpi_summary` | FRT, resolution times, wait times, reopens |
| `times` | All time-based metrics (calendar & business) |
| `efficiency

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [andmarios](https://github.com/andmarios)
- **Source:** [andmarios/zendesk-skill](https://github.com/andmarios/zendesk-skill)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-andmarios-zendesk-skill-zendesk-skill
- Seller: https://agentstack.voostack.com/s/andmarios
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
