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.
Install
npx skillscat add andmarios/zendesk-skill Install via the SkillsCat registry.
Zendesk CLI Skill
A command-line interface for comprehensive Zendesk API integration. Run commands via uv run zendesk <command> in the skill directory.
IMPORTANT: Always use
uv runAll commands MUST be run with
uv runto ensure dependencies are available:
- CLI commands:
uv run zendesk <command>- Python scripts:
uv run python src/zendesk_skill/scripts/<script>.pyNever use
python3orpythondirectly - it will fail withModuleNotFoundError.
Quick Start
# Test authentication
uv run zendesk me
# Search tickets
uv run zendesk search "status:open priority:urgent"
# Get ticket details
uv run zendesk ticket-details 12345
# Query saved response (path shown in command output)
uv run zendesk query <temp>/zendesk-skill/ticket_details_xxx.json -q comments_slimKey Concepts
Save First, Query Later
All API responses are automatically saved to <temp>/zendesk-skill/ (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:
- Run a command (e.g.,
uv run zendesk ticket-details 12345) - Response saved to a JSON file (path shown in output)
- Use
uv run zendesk query <file> -q <query_name>to extract specific data - 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 zendesk search "status:open" |
ticket |
Get ticket by ID | uv run zendesk ticket 12345 |
ticket-details |
Get ticket + all comments | uv run zendesk ticket-details 12345 |
linked-incidents |
Get incidents linked to problem | uv run zendesk linked-incidents 12345 |
attachment |
Download attachment file | uv run zendesk attachment --ticket 12345 <url> |
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 zendesk update-ticket 12345 --status pending |
create-ticket |
Create new ticket (Markdown) | uv run zendesk create-ticket "Subject" "**Bold** description" |
add-note |
Add internal note (Markdown) | uv run zendesk add-note 12345 "**Investigation:** found the issue" |
add-comment |
Add public comment (Markdown) | uv run zendesk 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 zendesk ticket-metrics 12345 |
list-metrics |
List metrics for tickets | uv run zendesk list-metrics |
satisfaction-ratings |
List CSAT ratings | uv run zendesk satisfaction-ratings --score bad |
satisfaction-rating |
Get single rating | uv run zendesk satisfaction-rating 67890 |
Views (Queue Management)
| Command | Description | Example |
|---|---|---|
views |
List available views | uv run zendesk views |
view-count |
Get ticket count | uv run zendesk view-count 123 |
view-tickets |
Get tickets from view | uv run zendesk view-tickets 123 |
Users & Organizations
| Command | Description | Example |
|---|---|---|
user |
Get user by ID | uv run zendesk user 12345 |
search-users |
Search users | uv run zendesk search-users "john@example.com" |
org |
Get organization by ID | uv run zendesk org 67890 |
search-orgs |
Search organizations | uv run zendesk search-orgs "Acme" |
Authentication
| Command | Description | Example |
|---|---|---|
auth login |
Configure Zendesk API token credentials | uv run zendesk auth login |
auth login-oauth |
OAuth 2.0 login (opens browser) | uv run zendesk auth login-oauth --subdomain co |
auth status |
Check auth configuration (token + OAuth) | uv run zendesk auth status |
auth logout |
Remove API token credentials | uv run zendesk auth logout |
auth logout-oauth |
Remove OAuth token | uv run zendesk auth logout-oauth |
auth login-slack |
Configure Slack webhook | uv run zendesk auth login-slack |
auth status-slack |
Check Slack configuration | uv run zendesk auth status-slack |
auth logout-slack |
Remove Slack configuration | uv run zendesk auth logout-slack |
Slack Integration
| Command | Description | Example |
|---|---|---|
slack-report |
Send support report to Slack | uv run zendesk slack-report [analysis_file] |
markdown-report |
Generate detailed markdown report | uv run zendesk markdown-report [analysis_file] -o report.md |
Configuration
| Command | Description | Example |
|---|---|---|
groups |
List support groups | uv run zendesk groups |
tags |
List popular tags | uv run zendesk tags |
sla-policies |
List SLA policies | uv run zendesk sla-policies |
me |
Get current user (test auth) | uv run zendesk me |
Query Tool
| Command | Description | Example |
|---|---|---|
query |
Query saved JSON with jq | uv run zendesk query <file> -q comments_slim |
Search Query Syntax
The search command uses Zendesk's query language:
Time Filters
created>2024-01-01- Created after dateupdated<2024-01-15- Updated before datesolved>=2024-01-20- Solved on or after datecreated>1week- Created in last week (relative)
Status
status:openstatus:pendingstatus:solvedstatus:closedstatus<solved- New, open, or pending
Priority
priority:urgentpriority:highpriority:normalpriority:low
Assignment
assignee:me- Assigned to current userassignee:none- Unassignedassignee_id:12345- Specific agentgroup:Support- Assigned to group
Tags
tags:billingtags:urgenttags:vip tags:enterprise- Multiple tags (AND)
Type
type:incidenttype:problemtype:questiontype:task
People
requester:user@example.comrequester_id:12345organization:acmesubmitter:agent@company.com
Combinations
status:open priority:urgent tags:escalated
status:pending assignee:me updated>1week
type:problem status<solved
requester:*@bigclient.com status:openText Search
subject:password reset- Search in subjectdescription:error- Search in descriptionpassword reset- Search anywhere
Named Queries for jq
After fetching data, use zendesk query with these named queries:
For Ticket Details (ticket-details)
| Query | Description |
|---|---|
ticket_summary |
Get ticket without comments |
comments_slim |
Comments with truncated body (no HTML) |
comments_full |
Full comment bodies |
attachments |
List all attachments from comments |
comment_count |
Count by public/private |
latest_comment |
Most recent comment |
For Search Results (search)
| Query | Description |
|---|---|
ids_only |
Just ticket IDs |
summary_list |
ID, subject, status, priority |
by_status |
Group tickets by status |
by_priority |
Group by priority |
pagination |
Pagination info |
Custom jq Examples
# Get specific fields from ticket
uv run zendesk query file.json --jq '.data.ticket | {id, subject, status, tags}'
# Filter comments by author
uv run zendesk query file.json --jq '[.data.comments[] | select(.author_id == 12345)]'
# Get timestamps only
uv run zendesk query file.json --jq '.data.comments | map({created_at, author_id})'List Available Queries
uv run zendesk query <file_path> --listCommon Workflows
Investigate a Ticket
# 1. Get full ticket details
uv run zendesk ticket-details 12345
# -> Output includes: file_path (e.g., "<temp>/zendesk-skill/12345/ticket_details_xxx.json")
# 2. Get ticket summary (use the file_path from step 1)
uv run zendesk query <file_path> -q ticket_summary
# 3. Get conversation (truncated bodies)
uv run zendesk query <file_path> -q comments_slim
# 4. Check for attachments
uv run zendesk query <file_path> -q attachmentsFind Related Tickets
# Find all open tickets from same requester
uv run zendesk search "requester:user@example.com status:open"
# If it's a problem ticket, find linked incidents
uv run zendesk linked-incidents 12345Check Queue Health
# Get available views
uv run zendesk views
# Check ticket count in queue
uv run zendesk view-count 123
# Get tickets to triage
uv run zendesk view-tickets 123Analyze CSAT
# Find negative ratings
uv run zendesk satisfaction-ratings --score bad
# Query for details (use file_path from command output)
uv run zendesk query <file_path> --jq '.data.satisfaction_ratings | map({ticket_id, score, comment})'
# Investigate specific case
uv run zendesk ticket-details <ticket_id>Update Ticket Status
# Change status and add tag
uv run zendesk update-ticket 12345 --status pending --tags "waiting-customer,tier2"
# Add internal note with Markdown formatting
uv run zendesk 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 zendesk add-note 12345 "Simple plain text note" --plain-textCommand Options
Global Options
All commands support:
--output PATH- Custom output file path--help- Show command help
Search Options
uv run zendesk 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
uv run zendesk 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 typeSatisfaction Ratings Options
uv run zendesk 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
uv run zendesk 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:
--output PATH- Full custom path (highest priority)uv run zendesk ticket 12345 --output ./my-ticket.json--ticket ID- Organizes files under<temp>/zendesk-skill/{ticket_id}/uv run zendesk attachment --ticket 12345 <url> # -> <temp>/zendesk-skill/12345/attachments/filename.pngDefault - Falls back to
<temp>/zendesk-skill/
Ticket-Based Organization
When you use ticket-related commands (ticket, ticket-details, ticket-metrics, etc.), files are automatically organized by ticket ID:
<temp>/zendesk-skill/
├── 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 rootDuplicate Filename Handling
When downloading attachments, if a file already exists with the same name, a numeric suffix is added:
screenshot.pngscreenshot_1.pngscreenshot_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.
uv run zendesk auth login-oauth --subdomain yourcompany --client-id YOUR_ID --client-secret YOUR_SECRETOpens a browser for authorization. For headless environments, add --manual to paste the code instead.
Option B: API Token (interactive)
uv run zendesk auth login
# Prompts for email, token (hidden), and subdomainOption C: API Token (non-interactive)
uv run zendesk auth login --email "your@email.com" --token "your-token" --subdomain "yourcompany"Option D: Environment Variables
export ZENDESK_EMAIL="your-email@company.com"
export ZENDESK_TOKEN="your-api-token"
export ZENDESK_SUBDOMAIN="yourcompany"Getting an API Token
- Go to Admin Center > Apps and integrations > APIs > Zendesk API
- Ensure Token Access is enabled
- Click Add API token, copy it (shown only once)
Check Auth Status
uv run zendesk auth statusVerify Auth Works
uv run zendesk meRemove Credentials
uv run zendesk auth logout # Remove API token
uv run zendesk auth logout-oauth # Remove OAuth tokenNotes for Claude Code Users
Interactive Authentication
The zendesk 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:
uv run zendesk 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 zendesk auth status command provides detailed guidance:
uv run zendesk auth statusIf 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:
# Quick auth check
uv run zendesk auth status
# If configured, test it works
uv run zendesk meSlack Integration
Setup
Configure Slack to receive support reports:
# Interactive mode
uv run zendesk auth login-slack
# Non-interactive mode
uv run zendesk auth login-slack --webhook "https://hooks.slack.com/services/..." --channel "#support-reports"Getting a Webhook URL:
- Go to your Slack workspace settings
- Navigate to Apps → Incoming Webhooks (or create a new app)
- Create a new webhook and copy the URL
- The URL format:
https://hooks.slack.com/services/T.../B.../...
Sending Reports
# Send most recent analysis to configured channel
uv run zendesk slack-report
# Send specific analysis file
uv run zendesk slack-report /path/to/support_analysis.json
# Override channel
uv run zendesk 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:
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:
# 1. Search for tickets in time range
uv run zendesk search "created>2024-12-22 created<2025-01-22"
# 2. Get ticket details for each result (for message analysis)
for ticket_id in $(uv run zendesk query <search_file> -q ids_only | jq -r '.[]'); do
uv run zendesk ticket-details $ticket_id
done
# 3. Run analysis queries on stored data
uv run zendesk query <ticket_details_file> -q conversation_stats
uv run zendesk query <ticket_details_file> -q call_mentions
uv run zendesk query <search_file> -q by_requesterAvailable 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 |
Reopens, replies, stations |
List Metrics (list-metrics):
| Query | Description |
|---|---|
frt_summary |
First reply time across tickets |
avg_frt |
Average FRT with min/max |
resolution_summary |
Resolution times across tickets |
reopen_rate |
Tickets with reopens (FCR issues) |
Customer Identification
Customers are identified by:
- Organization - If
organization_idis set on the user - Email domain - Fallback when no organization is set
To get organization info:
# Get user with organization
uv run zendesk user <user_id>
# Get organization details
uv run zendesk org <org_id>Python Analysis Script
For comprehensive analysis, use the included script:
# Default: 2-week period ending today
uv run python src/zendesk_skill/scripts/analyze_support_metrics.py [search_file]
# Explicit period
uv run python src/zendesk_skill/scripts/analyze_support_metrics.py search.json --start 2026-01-09 --end 2026-01-23Options:
--start DATE- Period start date (YYYY-MM-DD). Default: 14 days ago--end DATE- Period end date (YYYY-MM-DD). Default: today--output DIR- Output directory
This generates:
- Tickets per customer (by email domain)
- Messages per customer
- Messages per ticket
- Call detection results
- FRT and resolution statistics
- Status and priority breakdown
- JSON output at
<temp>/zendesk-skill/support_analysis.json
Tips
- Don't hallucinate dates: When constructing date-based queries, verify the current date first:
date +%Y-%m-%d - Always check file paths: Command output includes the saved file path - use it for follow-up queries
- Use named queries first: They're optimized for common patterns
- Combine queries: Run multiple jq queries on same file for different views
- Watch for pagination: Search results may have more pages - check
next_pagein output - Test auth first: Use
uv run zendesk meto verify credentials work - Use --help: All commands have detailed help:
uv run zendesk search --help