Skip to content

Latest commit

 

History

7 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Zendesk Admin Management Scripts

A modular collection of Python scripts for automating common Zendesk administration tasks. Built for support teams that need to audit, maintain, and bulk-manage their Zendesk instance beyond what the native UI offers.

Scripts

Admin & Management

Script Purpose
Zombie Trigger Auditor Find triggers/automations with zero usage
Bulk Macro Search & Replace Search and replace text across all macros
User Permission Snapshotter Export admin/agent users to CSV for audits
Tag Cleanup Bot Identify orphan tags for consolidation

Security & Compliance

Script Purpose
Suspended Ticket Spam-Killer Bulk-delete suspended tickets by cause pattern
Attachment Retention Enforcer Redact attachments from old tickets for privacy/storage
Inactive API Token Auditor Find OAuth tokens unused in 30+ days for revocation

Ticket Analytics & Reporting

Script Purpose
Ticket Volume Analyzer Analyze ticket volume by channel, brand, priority with PDF report + CSV

Architecture

All scripts share a common library (zendesk_admin/) that handles authentication, API requests, pagination, and rate limiting. This makes it easy to add new scripts without duplicating boilerplate.

graph TD
    subgraph "scripts/ — Admin & Management"
        A[zombie_trigger_auditor.py]
        B[bulk_macro_search_replace.py]
        C[user_permission_snapshotter.py]
        D[tag_cleanup_bot.py]
    end

    subgraph "scripts/ — Security & Compliance"
        S1[suspended_ticket_spam_killer.py]
        S2[attachment_retention_enforcer.py]
        S3[inactive_api_token_auditor.py]
    end

    subgraph "scripts/ — Analytics & Reporting"
        R1[ticket_volume_analyzer.py]
    end

    subgraph "zendesk_admin/"
        F["config.py<br/>(load credentials)"]
        G["client.py<br/>(API client)"]
        H["cli.py<br/>(argument parsing)"]
        I["utils.py<br/>(CSV & JSON output)"]
    end

    A & B & C & D --> F & G & H & I
    S1 & S2 & S3 --> F & G & H & I
    R1 --> F & G & H & I

    G -->|"HTTP requests<br/>with auth"| J[Zendesk REST API v2]
    G -->|"handles"| K["Rate Limiting<br/>(429 + Retry-After)"]
    G -->|"handles"| L["Pagination<br/>(cursor + offset)"]
Loading

Request Flow

sequenceDiagram
    participant Script
    participant ZendeskClient
    participant ZendeskAPI

    Script->>ZendeskClient: paginate("/api/v2/triggers", "triggers")
    loop Each page
        ZendeskClient->>ZendeskAPI: GET /api/v2/triggers?page[size]=100
        alt 200 OK
            ZendeskAPI-->>ZendeskClient: {triggers: [...], meta: {has_more}, links: {next}}
            ZendeskClient-->>Script: yield individual triggers
        else 429 Rate Limited
            ZendeskAPI-->>ZendeskClient: 429 + Retry-After: 30
            Note over ZendeskClient: Sleep for Retry-After seconds
            ZendeskClient->>ZendeskAPI: Retry same request
        end
    end
Loading

Quick Start

Prerequisites

  • Python 3.9+
  • A Zendesk account with Admin access
  • An API token (Admin Center → Apps and Integrations → APIs → Zendesk API)

Installation

# Clone the repository
git clone https://github.com/mohdasim/Zendesk-Admin-Management-Scripts.git
cd Zendesk-Admin-Management-Scripts

# Install dependencies
pip install -r requirements.txt

# Configure credentials
cp .env.example .env
# Edit .env with your Zendesk subdomain, email, and API token

Configuration

Edit the .env file with your Zendesk credentials:

ZENDESK_SUBDOMAIN=yourcompany        # yourcompany.zendesk.com
ZENDESK_EMAIL=admin@yourcompany.com  # Admin email address
ZENDESK_API_TOKEN=your_api_token     # From Admin Center

All scripts read credentials from the .env file by default. Use --env-file to specify a different path.


Script Details

1. Zombie Trigger Auditor

Identifies triggers and automations with zero usage over a configurable time period. Uses Zendesk's built-in usage statistics (usage_1h, usage_24h, usage_7d, usage_30d) for accurate detection.

flowchart TD
    A[Start] --> B[Load Configuration]
    B --> C[Fetch Triggers<br/>with usage stats]
    C --> D[Fetch Automations<br/>with usage stats]
    D --> E{Check usage for<br/>selected period}
    E -->|usage == 0| F[Add to zombie list]
    E -->|usage > 0| G[Skip - actively firing]
    F --> H[Generate Report]
    G --> H
    H --> I[Output JSON report<br/>+ console summary]
Loading

Usage

# Find triggers/automations with zero usage in the last 7 days (default)
python -m scripts.zombie_trigger_auditor

# Check for zero usage in the last 30 days
python -m scripts.zombie_trigger_auditor --period 30d

# Include disabled triggers in the report
python -m scripts.zombie_trigger_auditor --include-inactive

# Save report to file
python -m scripts.zombie_trigger_auditor --period 30d -o zombies.json

# Enable debug logging
python -m scripts.zombie_trigger_auditor -v

Options

Flag Default Description
--period 7d Usage period: 1h, 24h, 7d, or 30d
--include-inactive off Include disabled triggers/automations
--output, -o stdout Save JSON report to file
--verbose, -v off Enable debug logging
--env-file .env Path to credentials file

Sample Output

Auditing triggers and automations with zero usage in the last 7 days...

Found 3 zombie items (zero usage in 7 days):
  - Triggers: 2
  - Automations: 1

Type         ID                   Active   Title
--------------------------------------------------------------------------------
trigger      39147977549975       True     Auto-Close Walmart Notifications
trigger      25960167241239       True     Close Ticket
automation   21290448620695       True     Resolve stale pending tickets

2. Bulk Macro Content Search & Replace

Searches for specific text or URLs across all macro action values and optionally replaces them. Supports dry-run mode for safe previewing before making changes.

flowchart TD
    A[Start] --> B[Load Configuration]
    B --> C[Fetch all Macros]
    C --> D[Search action values<br/>for --search text]
    D --> E{Matches found?}
    E -->|No| F[Report: 0 matches]
    E -->|Yes| G{--replace provided?}
    G -->|No| H[Report matches<br/>search-only mode]
    G -->|Yes| I{--dry-run?}
    I -->|Yes| J[Preview changes<br/>no API writes]
    I -->|No| K[PUT updated macros<br/>via API]
    K --> L[Report updated macros]
Loading

Usage

# Search only - find macros containing a URL
python -m scripts.bulk_macro_search_replace --search "help.oldcompany.com"

# Preview replacements (dry run)
python -m scripts.bulk_macro_search_replace \
  --search "help.oldcompany.com" \
  --replace "help.newcompany.com" \
  --dry-run

# Apply replacements
python -m scripts.bulk_macro_search_replace \
  --search "help.oldcompany.com" \
  --replace "help.newcompany.com"

# Save match report to file
python -m scripts.bulk_macro_search_replace --search "old-brand" -o matches.json

Options

Flag Default Description
--search, -s (required) Text or URL to find in macros
--replace, -r (none) Replacement text (omit for search-only)
--dry-run off Preview changes without applying
--output, -o stdout Save match report to JSON file
--verbose, -v off Enable debug logging
--env-file .env Path to credentials file

3. User Permission Snapshotter

Exports a CSV of all Admin and Agent users with their last login date, custom role name, and permissions. Designed for monthly security audits.

flowchart TD
    A[Start] --> B[Load Configuration]
    B --> C[Fetch Custom Roles<br/>into lookup dict]
    C --> D[Fetch Users<br/>filtered: admin + agent]
    D --> E[Join user with<br/>custom role details]
    E --> F[Extract permission<br/>names from role config]
    F --> G[Write CSV file]
    G --> H[Print summary:<br/>admins, agents, never logged in]
Loading

Usage

# Export to default file (user_permissions_snapshot.csv)
python -m scripts.user_permission_snapshotter

# Export to custom file path
python -m scripts.user_permission_snapshotter -o audit_march_2026.csv

Options

Flag Default Description
--output, -o user_permissions_snapshot.csv Output CSV file path
--verbose, -v off Enable debug logging
--env-file .env Path to credentials file

CSV Columns

Column Description
id Zendesk user ID
name Full name
email Email address
role admin or agent
custom_role_id Custom role ID (Enterprise+)
custom_role_name Custom role name
custom_role_permissions Semicolon-separated list of enabled permissions
last_login_at Last login timestamp (ISO 8601)
two_factor_auth_enabled Whether 2FA is enabled
active Whether the user is active
suspended Whether the user is suspended
created_at Account creation date
updated_at Last profile update date

4. Tag Cleanup Bot

Identifies orphan tags -- tags that exist on tickets but are not referenced in any Trigger, Automation, or View. Generates a report for tag consolidation.

flowchart TD
    A[Start] --> B[Load Configuration]
    B --> C[Step 1: Collect tags<br/>from tickets via Tags API]
    C --> D[Step 2: Scan Triggers<br/>for tag references]
    D --> E[Step 2: Scan Automations<br/>for tag references]
    E --> F[Step 2: Scan Views<br/>for tag references]
    F --> G[Step 3: Compare<br/>ticket tags vs referenced tags]
    G --> H{Tag in any<br/>business rule?}
    H -->|Yes| I[Referenced - skip]
    H -->|No| J[Orphan tag]
    J --> K[Filter by<br/>--min-tickets threshold]
    K --> L[Sort by ticket<br/>count descending]
    L --> M[Output report]
Loading

Usage

# Find all orphan tags
python -m scripts.tag_cleanup_bot

# Only report orphan tags on 5+ tickets
python -m scripts.tag_cleanup_bot --min-tickets 5

# Save report to file
python -m scripts.tag_cleanup_bot -o orphan_tags.json

# Verbose output to see API calls
python -m scripts.tag_cleanup_bot -v

Options

Flag Default Description
--min-tickets 1 Minimum ticket count to include in report
--output, -o stdout Save JSON report to file
--verbose, -v off Enable debug logging
--env-file .env Path to credentials file

Sample Output

Step 1: Collecting tags from tickets...
  Found 342 tags on tickets

Step 2: Scanning business rules for tag references...
  Scanned 21 triggers
  Scanned 5 automations
  Scanned 15 views

  Total unique tags referenced in business rules: 28

Step 3: Identifying orphan tags...

Results:
  Tags on tickets:              342
  Tags in business rules:       28
  Orphan tags (>= 1 tickets):   314

Tag                                      Ticket Count
------------------------------------------------------
legacy_import                                     1847
old_category_electronics                           523
temp_migration_batch2                              201
...

Security & Compliance Scripts

5. Suspended Ticket Spam-Killer

Bulk-deletes suspended tickets based on specific cause patterns (e.g., "Detected as spam", "Automated response mail") to keep the suspended queue manageable. Operates in report-only mode by default — requires --delete flag to actually remove tickets.

flowchart TD
    A[Start] --> B[Load Configuration]
    B --> C[Fetch all<br/>Suspended Tickets]
    C --> D{Filter by<br/>cause pattern?}
    D -->|Yes| E[Match cause<br/>substring, case-insensitive]
    D -->|No| F[Include all]
    E --> G{Filter by<br/>age?}
    F --> G
    G -->|--older-than N| H[Exclude tickets<br/>newer than N days]
    G -->|No age filter| I[Include all ages]
    H --> J[Group by cause<br/>for summary]
    I --> J
    J --> K{--delete flag?}
    K -->|No| L[Report-only mode<br/>show matches]
    K -->|Yes| M{--dry-run?}
    M -->|Yes| L
    M -->|No| N[Bulk delete in<br/>batches of 100]
    N --> O[Report deleted count]
Loading

Usage

# List all suspended tickets (report only)
python -m scripts.suspended_ticket_spam_killer

# List suspended tickets matching specific causes
python -m scripts.suspended_ticket_spam_killer --causes "Detected as spam"

# Multiple cause patterns + age filter
python -m scripts.suspended_ticket_spam_killer \
  --causes "Detected as spam" "Automated response mail" \
  --older-than 30

# Preview deletions (dry run)
python -m scripts.suspended_ticket_spam_killer \
  --causes "Detected as spam" --delete --dry-run

# Actually delete matched tickets
python -m scripts.suspended_ticket_spam_killer \
  --causes "Detected as spam" --older-than 60 --delete

# Save report to file
python -m scripts.suspended_ticket_spam_killer --causes "Detected as spam" -o spam_report.json

Options

Flag Default Description
--causes, -c (all) Cause patterns to match (case-insensitive substring)
--older-than (none) Only target tickets older than N days
--delete off Actually delete matched tickets
--dry-run off Preview deletions (same as omitting --delete)
--output, -o stdout Save match report to JSON file
--verbose, -v off Enable debug logging
--env-file .env Path to credentials file

Sample Output

Scanning suspended tickets (causes matching: 'Detected as spam', older than 30 days)...

Found 47 matching suspended ticket(s):
  - Detected as spam: 42
  - Detected as spam by Zendesk: 5

ID                   Created                Cause                          Subject
----------------------------------------------------------------------------------------------------
8234567890123        2026-01-15             Detected as spam               Win a free iPhone!!!
8234567890456        2026-01-20             Detected as spam               Urgent business proposal
  ... and 45 more

[REPORT-ONLY MODE] No tickets deleted.
Use --delete to permanently remove these tickets.

6. Attachment Retention Enforcer

Identifies tickets older than a configurable number of years and redacts attachments while preserving conversation text. Zendesk replaces redacted attachments with an empty redacted.txt file. Helps manage storage costs and comply with data retention/privacy policies (e.g., GDPR).

WARNING: Redaction is PERMANENT and cannot be undone.

flowchart TD
    A[Start] --> B[Load Configuration]
    B --> C["Search tickets created<br/>before cutoff date<br/>(Search API)"]
    C --> D[Limit to --max-tickets<br/>for safety]
    D --> E[For each ticket:<br/>fetch comments +<br/>attachments]
    E --> F{Attachments<br/>found?}
    F -->|No| G[Skip ticket]
    F -->|Yes| H[Record attachment<br/>details + size]
    G --> I[Summary report:<br/>tickets, attachments, size]
    H --> I
    I --> J{--redact flag?}
    J -->|No| K[Report-only mode]
    J -->|Yes| L{--dry-run?}
    L -->|Yes| K
    L -->|No| M["PUT .../redact<br/>for each attachment"]
    M --> N["Attachment replaced<br/>with redacted.txt"]
    N --> O[Report redacted count<br/>+ storage freed]
Loading

Usage

# Report attachments on tickets older than 2 years (report only)
python -m scripts.attachment_retention_enforcer --older-than-years 2

# Filter to closed tickets only
python -m scripts.attachment_retention_enforcer --older-than-years 2 --status closed

# Preview redaction (dry run)
python -m scripts.attachment_retention_enforcer --older-than-years 3 --redact --dry-run

# Actually redact attachments (PERMANENT)
python -m scripts.attachment_retention_enforcer --older-than-years 3 --status closed --redact

# Process more tickets (default limit: 100)
python -m scripts.attachment_retention_enforcer --older-than-years 2 --max-tickets 500

# Save attachment report to file
python -m scripts.attachment_retention_enforcer --older-than-years 2 -o attachments.json

Options

Flag Default Description
--older-than-years (required) Target tickets created more than N years ago
--status (all) Filter by ticket status: new/open/pending/hold/solved/closed
--redact off Actually redact attachments (permanent!)
--dry-run off Preview redactions (same as omitting --redact)
--max-tickets 100 Max tickets to process per run (safety limit)
--output, -o stdout Save attachment report to JSON file
--verbose, -v off Enable debug logging
--env-file .env Path to credentials file

Sample Output

Searching for tickets created before 2024-03-31 with status 'closed'...
Found 234 ticket(s) matching criteria.
Limiting to first 100 tickets (use --max-tickets to adjust).

Scanning 100 ticket(s) for attachments...
  Scanned 20/100 tickets (45 attachments found)
  Scanned 40/100 tickets (89 attachments found)
  Scanned 100/100 tickets (156 attachments found)

Results:
  Tickets scanned:           100
  Tickets with attachments:  67
  Total attachments found:   156
  Total attachment size:     487.3 MB

Ticket       Attachment          Size  File Name
---------------------------------------------------------------------------
12345        99001            2.3 MB  invoice_scan.pdf
12345        99002          512.0 KB  receipt.jpg
12890        99155           15.7 MB  debug_log.zip
  ... and 153 more (see full report with -o)

[REPORT-ONLY MODE] No attachments redacted.
Use --redact to permanently redact these attachments.

7. Inactive API Token Auditor

Lists all OAuth access tokens and API tokens, then highlights those that haven't been used within a configurable number of days, alerting the admin to revoke them for security. Cross-references token owners with user details for context.

The script audits two token types:

  • OAuth tokens via /api/v2/oauth/tokens (tracks last use via used_at field)
  • API tokens via /api/v2/api_tokens (tracks last use via last_used_at field)

If the API tokens endpoint is not available on your Zendesk plan (returns 403/404), the script falls back gracefully and reports only OAuth tokens.

flowchart TD
    A[Start] --> B[Load Configuration]
    B --> C{--token-type?}
    C -->|all or oauth| D[Fetch OAuth tokens<br/>/api/v2/oauth/tokens]
    C -->|all or api| E[Fetch API tokens<br/>/api/v2/api_tokens]
    C -->|all| D & E
    E --> F{Endpoint<br/>available?}
    F -->|200 OK| G[Parse API tokens]
    F -->|403/404| H[Log warning<br/>continue without]
    D --> I[Collect user IDs<br/>from all tokens]
    G --> I
    H --> I
    I --> J[Batch-fetch user<br/>details via show_many]
    J --> K[Classify each token]
    K --> L{Last used field<br/>present?}
    L -->|null| M["Status: never_used"]
    L -->|has date| N{"Older than<br/>--inactive-days?"}
    N -->|Yes| O["Status: inactive"]
    N -->|No| P["Status: active"]
    M & O & P --> Q[Sort: never_used first<br/>then inactive by days]
    Q --> R[Summary by type:<br/>OAuth + API counts]
    R --> S[Output report<br/>JSON or CSV]
Loading

Usage

# Audit all token types with default 30-day inactivity threshold
python -m scripts.inactive_api_token_auditor

# Custom inactivity threshold (90 days)
python -m scripts.inactive_api_token_auditor --inactive-days 90

# Audit only OAuth tokens
python -m scripts.inactive_api_token_auditor --token-type oauth

# Audit only API tokens
python -m scripts.inactive_api_token_auditor --token-type api

# Export as CSV
python -m scripts.inactive_api_token_auditor --format csv -o token_audit.csv

# Export as JSON
python -m scripts.inactive_api_token_auditor -o token_audit.json

Options

Flag Default Description
--inactive-days 30 Mark tokens inactive if unused for N days
--token-type all Token type to audit: all, oauth, or api
--format json Output format: json or csv
--output, -o stdout Save report to file
--verbose, -v off Enable debug logging
--env-file .env Path to credentials file

Sample Output

Fetching OAuth tokens...
  Found 12 OAuth token(s).
Fetching API tokens...
  Found 5 API token(s).
Fetching details for 10 token owner(s)...

Token Audit Summary (inactive threshold: 30 days):
  Total tokens:    17
    OAuth tokens:  12
    API tokens:    5
  Active:          9
  Inactive:        5
  Never used:      3

Tokens requiring attention (8):
Type        ID           Status        Last Used      Days   User                      Description/Scopes
--------------------------------------------------------------------------------------------------------------
API         78901        never_used    never          N/A    staging-bot@company.com   Staging integration
API         78905        never_used    never          N/A    test@company.com          Test token
OAuth       44012        never_used    never          N/A    dev-bot@company.com       read, write
OAuth       44005        inactive      2026-01-15     75     old-integration@co.com    read, write
API         78903        inactive      2026-02-10     49     data-sync@company.com     Data sync service
OAuth       44009        inactive      2026-02-01     58     api-user@company.com      read
OAuth       44011        inactive      2026-02-20     39     reports@company.com       read
API         78904        inactive      2026-02-25     34     export@company.com        CSV export tool

Recommendation: Review and revoke inactive/unused tokens in
Admin Center > Apps and Integrations > APIs

Ticket Analytics & Reporting Scripts

8. Ticket Volume Analyzer

Pulls ticket data from the Zendesk Search API for a configurable date range, breaks it down by channel, brand, priority, and time period, then generates a multi-page PDF report with charts and summary tables alongside a CSV export of all ticket data.

The PDF report includes:

  • Executive summary with key metrics
  • Summary tables (channel, brand, priority, status breakdowns)
  • Volume over time trend chart
  • Channel and brand analysis (pie charts + stacked bar over time)
  • Priority analysis with color-coded charts
  • Hourly heatmap (day-of-week x hour-of-day)
flowchart TD
    A[Start] --> B[Parse date range<br/>and period args]
    B --> C[Fetch all Brands<br/>/api/v2/brands]
    C --> D["Fetch tickets via<br/>Search API with<br/>date range filter"]
    D --> E{Results >= 1000?}
    E -->|Yes, range > 1 day| F[Bisect date range<br/>and recurse both halves]
    F --> D
    E -->|No / single day| G[Deduplicate<br/>by ticket ID]
    G --> H[Extract: channel,<br/>brand, priority, status]
    H --> I[Aggregate by:<br/>field, time+field,<br/>hourly heatmap]
    I --> J[Generate charts<br/>matplotlib, Agg backend]
    J --> K["Build PDF report<br/>(reportlab + chart PNGs)"]
    K --> L[Write CSV export]
    L --> M[Print console summary]
Loading

Usage

# Analyze tickets from Q1 2026 with weekly bucketing (default)
python -m scripts.ticket_volume_analyzer --start-date 2026-01-01 --end-date 2026-03-31

# Monthly period with custom output directory
python -m scripts.ticket_volume_analyzer \
  --start-date 2026-01-01 \
  --end-date 2026-03-31 \
  --period monthly \
  --output-dir ./reports

# Daily breakdown for March
python -m scripts.ticket_volume_analyzer \
  --start-date 2026-03-01 \
  --end-date 2026-04-01 \
  --period daily

# With debug logging
python -m scripts.ticket_volume_analyzer --start-date 2026-01-01 -v

Options

Flag Default Description
--start-date (required) Start date inclusive (YYYY-MM-DD)
--end-date today End date exclusive (YYYY-MM-DD)
--period weekly Time bucketing: daily, weekly, or monthly
--output-dir . Directory for output files (created if needed)
--verbose, -v off Enable debug logging
--env-file .env Path to credentials file

Output Files

File Format Description
ticket_volume_report_YYYYMMDD.pdf PDF Multi-page report with charts and summary tables
ticket_volume_data_YYYYMMDD.csv CSV Raw ticket data with columns: ticket_id, created_at, subject, channel, brand_name, priority, status, via_source

PDF Report Pages

Page Content
1 Executive summary: date range, key metrics, top channel/brand
2 Summary tables: channel, brand, priority, and status breakdowns with counts and percentages
3 Volume over time line chart
4 Channel analysis: pie chart + stacked bar chart over time
5 Brand analysis: pie chart + stacked bar chart over time
6 Priority analysis: bar chart + color-coded stacked bar over time
7 Hourly heatmap: ticket creation by day-of-week x hour-of-day (UTC)

Sample Output

Fetching brands...
  Found 3 brand(s).
Searching tickets from 2026-01-01 to 2026-03-31...
  Found 8,247 ticket(s).
Generating charts and PDF report...
  PDF report: ./reports/ticket_volume_report_20260331.pdf
Wrote 8,247 rows to ./reports/ticket_volume_data_20260331.csv

--- Summary ---
  Date range:     2026-01-01 to 2026-03-31
  Period:         weekly
  Total tickets:  8,247
  Channels:       4
  Brands:         3
  Top channel:    Email (5,832 tickets)
  Top brand:      OREI (4,129 tickets)

Adding a New Script

The project is designed for easy extension. To add a new script:

  1. Create a new file in scripts/:
#!/usr/bin/env python3
"""Description of your new script."""

import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).resolve().parent.parent))

from zendesk_admin import ZendeskClient, load_config
from zendesk_admin.cli import base_parser, setup_logging
from zendesk_admin.utils import print_json_report  # or write_csv


def main():
    parser = base_parser("Your Script Description")
    # Add script-specific arguments
    parser.add_argument("--your-flag", help="...")

    args = parser.parse_args()
    setup_logging(args.verbose)

    config = load_config(args.env_file)
    client = ZendeskClient(config)

    # Use client.get(), client.put(), or client.paginate()
    for item in client.paginate("/api/v2/endpoint", "items"):
        # Process items
        pass


if __name__ == "__main__":
    main()
  1. Run it:
python -m scripts.your_new_script --help

The shared ZendeskClient handles authentication, pagination, and rate limiting automatically.

Available Client Methods

Method Description
client.get(endpoint, params) GET request, returns JSON dict
client.put(endpoint, json) PUT request, returns JSON dict
client.delete(endpoint, params) DELETE request, returns JSON dict or None (204)
client.paginate(endpoint, key, params) Yields individual records from paginated endpoint

API Rate Limits

Zendesk enforces rate limits on API usage. The ZendeskClient handles this automatically:

  • Detection: Monitors for HTTP 429 Too Many Requests responses
  • Backoff: Waits for the duration specified in the Retry-After header
  • Retry: Retries up to 5 times before raising a RateLimitError
  • Pagination: Uses cursor-based pagination (preferred) with offset fallback

Rate Limit Guidelines

Plan Limit
Team 200 requests/minute
Professional 400 requests/minute
Enterprise 700 requests/minute

For large Zendesk instances, consider running scripts during off-peak hours.


Limitations

Zombie Trigger Auditor

  • Usage statistics (usage_1h, usage_24h, usage_7d, usage_30d) are provided by Zendesk and may not be available on all plan tiers.
  • The usage_30d field only covers the last 30 days. A trigger that fires once every 60 days would still appear as a zombie.
  • Automations may not support the include=usage_* parameter on all Zendesk plans.

Bulk Macro Search & Replace

  • Searches action values only (not macro titles or descriptions).
  • Macro action values can be strings, lists of strings, or nested structures. The script handles strings and lists but not deeply nested structures.
  • No undo mechanism. Always use --dry-run first and keep backups.

User Permission Snapshotter

  • Custom roles and their permissions require an Enterprise+ plan. On lower plans, the custom_role_name and custom_role_permissions columns will be empty.
  • The role[] filter fetches admins and agents only. End-users are excluded by design.
  • The two_factor_auth_enabled field may not be available on all plans.

Tag Cleanup Bot

  • The Tags API returns up to 20,000 most popular tags from the last 60 days. Rarely-used tags or tags older than 60 days may not appear.
  • Tags referenced only in Macros or SLA policies are not checked (only Triggers, Automations, and Views are scanned).
  • Tag names are compared as exact strings (case-sensitive).

Suspended Ticket Spam-Killer

  • Bulk delete is limited to 100 ticket IDs per API request (handled automatically in batches).
  • Deletion is permanent — suspended tickets cannot be recovered after deletion.
  • The cause field is matched as a case-insensitive substring. Partial matches may capture unintended tickets — always review in report-only mode first.
  • Only Admins or custom-role agents with suspended ticket permissions can access this endpoint.

Attachment Retention Enforcer

  • Redaction is permanent and cannot be undone. Zendesk replaces the attachment with an empty redacted.txt file.
  • Cannot redact attachments on closed tickets on some Zendesk plans. The script logs warnings for failed redactions.
  • Uses the Zendesk Search API, which has its own rate limits and may return incomplete results for very large instances.
  • The --max-tickets safety limit defaults to 100 per run to prevent accidental mass redaction.
  • File size reported is from Zendesk metadata — actual storage savings may vary.

Inactive API Token Auditor

  • Audits both OAuth tokens (/api/v2/oauth/tokens) and API tokens (/api/v2/api_tokens).
  • The /api/v2/api_tokens endpoint may not be available on all Zendesk plans. If it returns 403 or 404, the script falls back gracefully and reports only OAuth tokens.
  • OAuth tokens use the used_at field; API tokens use the last_used_at field. A null value means the token was never used.
  • This script is read-only — it does not revoke tokens. Revocation must be done manually in Admin Center.
  • Token scopes (OAuth) and descriptions (API) are shown for context but cannot be modified via this script.

Ticket Volume Analyzer

  • The Zendesk Search API returns a maximum of 1,000 results per query. The script handles this by automatically bisecting the date range and re-querying, but if a single day exceeds 1,000 tickets, some data may be missing (a warning is logged).
  • All timestamps are in UTC. The hourly heatmap reflects UTC hours, not local time.
  • The Search API may have a slight delay in indexing recent tickets (typically a few minutes).
  • Requires matplotlib and reportlab as additional dependencies.
  • Chart rendering uses the Agg (non-interactive) matplotlib backend for headless server compatibility.
  • Pie charts group slices below 3% into "Other" for readability. Stacked bar charts show the top 8 categories.
  • The PDF is generated in landscape letter format. Very large datasets (50+ time buckets) may have crowded x-axis labels.

General

  • All scripts require Admin-level API access.
  • API token authentication only (OAuth not supported).
  • Rate limits vary by Zendesk plan tier (see Rate Limits).
  • Scripts run synchronously. Large instances with thousands of triggers, macros, or users may take several minutes.

Project Structure

Zendesk-Admin-Management-Scripts/
├── .env.example            # Template for credentials
├── .gitignore              # Python, IDE, and output file exclusions
├── LICENSE                 # MIT License
├── README.md               # This file
├── requirements.txt        # Python dependencies
├── zendesk_admin/          # Shared library
│   ├── __init__.py         # Package exports
│   ├── client.py           # ZendeskClient (auth, pagination, rate limiting)
│   ├── cli.py              # Shared CLI argument parser
│   ├── config.py           # Configuration loading from .env
│   └── utils.py            # CSV and JSON output helpers
└── scripts/                # Runnable admin scripts
    ├── __init__.py
    ├── zombie_trigger_auditor.py         # Admin & Management
    ├── bulk_macro_search_replace.py      # Admin & Management
    ├── user_permission_snapshotter.py    # Admin & Management
    ├── tag_cleanup_bot.py                # Admin & Management
    ├── suspended_ticket_spam_killer.py   # Security & Compliance
    ├── attachment_retention_enforcer.py  # Security & Compliance
    ├── inactive_api_token_auditor.py     # Security & Compliance
    └── ticket_volume_analyzer.py         # Ticket Analytics & Reporting

License

This project is licensed under the MIT License. See the LICENSE file for details.

About

Zendesk scripts to handle bulk tasks that the native UI makes tedious

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages