Files
freshservice-claude/reference.md
spencerm 5ded947b73 Document include=assets as the way to see a ticket's associated assets
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>
2026-08-24 15:37:16 -06:00

102 lines
5.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 `status` field choices:
> `GET /ticket_form_fields` → field where `name == "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 with `AND` / `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.py` does 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` → read `id`, 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:3`
- `agent_id:0 AND status:2` — unassigned open tickets
- `agent_id:21000816864 AND (status:2 OR status:3)` — assigned to an agent, still open
- `type:'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 /tickets` supports `filter` presets (`new_and_my_open`, `watching`,
`spam`, `deleted`), `updated_since`, `order_by`, `order_type`, `page`,
`per_page` (max 100), and `include` (`conversations`, `requester`, `stats`).
- `GET /tickets/{id}?include=assets` is 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-assets` endpoint (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.py` surfaces
`next_page` when a next-page Link header is present.
- Per-plan minute limits (100500/min). Responses include
`rate_limit_remaining`.