FRESHDESKAPIHƯỚNG DẪN KỸ THUẬT

Freshdesk API: Hướng Dẫn Tích Hợp Từ A Đến Z

HexaSync Team 1 tháng 10, 2026 15 phút đọc

Freshdesk API v2

Kết nối Freshdesk với hệ thống của bạn

Xác thực, rate limit, phân trang, webhook và kinh nghiệm triển khai thực tế.

Zalo OA
Zalo OA
Shopify
Shopify
HexaSync
HexaSync
Freshdesk
Freshdesk

Bài viết dành cho developer và trưởng nhóm kỹ thuật đang chuẩn bị kết nối Freshdesk với hệ thống khác như Zalo OA, phần mềm bán hàng hay cửa hàng online. Đọc xong, bạn sẽ biết cách xác thực, gọi các API chính, nhận webhook và những điểm cần xử lý để tích hợp chạy ổn định khi đưa vào vận hành.

Bài viết bổ sung kinh nghiệm triển khai, không thay thế tài liệu chính thức. Khi cần tra cứu chi tiết từng endpoint, hãy dùng Freshdesk API v2 documentation.

Tổng quan Freshdesk API v2

Freshdesk API v2 là REST API, dữ liệu trao đổi dạng JSON qua HTTPS. Mọi request đi tới domain Freshdesk của tài khoản:

https://yourdomain.freshdesk.com/api/v2/

yourdomain là tên miền Freshdesk của tài khoản, xem được ngay trên thanh địa chỉ trình duyệt khi đăng nhập.

Hình 1 – ảnh chụp giao diện Freshdesk
Hình 1: Tên miền Freshdesk của tài khoản hiển thị trên thanh địa chỉ, ví dụ beehexa-support.freshdesk.com.

Các nhóm tài nguyên thường dùng khi tích hợp:

Tài nguyênEndpointDùng để
Ticket/api/v2/ticketsTạo, cập nhật, tra cứu yêu cầu hỗ trợ
Conversation/api/v2/tickets/{id}/reply, /notesGửi phản hồi, ghi chú nội bộ trên ticket
Contact/api/v2/contactsQuản lý khách hàng (người gửi yêu cầu)
Company/api/v2/companiesQuản lý khách hàng doanh nghiệp
Agent, Group/api/v2/agents, /api/v2/groupsPhân công và phân tuyến ticket
Ticket field/api/v2/ticket_fieldsXem cấu trúc trường, kể cả custom field

Lấy API key Freshdesk

Freshdesk dùng API key của từng agent để xác thực. Quyền gọi API bằng đúng quyền của agent sở hữu key, vì vậy nên lấy key từ một agent dành riêng cho tích hợp thay vì tài khoản cá nhân.

Các bước lấy API key

  1. Đăng nhập Freshdesk bằng tài khoản agent dùng cho tích hợp.
  2. Bấm ảnh đại diện ở góc trên bên phải, chọn Profile settings.
Hình 2 – ảnh chụp giao diện Freshdesk
Hình 2: Bấm ảnh đại diện ở góc trên bên phải và chọn Profile settings.
  1. Tìm khung Your API Key ở cột bên phải trang My Profile Settings. Nếu key đang ẩn, bấm View API key và hoàn tất bước xác minh captcha.
  2. Sao chép API key và lưu vào nơi an toàn.
Hình 3 – ảnh chụp giao diện Freshdesk
Hình 3: Khung Your API Key và nút Reset API Key trong trang Profile settings (API key và thông tin cá nhân đã được che).

Nút Reset API Key dùng để thu hồi key cũ. Lưu ý mọi ứng dụng đang dùng key cũ sẽ mất kết nối cho đến khi được cập nhật key mới.

Gọi API với API key

Freshdesk dùng Basic Auth. Username là API key, password có thể là một ký tự bất kỳ như X.

curl -u YOUR_API_KEY:X -H "Content-Type: application/json" \
  https://yourdomain.freshdesk.com/api/v2/tickets

Một vài lưu ý khi triển khai:

  • Dùng agent riêng cho tích hợp: key không bị mất khi nhân sự nghỉ việc, và dễ kiểm soát quyền.
  • Cấp quyền vừa đủ: agent tích hợp chỉ cần quyền với các group và tài nguyên mà luồng dữ liệu sử dụng.
  • Không lưu key trong mã nguồn: đặt API key trong biến môi trường hoặc kho bí mật của hệ thống.

Rate limit và cách tránh lỗi 429

Freshdesk giới hạn số lượt gọi API theo phút, tính trên toàn tài khoản, không phân biệt agent hay địa chỉ IP. Theo trang hỗ trợ của Freshdesk:

GóiTổng lượt gọi / phútTạo ticketCập nhật ticketLiệt kê ticketLiệt kê contact
Free00000
Growth10050504040
Pro400160160100100
Enterprise700280280200200
Trial50

Freshdesk cho biết giới hạn theo phút đang được áp dụng dần. Một số tài khoản cũ vẫn có thể tính theo giờ, nên hãy đọc header thực tế thay vì cố định con số trong code.

Mỗi response trả về ba header để theo dõi:

  • X-Ratelimit-Total: tổng số lượt được phép
  • X-Ratelimit-Remaining: số lượt còn lại
  • X-Ratelimit-Used-CurrentRequest: số lượt request vừa rồi đã dùng

Khi vượt giới hạn, API trả về 429 Too Many Requests kèm header Retry-After (tính bằng giây). Cách xử lý nên áp dụng:

  • Chờ đúng `Retry-After` rồi mới gửi lại, không retry ngay lập tức.
  • Đưa request vào hàng đợi thay vì gọi song song không giới hạn, nhất là khi đồng bộ dữ liệu lớn lần đầu.
  • Hạn chế `include`/embed: mỗi tài nguyên embed kèm theo tốn thêm lượt gọi.

API Pagination and Incremental Data Pulling

Các API liệt kê trả về 30 bản ghi mỗi trang theo mặc định, tối đa 100 khi đặt per_page. Giá trị lớn hơn 100 sẽ bị báo lỗi.

GET /api/v2/tickets?per_page=100&page=2

Nếu còn trang tiếp theo, response có header link với rel="next". Hãy đọc header này để quyết định có gọi tiếp hay không, thay vì đoán tổng số trang.

Để đồng bộ tăng dần, chỉ lấy những ticket thay đổi kể từ lần chạy trước:

GET /api/v2/tickets?updated_since=2026-10-01T00:00:00Z&per_page=100

Khi cần lọc theo điều kiện phức tạp hơn, dùng Search API. Kết quả trả 30 bản ghi mỗi trang, tối đa 10 trang, câu truy vấn dài tối đa 512 ký tự và phải được URL encode:

GET /api/v2/search/tickets?query="status:2 AND priority:3"

Các đối tượng chính và cách ánh xạ dữ liệu

Phần lớn công sức tích hợp nằm ở việc thống nhất dữ liệu bên ngoài tương ứng với gì trong Freshdesk.

Đối tượngDữ liệu bên ngoài thường gặpGhi chú ánh xạ dữ liệu
TicketTin nhắn Zalo OA, yêu cầu đổi trả, khiếu nại đơn hàngLưu mã tham chiếu bên ngoài (mã hội thoại, mã đơn) vào custom field
ContactKhách hàng trên Zalo, phần mềm bán hàng, cửa hàng onlineKhớp theo email hoặc số điện thoại, xử lý trùng trước khi tạo mới
CompanyKhách hàng doanh nghiệpDùng domain email hoặc mã số thuế làm khóa
ConversationTin nhắn trả lời, ghi chú nội bộLưu ID tin nhắn bên ngoài để không ghi trùng
GroupNhóm phụ trách theo kênh hoặc khu vựcÁnh xạ từng kênh tiếp nhận về đúng group
Custom fieldMã đơn, kênh, mã kháchTạo trước khi go-live, tên trường bắt đầu bằng cf_

Một số mã giá trị cần nhớ khi tạo ticket:

  • status: 2 Open, 3 Pending, 4 Resolved, 5 Closed
  • priority: 1 Low, 2 Medium, 3 High, 4 Urgent
  • source: 1 Email, 2 Portal, 3 Phone, 7 Chat, 9 Feedback widget, 10 Outbound email

Khi tạo ticket, bắt buộc có ít nhất một thông tin người yêu cầu: requester_id, email, phone, facebook_id hoặc twitter_id.

Ví dụ code

Tạo ticket kèm custom field

curl -u YOUR_API_KEY:X -H "Content-Type: application/json" -X POST \
  -d '{
    "email": "khachhang@example.com",
    "subject": "Yêu cầu đổi size đơn #10234",
    "description": "Khách muốn đổi sang size M.",
    "status": 2,
    "priority": 2,
    "source": 7,
    "custom_fields": { "cf_ma_don_hang": "10234" }
  }' \
  https://yourdomain.freshdesk.com/api/v2/tickets

Tìm hoặc tạo contact theo email (Node.js)

const BASE = 'https://yourdomain.freshdesk.com/api/v2';
const AUTH = 'Basic ' + Buffer.from(process.env.FRESHDESK_API_KEY + ':X').toString('base64');

async function findOrCreateContact(email, name) {
  const headers = { Authorization: AUTH, 'Content-Type': 'application/json' };
  const res = await fetch(`${BASE}/contacts?email=${encodeURIComponent(email)}`, { headers });
  const found = await res.json();
  if (found.length > 0) return found[0];
  const created = await fetch(`${BASE}/contacts`, {
    method: 'POST', headers, body: JSON.stringify({ email, name })
  });
  return created.json();
}

Duyệt các ticket đã cập nhật, có xử lý 429

async function fetchUpdatedTickets(since) {
  const headers = { Authorization: AUTH };
  let url = `${BASE}/tickets?updated_since=${since}&per_page=100`;
  const all = [];
  while (url) {
    const res = await fetch(url, { headers });
    if (res.status === 429) {
      const wait = Number(res.headers.get('Retry-After') || 60);
      await new Promise(r => setTimeout(r, wait * 1000));
      continue;
    }
    all.push(...await res.json());
    const link = res.headers.get('link');
    const next = link && link.match(/<([^>]+)>;\s*rel="next"/);
    url = next ? next[1] : null;
  }
  return all;
}

Tạo webhook bằng Automation rule

Freshdesk không có trang đăng ký webhook riêng. Webhook được gửi qua action Trigger webhook trong Automation rules, mỗi khi ticket thỏa điều kiện bạn đặt ra. Ví dụ dưới đây tạo rule gửi webhook mỗi khi agent thêm ghi chú công khai (public note) vào ticket.

Bước 1: Mở trang Automations

Vào Admin, chọn Automations (nằm trong nhóm Workflows). Chọn tab theo thời điểm muốn gửi webhook:

  • Ticket Creation: chạy khi có ticket mới.
  • Ticket Updates: chạy khi ticket thay đổi, ví dụ có phản hồi hoặc ghi chú mới.
  • Hourly Triggers: quét ticket mỗi giờ theo điều kiện thời gian.

Bấm New rule để tạo rule mới.

Hình 4 – ảnh chụp giao diện Freshdesk
Hình 4: Trang Admin › Automations, tab Ticket Updates và nút New rule.

Bước 2: Đặt tên, chọn sự kiện và điều kiện

Một rule chạy theo ticket update gồm ba phần: Event, Condition và Action.

  • Tên rule: đặt tên dễ hiểu, ví dụ "HexaSync Integration".
  • Event: chọn ai thực hiện hành động (Action performed by, ví dụ Agent) và sự kiện kích hoạt, ví dụ Note is added với loại Public note.
  • Condition: lọc thêm theo thuộc tính ticket nếu cần, chọn Match ANY hoặc Match ALL cho các điều kiện.
Hình 5 – ảnh chụp giao diện Freshdesk
Hình 5: Đặt tên rule, chọn Event "Note is added – Public note" và phần Condition.

Bước 3: Chọn action Trigger webhook

Ở phần Action, chọn Trigger webhook và điền:

TrườngNên điền
Request typePOST khi gửi dữ liệu sang hệ thống khác
URLURL endpoint nhận webhook, có thể chèn placeholder như {{ticket.id}}
Requires authenticationBật nếu endpoint nhận cần xác thực. Authentication method chọn I have API key hoặc I have username & password
Add custom headersThêm header bí mật nếu endpoint cần, ví dụ X-Webhook-Secret: <chuỗi bí mật>
EncodingJSON
ContentSimple để chọn sẵn các trường ticket trong ô Placeholders, Advanced để tự viết nội dung JSON
Hình 6 – ảnh chụp giao diện Freshdesk
Hình 6: Chọn Trigger webhook, Request type POST, điền URL và bật Requires authentication (URL và API key đã được che).

Với Simple, bạn chọn các trường cần gửi trong ô Placeholders, ví dụ Ticket ID {{ticket.id}}, Subject {{ticket.subject}}, Last Public Comment {{ticket.latest_public_comment}}, Agent name {{ticket.agent.name}}, Contact Name {{ticket.contact.name}}.

Hình 7 – ảnh chụp giao diện Freshdesk
Hình 7: Chọn Encoding JSON, Content Simple và các trường trong ô Placeholders, sau đó bấm Preview.

Nếu cần cấu trúc JSON riêng, chọn Advanced và tự viết nội dung, ví dụ:

{
  "ticket_id": "{{ticket.id}}",
  "subject": "{{ticket.subject}}",
  "last_public_comment": "{{ticket.latest_public_comment}}",
  "contact_name": "{{ticket.contact.name}}"
}

Bước 4: Xem trước, lưu và kiểm tra

Bấm Preview để xem lại rule, sau đó lưu. Thêm một public note vào ticket thử để kiểm tra endpoint có nhận được dữ liệu không.

Giới hạn và cơ chế gửi lại

Theo tài liệu hỗ trợ của Freshdesk:

  • Giới hạn: tối đa 1000 lượt gọi webhook mỗi giờ.
  • Thành công: endpoint trả về mã 200–299.
  • Thất bại: Freshdesk gửi lại mỗi 30 phút, tổng cộng tối đa 48 lần, và gửi email báo lỗi cho admin.

Xử lý ở phía nhận webhook

  • Xác thực nguồn gửi: kiểm tra header bí mật đã cấu hình ở bước 3.
  • Phản hồi nhanh: trả về 200 ngay, đưa việc xử lý nặng vào hàng đợi.
  • Chịu được gửi lặp: cùng một sự kiện có thể đến nhiều lần do cơ chế gửi lại, nên xử lý idempotent dựa trên mã ticket và thời điểm cập nhật.
  • Lấy dữ liệu đầy đủ khi cần: webhook chỉ nên mang mã ticket và vài trường chính, phần còn lại gọi API để đọc bản mới nhất.

Kinh nghiệm từ dự án thực tế

Chống tạo ticket trùng

Tài liệu công khai của Freshdesk không nêu idempotency key khi tạo ticket. Khi retry hoặc khi webhook bên ngoài gửi lặp, hai ticket có thể được tạo cho cùng một yêu cầu. Cách an toàn là giữ bảng ánh xạ dữ liệu ở phía middleware (mã bên ngoài với ticket ID Freshdesk), tra bảng trước khi tạo, đồng thời lưu mã bên ngoài vào custom field để đối soát.

Retry có kiểm soát

  • Lỗi 429: chờ theo Retry-After.
  • Lỗi 5xx hoặc lỗi mạng: retry với thời gian chờ tăng dần, có giới hạn số lần.
  • Lỗi 4xx khác: không retry tự động, ghi lại để người phụ trách xử lý.
  • Bản ghi thất bại nhiều lần: chuyển vào hàng đợi lỗi để xử lý lại sau, không chặn cả luồng.

Đọc đúng mã lỗi

MãÝ nghĩa thường gặpCách xử lý
400Thiếu trường bắt buộc, sai kiểu dữ liệu, sai giá trịĐọc mảng errors (field, message, code) để sửa ánh xạ dữ liệu
401Sai hoặc thiếu API keyKiểm tra key và cách mã hóa Basic Auth
403Agent không đủ quyền hoặc tính năng chưa bậtKiểm tra quyền agent tích hợp và gói Freshdesk
404Không tìm thấy tài nguyênTicket hoặc contact đã bị xóa, cập nhật bảng ánh xạ dữ liệu
429Vượt rate limitChờ Retry-After, giảm tốc độ gửi

Thời gian và trạng thái

  • Freshdesk trả thời gian theo UTC. Quy đổi sang giờ Việt Nam ở lớp hiển thị, không lưu lẫn hai múi giờ.
  • Trạng thái đơn hàng, hội thoại ở hệ thống khác cần được ánh xạ rõ sang status của ticket ngay từ đầu, kể cả các trạng thái hiếm như hoàn trả một phần.

Kiến trúc tích hợp tham chiếu

Một luồng tích hợp Freshdesk ổn định thường gồm ba lớp:

  1. Hệ thống nguồn: Zalo OA, Shopify, Sapo, KiotViet hoặc phần mềm nội bộ phát sinh sự kiện.
  2. Lớp trung gian: nhận sự kiện, đưa vào hàng đợi, ánh xạ dữ liệu, kiểm soát rate limit, retry, chống trùng và ghi log.
  3. Freshdesk: nhận ticket, contact, conversation qua API và gửi webhook ngược lại khi ticket thay đổi.

Lớp trung gian là phần tốn công nhất khi tự xây và tự bảo trì. Trong phạm vi dự án đã khảo sát và thống nhất, HexaSync có thể thiết kế, triển khai và hỗ trợ vận hành lớp này để đội kỹ thuật của doanh nghiệp tập trung vào quy tắc nghiệp vụ.

Câu hỏi thường gặp

Tài liệu Freshdesk API chính thức ở đâu?+

Tài liệu Freshdesk API v2 nằm tại developers.freshdesk.com/api, gồm mô tả từng endpoint, tham số và ví dụ request.

Freshdesk API có miễn phí không?+

API đi kèm các gói trả phí của Freshdesk, số lượt gọi phụ thuộc gói đang dùng. Theo trang hỗ trợ của Freshdesk, gói Free không có lượt gọi API.

Lấy API key Freshdesk ở đâu?+

Bấm ảnh đại diện ở góc trên bên phải, chọn Profile settings. API key nằm trong khung Your API Key ở cột bên phải.

Freshdesk có webhook không?+

Có, thông qua action Trigger Webhook trong Automation rules (Admin › Automations). Bạn cấu hình điều kiện kích hoạt, URL nhận và nội dung gửi đi.

Làm sao tránh lỗi 429 khi đồng bộ nhiều dữ liệu?+

Đọc các header X-Ratelimit-*, đưa request vào hàng đợi, chờ theo Retry-After khi gặp 429 và hạn chế embed tài nguyên trong mỗi request.

Bài viết liên quan