Zendesk integration for Combinate's support ticket system. Use this skill for any interaction with Zendesk - reading tickets, adding internal notes, writing draft replies to customers, updating ticket status, and searching for tickets by requester or keyword. Trigger on any mention of support tickets, Zendesk, customer support requests, or phrases like "what tickets are open", "reply to the ticket from [person]", "add a note to ticket [ID]", "show me open tickets", or "draft a response to [ticket]".
Use this skill for any interaction with Combinate's Zendesk support system - reading tickets, drafting replies, adding internal notes, and updating ticket status.
API key is stored in .env as ZENDESK_API_KEY.
Zendesk URL is stored as ZENDESK_URL (e.g. https://combinate.zendesk.com).
The .env file is gitignored - the API key never gets committed.
All Zendesk API calls use HTTP Basic Auth where the username is and the password is the API token.
{email}/tokenThe authenticated user email for Combinate is [email protected] (the account the API token is tied to).
source "/Users/shanemcgeorge/Claude/Combinate EA/.env" && curl -s \
-u "[email protected]/token:$ZENDESK_API_KEY" \
-H "Content-Type: application/json" \
"$ZENDESK_URL/api/v2/[endpoint]"
Returns the most recent tickets across all statuses. Useful for a quick overview.
source "/Users/shanemcgeorge/Claude/Combinate EA/.env" && curl -s \
-u "[email protected]/token:$ZENDESK_API_KEY" \
"$ZENDESK_URL/api/v2/tickets.json?sort_by=created_at&sort_order=desc&per_page=25" | python3 -c "
import sys, json
data = json.load(sys.stdin)
for t in data.get('tickets', []):
print(f\"[{t['id']}] {t['status'].upper():8} | {t['subject']} | Created: {t['created_at'][:10]}\")
"
source "/Users/shanemcgeorge/Claude/Combinate EA/.env" && curl -s \
-u "[email protected]/token:$ZENDESK_API_KEY" \
"$ZENDESK_URL/api/v2/tickets.json?status=open&per_page=50" | python3 -c "
import sys, json
data = json.load(sys.stdin)
tickets = data.get('tickets', [])
print(f'Open tickets: {len(tickets)}')
for t in tickets:
print(f\" [{t['id']}] {t['subject']} | Requester ID: {t['requester_id']} | Updated: {t['updated_at'][:10]}\")
"
Replace TICKET_ID with the actual ticket ID.
source "/Users/shanemcgeorge/Claude/Combinate EA/.env" && curl -s \
-u "[email protected]/token:$ZENDESK_API_KEY" \
"$ZENDESK_URL/api/v2/tickets/TICKET_ID.json" | python3 -c "
import sys, json
data = json.load(sys.stdin)
t = data.get('ticket', {})
print(f\"ID: {t.get('id')}\")
print(f\"Subject: {t.get('subject')}\")
print(f\"Status: {t.get('status')}\")
print(f\"Priority: {t.get('priority')}\")
print(f\"Requester: {t.get('requester_id')}\")
print(f\"Assignee: {t.get('assignee_id')}\")
print(f\"Created: {t.get('created_at', '')[:10]}\")
print(f\"Updated: {t.get('updated_at', '')[:10]}\")
print(f\"Description:\")
print(t.get('description', '(none)'))
"
Returns the full conversation thread including public replies and internal notes.
source "/Users/shanemcgeorge/Claude/Combinate EA/.env" && curl -s \
-u "[email protected]/token:$ZENDESK_API_KEY" \
"$ZENDESK_URL/api/v2/tickets/TICKET_ID/comments.json" | python3 -c "
import sys, json
data = json.load(sys.stdin)
comments = data.get('comments', [])
print(f'Comments: {len(comments)}')
for c in comments:
visibility = 'INTERNAL' if not c.get('public') else 'PUBLIC'
author_id = c.get('author_id')
created = c.get('created_at', '')[:10]
print(f'--- [{visibility}] Author ID: {author_id} | {created}')
print(c.get('body', ''))
print()
"
This posts a public reply visible to the customer. Review the content carefully before running.
Replace TICKET_ID and the reply body as needed.
source "/Users/shanemcgeorge/Claude/Combinate EA/.env" && curl -s -X PUT \
-u "[email protected]/token:$ZENDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"ticket": {
"comment": {
"body": "REPLY BODY HERE",
"public": true
}
}
}' \
"$ZENDESK_URL/api/v2/tickets/TICKET_ID.json"
Internal notes are only visible to your team, not the customer.
source "/Users/shanemcgeorge/Claude/Combinate EA/.env" && curl -s -X PUT \
-u "[email protected]/token:$ZENDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"ticket": {
"comment": {
"body": "INTERNAL NOTE HERE",
"public": false
}
}
}' \
"$ZENDESK_URL/api/v2/tickets/TICKET_ID.json"
Valid statuses: new, open, pending, hold, solved, closed
source "/Users/shanemcgeorge/Claude/Combinate EA/.env" && curl -s -X PUT \
-u "[email protected]/token:$ZENDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"ticket": {
"status": "STATUS_HERE"
}
}' \
"$ZENDESK_URL/api/v2/tickets/TICKET_ID.json"
Search by keyword, requester email, subject, or status. Uses Zendesk Search API.
source "/Users/shanemcgeorge/Claude/Combinate EA/.env" && curl -s -G \
-u "[email protected]/token:$ZENDESK_API_KEY" \
--data-urlencode "query=SEARCH_TERM type:ticket" \
"$ZENDESK_URL/api/v2/search.json" | python3 -c "
import sys, json
data = json.load(sys.stdin)
results = data.get('results', [])
print(f'Results: {len(results)}')
for t in results:
print(f\" [{t['id']}] {t['status'].upper():8} | {t['subject']} | Updated: {t['updated_at'][:10]}\")
"
Search query examples:
requester:[email protected] type:ticket - tickets from a specific emailstatus:open type:ticket - open ticketssubject:refund type:ticket - tickets with "refund" in the subjecttype:ticket created>2026-01-01 - tickets created after a dateReplace USER_ID with the requester_id from a ticket.
source "/Users/shanemcgeorge/Claude/Combinate EA/.env" && curl -s \
-u "[email protected]/token:$ZENDESK_API_KEY" \
"$ZENDESK_URL/api/v2/users/USER_ID.json" | python3 -c "
import sys, json
data = json.load(sys.stdin)
u = data.get('user', {})
print(f\"Name: {u.get('name')}\")
print(f\"Email: {u.get('email')}\")
print(f\"Role: {u.get('role')}\")
"
When asked to draft a reply to a ticket:
For internal notes, follow the same process but use operation 6.
When surfacing ticket data:
open and have not been updated in more than 3 days as potentially stale.env for ZENDESK_API_KEY and confirm the email [email protected] is correct for this Zendesk account.env is sourced correctly