Freshdesk API 티켓
Freshdesk API 티켓
고객센터를 운영하다 보면 "이 문의를 API로 자동으로 접수하고 싶다", "오늘 들어온 티켓을 코드로 한 번에 정리하고 싶다" 같은 요구가 꼭 생겨요. Freshdesk의 티켓 API는 바로 그런 일을 처리하는 핵심 축입니다. 티켓 생성부터 조회·필터·수정까지 모두 REST 엔드포인트 하나로 다룰 수 있어서, 외부 시스템에서 문의가 들어왔을 때 티켓을 자동 생성하거나 대시보드처럼 티켓 목록을 가져오는 데 아주 유용해요.
이 문서는 Freshdesk 공식 API 중 티켓(Tickets) 부분을 발췌해 정리한 내용입니다. 요청·응답 구조와 코드 예시는 원문 그대로 실었으니, 실제 호출해 보면서 하나씩 따라 해 보면 좋아요. 인증은 -u yourapikey:***처럼 API 키를 기본 인증으로 넘기는 방식이며, domain 자리에는 본인 계정의 서브도메인이 들어가요.
출처: 문서
티켓이란 무엇인가요
티켓은 요청자(requester)가 올린, 해결이 필요한 이슈예요. 보안 취약점처럼 긴급하고 우선순위가 높은 문제일 수도 있고, 무료 티셔츠에 관한 질문처럼 낮은 우선순위의 문의일 수도 있어요. 티켓은 담당 에이전트의 전문성과 티켓 주제에 따라 에이전트에게 배정됩니다.
티켓의 주요 속성 (Ticket Properties)
티켓 하나에는 아래 같은 필드들이 담겨요. 이 중 어떤 것은 읽기 전용이고, 어떤 것은 생성·수정 시에 함께 보내는 요청 필드예요.
| Attribute | Type | Description |
|---|---|---|
| attachments | array of objects | 티켓 첨부파일. 총 크기는 20MB를 초과할 수 없어요. |
| cc_emails | array of strings | 수신 티켓 메일의 'cc' 필드에 추가된 이메일 주소 |
| company_id | number | 이 티켓이 속한 회사의 ID |
| custom_fields | dictionary | 커스텀 필드의 이름과 값을 담은 키-값 쌍 |
| description | string | 티켓의 HTML 내용 |
| description_text | string | 티켓 내용을 평문(plain text)으로 나타낸 값 |
| due_by | datetime | 티켓이 해결되어야 하는 시한 타임스탬프 |
| string | 요청자의 이메일 주소. Freshdesk에 이 이메일의 연락처가 없다면 새 연락처로 추가돼요. | |
| group_id | number | 티켓이 배정된 그룹의 ID |
| id | number | 티켓의 고유 ID |
| name | string | 요청자의 이름 |
| phone | string | 요청자의 전화번호 |
| priority | number | 티켓의 우선순위 |
| product_id | number | 티켓과 연결된 제품의 ID |
| requester_id | number | 요청자의 사용자 ID |
| responder_id | number | 티켓이 배정된 에이전트의 ID |
| source | number | 티켓이 생성된 채널 |
| spam | boolean | 티켓이 스팸으로 표시되었으면 true |
| status | number | 티켓의 상태 |
| subject | string | 티켓의 제목 |
| tags | array of strings | 티켓과 연결된 태그 |
| created_at | datetime | 티켓 생성 타임스탬프 |
| updated_at | datetime | 티켓 업데이트 타임스탬프 |
상태·우선순위·소스의 고정 수치
모든 티켓은 상태(Status), 우선순위(Priority), 소스(Source)를 고정된 숫자값으로 표현해요. 정확한 값이 아래 표에 정리되어 있어요.
Status (상태)
| Status | Value |
|---|---|
| Open | 2 |
| Pending | 3 |
| Resolved | 4 |
| Closed | 5 |
Priority (우선순위)
| Priority | Value |
|---|---|
| Low | 1 |
| Medium | 2 |
| High | 3 |
| Urgent | 4 |
Source (소스)
| Source | Value |
|---|---|
| 1 | |
| Portal | 2 |
| Phone | 3 |
| Chat | 7 |
| Feedback Widget | 9 |
| Outbound Email | 10 |
티켓 생성 (POST /api/v2/tickets)
새 티켓을 만들 때는 POST /api/v2/tickets 엔드포인트를 사용해요. 요청자 식별은 email, phone, twitter_id, facebook_id, requester_id, unique_external_id 중 어느 하나가 필수예요. 기본 status 값은 2(Open), priority 기본값은 1(Low), source 기본값은 2(Portal)예요.
curl 예시부터 볼게요.
curl -v -u yourapikey:*** -H "Content-Type: application/json" -d '{ "description": "Details about the issue...", "subject": "Support Needed...", "email": "[email protected]", "priority": 1, "status": 2, "cc_emails": ["[email protected]","[email protected]"] }' -X POST 'https://domain.freshdesk.com/api/v2/tickets'
요청 본문(request)은 이렇게 생겼어요.
{
"description":"Some details on the issue ...",
"subject":"Support needed..",
"email":"[email protected]",
"priority":1,
"status":2,
"cc_emails":["[email protected]", "[email protected]"]
}
그러면 응답(response)으로 생성된 티켓 객체가 돌아와요. id가 배정되고, due_by·fr_due_by 같은 시한 값은 티켓 생성 후 몇 초 안에 채워져요.
{
"cc_emails" : ["[email protected]", "[email protected]"],
"fwd_emails" : [ ],
"reply_cc_emails" : ["[email protected]", "[email protected]"],
"email_config_id" : null,
"group_id" : null,
"priority" : 1,
"requester_id" : 129,
"responder_id" : null,
"source" : 2,
"status" : 2,
"subject" : "Support needed..",
"company_id" : 1,
"id" : 1,
"type" : "Question",
"to_emails" : null,
"product_id" : null,
"fr_escalated" : false,
"spam" : false,
"urgent" : false,
"is_escalated" : false,
"created_at" : "2015-07-09T13:08:06Z",
"updated_at" : "2015-07-23T04:41:12Z",
"due_by" : "2015-07-14T13:08:06Z",
"fr_due_by" : "2015-07-10T13:08:06Z",
"description_text" : "Some details on the issue ...",
"description" : "<div>Some details on the issue ..</div>",
"tags" : [ ],
"attachments" : [ ]
}
커스텀 필드와 함께 생성하기
계정에 만든 커스텀 필드가 있다면 custom_fields에 키-값으로 실어서 보내면 돼요.
curl -v -u yourapikey:*** -H "Content-Type: application/json" -d '{ "description": "Details about the issue...", "subject": "Support Needed...", "email": "[email protected]", "priority": 1, "status": 2, "cc_emails": ["[email protected]","[email protected]"], "custom_fields" : { "category" : "Primary" } }' -X POST 'https://domain.freshdesk.com/api/v2/tickets'
응답에서 custom_fields 값이 그대로 반영된 걸 확인할 수 있어요.
{
"cc_emails" : ["[email protected]", "[email protected]"],
"fwd_emails" : [ ],
"reply_cc_emails" : ["[email protected]", "[email protected]"],
"email_config_id" : null,
"group_id" : null,
"priority" : 1,
"requester_id" : 129,
"responder_id" : null,
"source" : 2,
"status" : 2,
"subject" : "Support needed..",
"company_id" : 1,
"id" : 1,
"type" : "Question",
"to_emails" : null,
"product_id" : null,
"fr_escalated" : false,
"spam" : false,
"urgent" : false,
"is_escalated" : false,
"created_at" : "2015-07-09T13:08:06Z",
"updated_at" : "2015-07-23T04:41:12Z",
"due_by" : "2015-07-14T13:08:06Z",
"fr_due_by" : "2015-07-10T13:08:06Z",
"description_text" : "Some details on the issue ...",
"description" : "<div>Some details on the issue ..</div>",
"custom_fields" : {
"category" : "Primary"
},
"tags" : [ ],
"attachments" : [ ]
}
첨부파일과 함께 생성하기
첨부파일이 있으면 Content-Type을 multipart/form-data로 설정하고 attachments[] 필드로 보내야 해요.
curl -v -u yourapikey:*** -F "attachments[]=@/path/to/attachment1.ext" -F "attachments[]=@/path/to/attachment2.ext" -F "[email protected]" -F "subject=Ticket Title" -F "description=this is a sample ticket" -X POST 'https://domain.freshdesk.com/api/v2/tickets'
첨부는 응답의 attachments 배열에 파일 메타데이터로 나타나요.
{
"cc_emails" : ["[email protected]", "[email protected]"],
"fwd_emails" : [ ],
"reply_cc_emails" : ["[email protected]", "[email protected]"],
"email_config_id" : null,
"group_id" : null,
"priority" : 1,
"requester_id" : 129,
"responder_id" : null,
"source" : 2,
"status" : 2,
"subject" : "Ticket Title",
"id" : 1,
"type" : "Question",
"to_emails" : null,
"product_id" : null,
"fr_escalated" : false,
"spam" : false,
"urgent" : false,
"is_escalated" : false,
"created_at" : "2015-07-09T13:08:06Z",
"updated_at" : "2015-07-23T04:41:12Z",
"due_by" : "2015-07-14T13:08:06Z",
"fr_due_by" : "2015-07-10T13:08:06Z",
"description_text" : "this is a sample ticket",
"description" : "<div>this is a sample ticket</div>",
"custom_fields" : {
"category" : null
},
"tags" : [ ],
"attachments":[
{
"id":4004881085,
"content_type":"image/jpeg",
"file_size":44115,
"name":"attachment1.jpg",
"attachment_url":"https://cdn.freshdesk.com/data/helpdesk/attachments/production/4004881085/original/attachment.jpg"
"created_at":"2014-07-28T16:20:03+05:30",
"updated_at":"2014-07-28T16:20:03+05:30",
},
{
"id":4004881086,
"content_type":"image/jpeg",
"file_size":44134,
"name":"attachment2.jpg",
"attachment_url":"https://cdn.freshdesk.com/data/helpdesk/attachments/production/4004881085/original/attachment2.jpg"
"created_at":"2014-07-28T16:20:03+05:30",
"updated_at":"2014-07-28T16:20:03+05:30",
}
]
}
티켓 조회 (GET /api/v2/tickets/[id])
하나의 티켓을 조회할 때는 GET /api/v2/tickets/[id]를 사용해요. 기본적으로 conversations, company name, requester email 같은 일부 필드는 응답에 포함되지 않아요. 이런 값들이 필요하면 include 파라미터로 추가 정보를 임베드(embed)하면 돼요. 각 include는 추가 API 크레딧을 소모한다는 점을 기억하세요.
curl -v -u yourapikey:*** -H "Content-Type: application/json" -X GET 'https://domain.freshdesk.com/api/v2/tickets/20'
include로 담을 수 있는 항목은 아래와 같아요.
| Embed | Handle |
|---|---|
| conversations | /api/v2/tickets/[id]?include=conversations — 생성 순(ascending)으로 최대 10개의 대화를 반환해요. conversations include는 API 호출 2회를 소모해요. 10개를 넘는 대화는 List All Conversations of a Ticket API로 조회해요. |
| requester | /api/v2/tickets/[id]?include=requester — 요청자의 email, id, mobile, name, phone을 반환해요. |
| company | /api/v2/tickets/[id]?include=company — 회사의 id와 name을 반환해요. |
| stats | /api/v2/tickets/[id]?include=stats — 티켓의 closed_at, resolved_at, first_responded_at 시각을 반환해요. |
curl -v -u yourapikey:*** -X GET 'https://domain.freshdesk.com/api/v2/tickets/20?include=conversations'
curl -v -u yourapikey:*** -X GET 'https://domain.freshdesk.com/api/v2/tickets/20?include=company,requester'
curl -v -u yourapikey:*** -X GET 'https://domain.freshdesk.com/api/v2/tickets/20?include=stats'
티켓 목록 조회 (GET /api/v2/tickets)
여러 티켓을 한 번에 가져올 때는 GET /api/v2/tickets를 사용해요. 기본적으로 삭제되지 않았고 스팸으로 표시되지 않은 티켓만 반환하며, 필터를 쓰면 특정 조건에 맞는 티켓만 고를 수 있어요.
curl -v -u yourapikey:*** -X GET 'https://domain.freshdesk.com/api/v2/tickets'
목록 조회 시 알아둘 점
기본 동작 몇 가지를 짚고 갈게요.
- 기본적으로 최근 30일 내에 생성된 티켓만 반환돼요. 더 오래된 티켓은
updated_since필터를 사용해요. - 최대 300페이지(30,000개 티켓)까지만 반환돼요.
- 필터를 쓸 때는 쿼리 문자열을 URL 인코딩해야 해요.
include를 쓰면 각 include가 2크레딧을 추가로 소모해요 (예: stats include → 총 3크레딧).- 2018-11-30 이후에 생성된 계정은
description을 얻으려면include를 사용해야 해요.
필터 (Filter by)
| Filter by | Handle |
|---|---|
| Predefined filters | /api/v2/tickets?filter=[filter_name] — 사용 가능한 필터는 new_and_my_open, watching, spam, deleted예요. |
| Requester | /api/v2/tickets?requester_id=[id], /api/v2/tickets?email=[requester_email], /api/v2/tickets?unique_external_id=[requester_unique_external_id] |
| Company ID | /api/v2/tickets?company_id=[id] |
| Updated since | /api/v2/tickets?updated_since=2015-01-19T02:00:00Z |
| Custom ticket views | Filter Tickets API 참고 |
정렬 (Sort by)
| Sort by | Handle |
|---|---|
| created_at, due_by, updated_at, status | /api/v2/tickets?order_by=created_at — 기본 정렬은 created_at |
| asc, desc | /api/v2/tickets?order_type=asc — 기본 정렬 방향은 desc |
필터·정렬·페이지네이션 예시
requester_id=1230인 티켓을 상태 기준 내림차순으로 정렬해 볼게요.
curl -v -u yourapikey:*** -X GET 'https://domain.freshdesk.com/api/v2/tickets?requester_id=1230&order_by=status&order_type=desc'
한 페이지에 10개씩 2페이지를 조회하는 페이지네이션 예시예요.
curl -v -u yourapikey:*** -X GET 'https://domain.freshdesk.com/api/v2/tickets?per_page=10&page=2'
특정 시점 이후 업데이트된 티켓만 가져올 수도 있어요.
curl -v -u yourapikey:*** -X GET 'https://domain.freshdesk.com/api/v2/tickets?updated_since=2015-08-17'
티켓 목록 응답은 티켓 객체들의 배열로 돌아와요.
[
{
"cc_emails" : ["[email protected]", "[email protected]"],
"fwd_emails" : [ ],
"reply_cc_emails" : ["[email protected]", "[email protected]"],
"fr_escalated" : false,
"spam" : false,
"email_config_id" : null,
"group_id" : 2,
"priority" : 1,
"requester_id" : 5,
"responder_id" : 1,
"source" : 2,
"source_info": 1,
"status" : 2,
"subject" : "Please help",
"to_emails" : null,
"product_id" : null,
"id" : 18,
"type" : Lead,
"created_at" : "2015-08-17T12:02:50Z",
"updated_at" : "2015-08-17T12:02:51Z",
"due_by" : "2015-08-20T11:30:00Z",
"fr_due_by" : "2015-08-18T11:30:00Z",
"is_escalated" : false,
"structured_description" : {
"description_contents" : [
{
"type" : "text",
"data" : {
"content" : "Please help with this issue"
}
}
]
},
"custom_fields" : {
"category" : "Default"
}
},
{
"cc_emails" : [ ],
"fwd_emails" : [ ],
"reply_cc_emails" : [ ],
"fr_escalated" : false,
"spam" : false,
"email_config_id" : null,
"group_id" : null,
"priority" : 1,
"requester_id" : 1,
"responder_id" : null,
"source" : 2,
"source_info": 1,
"status" : 2,
"subject" : "",
"to_emails" : null,
"product_id" : null,
"id" : 17,
"type" : null,
"created_at" : "2015-08-17T12:02:06Z",
"updated_at" : "2015-08-17T12:02:07Z",
"due_by" : "2015-08-20T11:30:00Z",
"fr_due_by" : "2015-08-18T11:30:00Z",
"is_escalated" : false,
"structured_description" : {
"description_contents" : [
{
"type" : "text",
"data" : {
"content" : "Another ticket description"
}
}
]
},
"custom_fields" : {
"category" : null
}
}
]
티켓 필터/검색 (GET /api/v2/search/tickets?query=[query])
계정에 만든 커스텀 티켓 필드를 기준으로 티켓을 걸러낼 때는 검색 API를 사용해요. 쿼리 형식은 "(ticket_field:integer OR ticket_field:'string') AND ticket_field:boolean" 형태예요.
curl -v -u yourapikey:*** -X GET 'https://domain.freshdesk.com/api/v2/search/tickets?query="priority:3"'
검색/필터 규칙
- 보관(archived)된 티켓은 결과에 포함되지 않아요.
- 쿼리는 반드시 URL 인코딩해야 해요.
- 필드명은 대소문자를 구분해요.
- 쿼리는 큰따옴표로 감싸야 하고, 최대 512자까지 사용할 수 있어요.
AND,OR논리 연산자와 괄호()로 조건을 묶을 수 있어요.- 날짜·숫자 필드에는
:>(크거나 같음),:<(작거나 같음) 비교 연산자를 쓸 수 있어요. - 날짜 필드 입력은 UTC 형식이어야 해요.
- 페이지당 30개 객체를 반환하고, 총 개수도 함께 반환돼요.
- 페이지 파라미터로 넘기며, 페이지는 1부터 10을 초과하면 안 돼요.
- 값이 없는 필드를 걸러낼 때는
null키워드를 사용해요. - 변경 사항이 API에 반영되기까지 몇 분 소요될 수 있어요.
지원되는 검색 필드 (Supported Ticket Fields)
| Field | Type | Description |
|---|---|---|
| agent_id | integer | 티켓이 배정된 에이전트의 ID |
| group_id | integer | 티켓이 배정된 그룹의 ID |
| priority | integer | 티켓의 우선순위 |
| status | integer | 티켓의 상태 |
| tag | string | 티켓에 연결된 태그 |
| type | string | 티켓에 연결된 이슈 유형 |
| due_by | date | 티켓이 해결되어야 하는 날짜 (YYYY-MM-DD) |
| fr_due_by | date | 첫 응답이 마감인 날짜 (YYYY-MM-DD) |
| created_at | date | 티켓 생성일 (YYYY-MM-DD) |
| updated_at | date | 티켓이 마지막으로 업데이트된 날짜 (YYYY-MM-DD) |
| closed_at | date | 티켓이 닫힌 날짜 (YYYY-MM-DD) |
커스텀 필드도 검색에 사용할 수 있어요. Single line text(문자열), Number(정수), Checkbox(불리언), Dropdown(문자열) 타입을 지원해요.
검색 예시
여러 조건을 조합하는 예시를 몇 개 볼게요.
우선순위 4 또는 3인 티켓 검색:
curl -v -u yourapikey:*** -X GET 'https://domain.freshdesk.com/api/v2/search/tickets?query="priority:4%20OR%20priority:3"'
상태 3 또는 4인 티켓을 2페이지로 검색:
curl -v -u yourapikey:*** -X GET 'https://domain.freshdesk.com/api/v2/search/tickets?query="status:3%20OR%20status:4"&page=2'
우선순위가 3보다 크고 그룹 11에 배정된 열린 티켓:
curl -v -u yourapikey:*** -X GET 'https://domain.freshdesk.com/api/v2/search/tickets?query="priority:>3%20AND%20group_id:11%20AND%20status:2"'
커스텀 필드를 조합한 예시 (and + or):
curl -v -u yourapikey:*** -X GET 'https://domain.freshdesk.com/api/v2/search/tickets?query="(cf_sector:%27finance%27%20OR%20cf_sector:%27marketing%27)%20AND%20cf_locked:true"'
날짜 필드 비교:
curl -v -u yourapikey:*** -X GET 'https://domain.freshdesk.com/api/v2/search/tickets?query="priority:>3%20AND%20created_at:%272017-01-01%27"'
값이 없는 필드(null) 검색:
curl -v -u yourapikey:*** -X GET 'https://domain.freshdesk.com/api/v2/search/tickets?query="tag:null"'
티켓 수정 (PUT /api/v2/tickets/[id])
기존 티켓을 수정할 때는 PUT /api/v2/tickets/[id]를 사용해요. 바꾸고 싶은 필드만 payload로 보내면 돼요. 단, 일반 티켓과 달리 아웃바운드(outbound) 티켓의 subject와 description은 수정할 수 없어요.
curl -v -u yourapikey:*** -H "Content-Type: application/json" -X PUT -d '{ "priority":2, "status":3 }' 'https://domain.freshdesk.com/api/v2/tickets/1'
수정 시 사용할 수 있는 주요 파라미터는 생성과 거의 같아요. status(기본값 2), priority(기본값 1), source(기본값 2)는 표에 있는 고정 수치 중에서만 사용할 수 있어요. due_by·fr_due_by는 최신 SLA 버전 계정에서 티켓 업데이트 후 몇 초 안에 재계산되며, 응답에는 업데이트 전 값이 표시돼요.
더 알아보기 (Learn more)
- 공식 문서 — Freshdesk 티켓 API 전체 레퍼런스