The /tickets/{id}/associated-assets path 404s on this instance; assets come
back embedded via GET /tickets/{id}?include=assets. Spell out the full include
list on get_ticket and in the skill reference so consumers don't hunt for a
nonexistent endpoint.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
5.6 KiB
Freshservice API v2 reference
Base URL: https://<domain>.freshservice.com/api/v2. Auth is HTTP Basic with the
API key as username (handled by scripts/fs.py). Full docs: https://api.freshservice.com
Codes
Ticket status (defaults): 2 Open · 3 Pending · 4 Resolved · 5 Closed Ticket priority: 1 Low · 2 Medium · 3 High · 4 Urgent
⚠️ Instances often define custom statuses beyond the 4 defaults (e.g. "Working", "Scheduled", "Waiting Vendor Support"). Resolved and Closed are always ids 4 and 5; every other status is "open". To list them all, read the
statusfield choices:GET /ticket_form_fields→ field wherename == "status"→choices[]. So "all my tickets that aren't resolved/closed" must enumerate every non-4/5 status, not just(status:2 OR status:3). Recipe:agent_id:<id> AND (status:2 OR status:3 OR status:6 OR status:7 OR ...)using all open ids from the status field. Ticket source: 1 Email · 2 Portal · 3 Phone · 4 Chat · 5 Feedback widget · 6 Yammer · 7 AWS CloudWatch · 8 PagerDuty · 9 Walkup · 10 Slack
Status/priority for changes use their own workflow codes; list a few existing records to infer them, or read the ticket-fields / change-fields endpoints.
Endpoints
| Resource | List | Create | View | Update | Delete |
|---|---|---|---|---|---|
| Tickets | GET /tickets |
POST /tickets |
GET /tickets/{id} |
PUT /tickets/{id} |
DELETE /tickets/{id} |
| Ticket filter | GET /tickets/filter?query="..." |
— | — | — | — |
| Conversations | GET /tickets/{id}/conversations |
reply: POST /tickets/{id}/reply; note: POST /tickets/{id}/notes |
— | PUT /conversations/{id} |
DELETE /conversations/{id} |
| Assets | GET /assets |
POST /assets |
GET /assets/{display_id} |
PUT /assets/{display_id} |
DELETE /assets/{display_id} |
| Agents | GET /agents |
POST /agents |
GET /agents/{id} |
PUT /agents/{id} |
— |
| Requesters | GET /requesters |
POST /requesters |
GET /requesters/{id} |
PUT /requesters/{id} |
— |
| Groups | GET /groups |
POST /groups |
GET /groups/{id} |
PUT /groups/{id} |
DELETE /groups/{id} |
| Departments | GET /departments |
POST /departments |
GET /departments/{id} |
PUT /departments/{id} |
DELETE /departments/{id} |
| Changes | GET /changes (+ /changes/filter) |
POST /changes |
GET /changes/{id} |
PUT /changes/{id} |
DELETE /changes/{id} |
| Problems | GET /problems |
POST /problems |
GET /problems/{id} |
PUT /problems/{id} |
DELETE /problems/{id} |
| Releases | GET /releases |
POST /releases |
GET /releases/{id} |
PUT /releases/{id} |
DELETE /releases/{id} |
| Current agent | GET /agents/me |
— | — | — | — |
Other useful endpoints reachable the same way: /solutions/categories,
/solutions/folders, /solutions/articles, /products, /vendors,
/ticket_fields, /tickets/{id}/time_entries, /canned_responses.
Ticket fields (create/update)
subject, description (HTML ok), email or requester_id, priority,
status, source, group_id, responder_id (assigned agent), type
(e.g. "Incident", "Service Request"), tags (array), category,
sub_category, custom_fields (object), due_by, fr_due_by.
Provide either email or requester_id. For a public reply the
requester is emailed; a note with "private": true is internal-only.
Filter (query) syntax — /tickets/filter and /changes/filter
- Format:
field:value, combined withAND/OR. - Strings single-quoted:
tag:'vip'. Numbers/dates bare or quoted. - Operators on dates/numbers:
>,<, e.g.created_at:>'2026-01-01'. - Filterable ticket fields include:
status,priority,agent_id,group_id,requester_id,type,source,tag,created_at,updated_at,due_by, plus custom fields by name. - The whole expression must be URL-double-quoted;
scripts/fs.pydoes this when you pass--param query=.../--param filter=....
Two common gotchas:
- Assignee is
agent_id(numeric), not an email. Resolve an email to an id first:GET /agents?email=person@co.com→ readid, then filter on it. - No "not" operator for status. "Open / unresolved / not closed" must be
enumerated:
(status:2 OR status:3). Parenthesize the OR group when AND-ing it.
Examples:
status:2 AND priority:3agent_id:0 AND status:2— unassigned open ticketsagent_id:21000816864 AND (status:2 OR status:3)— assigned to an agent, still opentype:'Incident' AND created_at:>'2026-06-01'
Multi-workspace accounts: /tickets/filter searches one workspace by default.
Pass --param workspace_id=<id> to target another (an agent's workspace_ids
lists which ones they're in).
Listing vs. filtering
GET /ticketssupportsfilterpresets (new_and_my_open,watching,spam,deleted),updated_since,order_by,order_type,page,per_page(max 100), andinclude(conversations,requester,stats).GET /tickets/{id}?include=assetsis the only way to see a ticket's associated CMDB assets — they come back embedded in the ticket object. There is no/tickets/{id}/associated-assetsendpoint (it 404s). Other single-ticket includes:conversations,requester,requested_for,stats,problem,tags,related_tickets.GET /tickets/filter?query="..."is for ad-hoc field queries (also 100/page).
Pagination & rate limits
- 30 results/page default, 100 max via
per_page.scripts/fs.pysurfacesnext_pagewhen a next-page Link header is present. - Per-plan minute limits (100–500/min). Responses include
rate_limit_remaining.