Zendesk CLI (zd)
An unofficial, agent-friendly command-line interface for Zendesk's ticketing REST API. Built for both humans and AI agents.
What it does
zd lets you manage Zendesk tickets from the terminal. List, search, create, update, and delete tickets with structured output that works well in scripts and AI agent workflows. It includes built-in discovery commands (zd commands and zd schema) that let AI agents introspect the CLI at runtime, so they can figure out what's available without hardcoded knowledge.
Installation
Homebrew
brew install johanviberg/tap/zd
go install
go install github.com/johanviberg/zd@latest
Build from source
git clone https://github.com/johanviberg/zd.git
cd zd
go build -o zd
Authentication
Choose one of the methods below. Do not mix methods — zd uses the first credentials it finds (environment variables take priority over stored credentials).
OAuth (recommended)
OAuth is the recommended authentication method. It uses a browser-based consent flow, avoids putting secrets on the command line, and the resulting token is scoped to only the permissions you grant.
1. Register an OAuth client in Zendesk
- In Admin Center, go to Apps and integrations → APIs → OAuth clients, then click Add OAuth client.
- Fill in the fields:
- Name — e.g.
zd CLI (shown to users on the consent screen)
- Description — optional
- Client kind — select Confidential (the CLI runs locally and stores the secret with restricted file permissions)
- Redirect URLs — enter
http://127.0.0.1/callback (the CLI starts a local server on a random port; Zendesk matches on host and path, ignoring the port for localhost)
- Click Save. A Secret field appears — copy it immediately, it is only shown in full once.
- Note the Identifier field — this is the Client ID.
2. Log in
zd auth login \
--subdomain mycompany \
--client-id YOUR_CLIENT_ID \
--client-secret YOUR_CLIENT_SECRET
This opens a browser window for the OAuth consent flow. The CLI requests read write scopes. The token is stored locally.
API token
If you can't use OAuth (e.g. in headless environments or CI), you can authenticate with an API token instead:
zd auth login --method token \
--subdomain mycompany \
--email you@example.com \
--api-token YOUR_API_TOKEN
Environment variables
As an alternative to auth login, you can set environment variables. This is useful for CI/CD or scripts. Environment variables always take priority over stored credentials.
# OAuth token
export ZENDESK_SUBDOMAIN=mycompany
export ZENDESK_OAUTH_TOKEN=your_oauth_token
# Or API token
export ZENDESK_SUBDOMAIN=mycompany
export ZENDESK_EMAIL=you@example.com
export ZENDESK_API_TOKEN=your_token
Check auth status
zd auth status
Quick start
# List recent tickets
zd tickets list
# Show a specific ticket
zd tickets show 12345
# Create a ticket
zd tickets create --subject "Printer broken" --comment "The office printer is not responding"
# Update a ticket
zd tickets update 12345 --status pending --comment "Waiting on vendor" --public=false
# Search tickets
zd tickets search "status:open priority:high"
# Delete a ticket (requires confirmation)
zd tickets delete 12345 --yes
Natural language search
zd tickets search accepts natural language queries, which are locally translated to Zendesk search syntax (no API key needed). Queries already in Zendesk syntax pass through unchanged.
zd tickets search "urgent tickets assigned to jane"
zd tickets search "open tickets created this week"
Demo mode
The --demo flag lets you explore zd without authentication. It generates 100+ synthetic tickets locally.
zd tui --demo
zd tickets list --demo
zd tickets show 42 --demo
Works with tickets list, tickets show, tickets search, tickets comments, and tui.
Interactive TUI
zd includes an optional interactive terminal UI for browsing and managing tickets. Launch it with:
zd tui
The TUI provides:
- Split-panel layout — default side-by-side view with ticket list on the left and detail on the right; auto-collapses to single panel on narrow terminals (<80 cols)
- Ticket list — browse tickets with
j/k or arrow keys, color-coded status and priority
- Panel control — press
tab to switch focus between panels, v to toggle the detail panel
- Infinite scroll — auto-loads the next page when reaching the bottom of the list; or press
n
- Detail view — press
enter to view a ticket's details, description, and comments (scroll with arrows)
- Search — press
/ to search using Zendesk search syntax or natural language (e.g. status:open priority:high), esc to clear
- Comment — press
c to add a comment, toggle between public reply and internal note with tab, submit with ctrl+s
- Status/Priority — press
s or p to change status or priority via a picker
- Auto-refresh — press
r to toggle auto-refresh (polls every 5 min with countdown), R for an immediate refresh; new tickets are highlighted with a star
- Open in browser — press
o to open the selected ticket in your default browser
- Status bar — shows the authenticated user in the bottom bar
- Navigation —
esc to go back, q to quit
The TUI uses the same authentication and service layer as the CLI commands — no additional setup required.
Use --output (or -o) to control how results are formatted:
# Human-readable table (default)
zd tickets list
# JSON
zd tickets list -o json
# Newline-delimited JSON (one object per line, good for piping)
zd tickets list -o ndjson
Field projection
Use --fields to select specific fields:
zd tickets list --fields id,status,subject -o json
Use --include to sideload related data (e.g. users) alongside tickets. This resolves IDs like requester_id and assignee_id into human-readable names and emails:
# Show a ticket with requester and assignee names
zd tickets show 12345 --include users
# List tickets with user names in the table
zd tickets list --include users
# Combine with field projection
zd tickets show 12345 --include users --fields id,subject,requester_name,assignee_name
When users are sideloaded, the output is enriched with requester_name, requester_email, assignee_name, and assignee_email fields.
Errors always go to stderr. When using --output json, errors are also structured JSON on stderr.
Using with AI agents
zd is designed to be used by AI agents like Claude Code. The quickest way to get started is to install the bundled agent skill.
Agent skill
zd ships with an agent skill that teaches your AI agent how to authenticate, discover commands, handle errors, and run common workflows. Install it with the skills CLI:
npx skills add johanviberg/zd
This copies the skill into your agent's skills directory (e.g. .claude/skills/ for Claude Code). Once installed, the agent can use zd without any additional setup in your project files.
Self-describing commands
Two built-in commands make zd discoverable at runtime, even without the skill:
Command discovery
zd commands lists every available command with its flags, types, defaults, and argument names:
zd commands -o json
An agent can call this once to learn the full CLI surface.
zd schema generates a JSON Schema for any command's input, which maps directly to tool-calling conventions:
zd schema --command "tickets create"
This returns a schema with property types, required fields, and defaults that an agent can use to construct valid calls.
Example: Claude Code with CLAUDE.md
Add something like this to your project's CLAUDE.md to give Claude Code access to Zendesk:
## Zendesk
Use the `zd` CLI to interact with Zendesk. Auth is already configured.
- Run `zd commands -o json` to discover available commands
- Run `zd schema --command "<command>"` to get the input schema for a command
- Always use `--output json` when reading ticket data
- Use `--non-interactive` to prevent prompts
You can wrap zd as an MCP tool by pointing your server at the binary and using zd schema to generate input schemas dynamically.
Command reference
| Command |
Description |
zd auth login |
Authenticate with Zendesk (OAuth or API token) |
zd auth logout |
Remove stored credentials |
zd auth status |
Show current authentication status |
zd tickets list |
List tickets (supports --include) |
zd tickets show <id> |
Show a ticket (supports --include) |
zd tickets create |
Create a ticket |
zd tickets update <id> |
Update a ticket |
zd tickets delete <id> |
Delete a ticket |
zd tickets search <query> |
Search tickets (supports --include and natural language) |
zd tickets comments <id> |
List comments on a ticket (supports --include) |
zd articles list |
List Help Center articles |
zd articles show <id> |
Show a Help Center article |
zd articles search <query> |
Search Help Center articles |
zd tui |
Interactive terminal UI for managing tickets |
zd config show |
Show current configuration |
zd config set <key> <value> |
Set a configuration value |
zd commands |
List all commands with flags (for agent discovery) |
zd schema --command "..." |
JSON Schema for a command's input |
zd version |
Print version information |
Global flags
| Flag |
Description |
-o, --output |
Output format: text, json, ndjson (default: text) |
--fields |
Field projection (comma-separated) |
--no-headers |
Omit table headers in text mode |
--non-interactive |
Never prompt for input |
--yes |
Auto-confirm prompts |
--subdomain |
Override Zendesk subdomain |
--profile |
Config profile (default: default) |
--demo |
Use synthetic demo data (no auth required) |
--debug |
Debug logging to stderr |
--trace-id |
Trace ID attached to API requests |
Configuration
Config files live in $XDG_CONFIG_HOME/zd/ (typically ~/.config/zd/):
config.yaml -- settings per profile
credentials.json -- stored auth tokens (file permissions: 0600)
Profiles
You can maintain multiple Zendesk accounts using profiles:
# Login to a second account
zd auth login --profile staging --subdomain mycompany-staging --method token \
--email you@example.com --api-token STAGING_TOKEN
# Use it
zd tickets list --profile staging
Setting config values
zd config set subdomain mycompany
zd config show
Exit codes
| Code |
Meaning |
| 0 |
Success |
| 1 |
General error |
| 2 |
Argument error |
| 3 |
Authentication error |
| 4 |
Retryable error (rate limited) |
| 5 |
Not found |
License
MIT