• Freshdesk
  • API
  • Hướng dẫn kỹ thuật

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

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

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 hoặc 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à xử lý những điểm quan trọng để luồng tích hợp vận hành ổn định.

Nội dung dưới đây bổ sung kinh nghiệm triển khai, không thay thế tài liệu của nhà cung cấp. 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, trao đổi dữ liệu 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, có thể xem trên thanh địa chỉ khi đăng nhập. Tài liệu chính thức lưu ý API hoạt động qua domain Freshdesk, không qua custom CNAME.

Tên miền Freshdesk của tài khoản hiển thị trên thanh địa chỉ

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 và tra cứu yêu cầu hỗ trợ
Conversation/api/v2/tickets/{id}/reply, /notesGửi phản hồi hoặc ghi chú trên ticket
Contact/api/v2/contactsQuản lý khách hàng 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/groupsHỗ trợ phân công và phân tuyến ticket
Ticket field/api/v2/ticket_fieldsĐọc cấu trúc trường, kể cả custom field

Lấy API key Freshdesk

Freshdesk dùng API key của agent để xác thực. Quyền gọi API phụ thuộc quyền của agent sở hữu key, vì vậy nên dùng 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 và chọn Profile settings.

Mở Profile settings từ menu tài khoả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 khu vực Your API Key trên trang hồ sơ. Nếu key đang ẩn, bấm View API key và hoàn tất bước xác minh nếu hệ thống yêu cầu.
  2. Sao chép API key và lưu trong kho bí mật của hệ thống.

Khu vực Your API Key trong trang Profile settings của Freshdesk

Hình 3: Khu vực Your API Key trong trang hồ sơ; API key và thông tin cá nhân đã được che.

Nếu dùng Reset API Key, key cũ sẽ không còn dùng được. Mọi ứng dụng đang giữ key cũ phải được cập nhật trước khi hoạt động trở lại.

Gọi API với API key

Freshdesk dùng Basic Auth: username là API key, còn password có thể là một chuỗi 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 nguyên tắc nên áp dụng:

  • Dùng agent riêng cho tích hợp: giảm phụ thuộc vào vòng đời tài khoản nhân sự và giúp kiểm soát quyền.
  • Cấp quyền vừa đủ: agent tích hợp chỉ nên truy cập các group và tài nguyên mà luồng dữ liệu thực sự 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; không gửi key vào log.

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ụ thuộc số agent hay địa chỉ IP. Bảng giới hạn hiện được tài liệu Freshdesk công bố như sau:

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 cơ chế giới hạn theo phút được áp dụng theo từng đợt; một số tài khoản cũ có thể vẫn dùng giới hạn theo giờ. Vì vậy, không nên cố định duy nhất các con số trên trong code. Hãy kiểm tra gói hiện tại và đọc header thực tế của response.

Các header cần theo dõi:

  • X-Ratelimit-Total: tổng số lượt được phép trong cửa sổ hiện tại;
  • X-Ratelimit-Remaining: số lượt còn lại;
  • X-Ratelimit-Used-CurrentRequest: số lượt request vừa rồi tiêu thụ.

Khi vượt giới hạn, API trả về 429 Too Many Requests cùng 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 hoặc embed không cần thiết: mỗi tài nguyên được nhúng có thể tiêu thụ thêm lượt gọi.
  • Cache dữ liệu ít thay đổi: chẳng hạn ánh xạ tên agent với agent ID.

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 bị coi là không hợp lệ.

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

Nếu còn trang tiếp theo, response có header link chứa URL với rel="next". Hãy đọc header này thay vì suy đoán tổng số trang.

Để đồng bộ tăng dần, chỉ lấy các ticket có hoạt động kể từ lần chạy trước:

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

Thời điểm trong request nên dùng UTC và lần chạy kế tiếp nên có một khoảng chồng lấn nhỏ để giảm nguy cơ bỏ sót bản ghi ở ranh giới. Middleware cần chống xử lý trùng dựa trên ticket ID và updated_at.

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ự, phải đặt trong dấu nháy kép và URL encode.

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

Search API có độ trễ lập chỉ mục vài phút, vì vậy không nên dùng nó như nguồn duy nhất cho một luồng đồng bộ đòi hỏi nhận thay đổi ngay sau khi ghi.

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 đối tượng và trường nào trong Freshdesk.

Đối tượngDữ liệu bên ngoài thường gặpGhi chú ánh xạ
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 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 và xử lý trùng trước khi tạo
CompanyKhách hàng doanh nghiệpDùng khóa nghiệp vụ ổn định như mã khách hàng; không chỉ dựa vào tên
ConversationTin nhắn trả lời, ghi chú nội bộLưu ID tin nhắn bên ngoài để tránh 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 và kiểm thử trước khi go-live; tên API thường có tiền tố cf_

Các giá trị mặc định thường gặp 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.

Tài khoản có thể được cấu hình thêm trường hoặc trạng thái. Trước khi đưa vào vận hành, hãy đọc /api/v2/ticket_fields và xác nhận giá trị thực tế thay vì chỉ dựa vào danh sách mặc định.

Khi tạo ticket, cần cung cấp thông tin để xác định requester, chẳng hạn requester_id, email, phone, facebook_id hoặc twitter_id. Một số lựa chọn có ràng buộc bổ sung; ví dụ nếu chỉ gửi phone mà không có email thì trường name cũng bắt buộc.

Ví dụ code Freshdesk API

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ên cf_ma_don_hang chỉ là ví dụ. Custom field phải tồn tại trong tài khoản trước khi request được gửi.

Tìm hoặc tạo contact theo email bằng 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 freshdeskRequest(url, options = {}) {
  const response = await fetch(url, {
    ...options,
    headers: {
      Authorization: AUTH,
      'Content-Type': 'application/json',
      ...options.headers,
    },
  });

  if (!response.ok) {
    const body = await response.text();
    throw new Error(`Freshdesk ${response.status}: ${body}`);
  }

  return response.json();
}

async function findOrCreateContact(email, name) {
  const contacts = await freshdeskRequest(
    `${BASE}/contacts?email=${encodeURIComponent(email)}`,
  );

  if (contacts.length > 0) return contacts[0];

  return freshdeskRequest(`${BASE}/contacts`, {
    method: 'POST',
    body: JSON.stringify({ email, name }),
  });
}

Trong môi trường có nhiều worker, hai tiến trình vẫn có thể cùng không tìm thấy contact rồi cùng tạo mới. Hãy xử lý response xung đột và dùng khóa hoặc bảng ánh xạ ở lớp trung gian nếu cần bảo đảm duy nhất.

Duyệt ticket đã cập nhật và xử lý 429

async function fetchUpdatedTickets(since) {
  const headers = { Authorization: AUTH };
  let url = `${BASE}/tickets?updated_since=${encodeURIComponent(since)}&per_page=100`;
  const tickets = [];

  while (url) {
    const response = await fetch(url, { headers });

    if (response.status === 429) {
      const waitSeconds = Number(response.headers.get('Retry-After') || 60);
      await new Promise((resolve) => setTimeout(resolve, waitSeconds * 1000));
      continue;
    }

    if (!response.ok) {
      throw new Error(`Freshdesk ${response.status}: ${await response.text()}`);
    }

    tickets.push(...await response.json());

    const link = response.headers.get('link');
    const next = link?.match(/<([^>]+)>;\s*rel="next"/);
    url = next ? next[1] : null;
  }

  return tickets;
}

Ví dụ trên minh họa cơ chế chính. Khi chạy production, nên bổ sung timeout, retry có jitter cho lỗi mạng và 5xx, logging có correlation ID và giới hạn tổng thời gian xử lý.

Tạo webhook bằng Automation rule

Với ticket, Freshdesk gửi webhook thông qua action Trigger Webhook trong Automation rules khi ticket thỏa điều kiện đã cấu hình. Ví dụ dưới đây tạo rule gửi webhook khi agent thêm public note vào ticket.

Trang Automations trong khu vực quản trị Freshdesk

Hình 4: Mở Admin › Workflows › Automations trong Freshdesk.

Bước 1: Mở trang Automations

Trong Freshdesk, vào Admin › Workflows › Automations. Với Freshdesk Omni, đường dẫn có thể là Admin Settings › Configuration and Workflows › Ticket Automations. Chọn tab phù hợp:

  • Ticket Creation: chạy khi có ticket mới;
  • Ticket Updates: chạy khi ticket thay đổi, chẳng hạn có phản hồi hoặc ghi chú mới;
  • Hourly Triggers: chạy theo lịch và điều kiện thời gian.

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

Tab Ticket Updates trong trang Automations của Freshdesk

Hình 5: Chọn tab Ticket Updates và bấm New Rule.

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

Một rule cho ticket update gồm Event, Condition và Action:

  • Tên rule: đặt tên dễ truy vết, ví dụ HexaSync - Public note webhook.
  • Event: chọn người thực hiện và sự kiện kích hoạt, chẳng hạn agent thêm public note.
  • Condition: lọc thêm theo thuộc tính ticket; chọn Match ANY hoặc Match ALL phù hợp với nghiệp vụ.

Chọn action Trigger Webhook trong Freshdesk Automation

Hình 6: Thêm action Trigger Webhook sau khi thiết lập event và condition.

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

Ở phần Action, chọn Trigger Webhook và cấu hình:

TrườngCách cấu hình gợi ý
Request typeDùng POST khi gửi sự kiện sang hệ thống nhận
URLURL HTTPS của endpoint nhận; có thể chèn placeholder như {{ticket.id}}
Requires authenticationBật nếu endpoint cần xác thực và chọn phương thức phù hợp
Add custom headersThêm header phục vụ xác thực hoặc versioning, không ghi bí mật vào URL
EncodingChọn JSON
ContentDùng Simple để chọn trường có sẵn hoặc Advanced để tự viết body

Với Simple, có thể chọn Ticket ID, Subject, Last Public Comment, Agent Name hoặc Contact Name từ danh sách placeholder mà giao diện cung cấp.

Cấu hình nội dung JSON và placeholder cho Freshdesk webhook

Hình 7: Chọn JSON, cấu hình nội dung và kiểm tra các placeholder trước khi preview.

Nếu cần cấu trúc JSON riêng, chọn Advanced và dùng đúng placeholder hiển thị trong tài khoản, 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 rồi lưu. Thêm một public note vào ticket thử và kiểm tra endpoint có nhận đúng request, header và body hay không. Không dùng dữ liệu khách hàng thật cho lần thử đầu tiên nếu môi trường nhận chưa được kiểm soát.

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

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

  • tối đa 1.000 lượt gọi webhook mỗi giờ;
  • mã 200–299 được coi là thành công;
  • mã 300–399 được chuyển hướng;
  • các trường hợp khác được coi là thất bại và Freshdesk tự gửi lại mỗi 30 phút, tổng cộng 48 lần;
  • lượt gọi vượt giới hạn được đưa vào bộ đệm cho đến khi có hạn mức mới.

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

  • Xác thực request: kiểm tra credential hoặc header bí mật đã cấu hình và chỉ nhận qua HTTPS.
  • Phản hồi nhanh: xác thực tối thiểu, ghi sự kiện bền vững rồi trả mã 2xx; đư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 retry, nên dùng khóa idempotency nội bộ dựa trên dữ liệu sự kiện.
  • Không tin tuyệt đối vào payload: kiểm tra kiểu dữ liệu, giới hạn kích thước và escape nội dung trước khi ghi log hoặc hiển thị.
  • Lấy dữ liệu đầy đủ khi cần: webhook chỉ nên mang mã ticket và các trường chính; dữ liệu còn lại có thể đọc lại qua API.

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

Chống tạo ticket trùng

Freshdesk API không công bố idempotency key cho thao tác tạo ticket. Khi client retry hoặc hệ thống nguồn gửi lặp, cùng một yêu cầu có thể tạo nhiều ticket. Cách an toàn là giữ bảng ánh xạ tại middleware giữa mã bên ngoài và ticket ID Freshdesk, tra cứu trước khi tạo, đồng thời lưu mã bên ngoài vào custom field để đối soát.

Nếu luồng có xử lý song song, chỉ thao tác “tra cứu rồi tạo” là chưa đủ. Cần unique constraint hoặc cơ chế khóa ở lớp dữ liệu để hai worker không cùng tạo bản ghi.

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 exponential backoff có jitter và giới hạn số lần.
  • Lỗi 4xx khác: không retry tự động theo cùng một payload; ghi lại lỗi để sửa quyền, dữ liệu hoặc ánh xạ.
  • Bản ghi thất bại nhiều lần: chuyển vào dead-letter queue để xử lý lại sau, không chặn toàn bộ 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 hoặc sai giá trịĐọc mảng errors để sửa ánh xạ hoặc payload
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 không khả dụngKiểm tra quyền agent, gói và cấu hình tài khoản
404Không tìm thấy tài nguyênKiểm tra ID, trạng thái xóa và bảng ánh xạ
409Trạng thái xung đột, chẳng hạn contact đã tồn tạiĐọc lỗi và đối soát bản ghi hiện có
429Vượt rate limitChờ Retry-After và giảm tốc độ gửi

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

  • Freshdesk trả timestamp theo UTC. Lưu dữ liệu ở UTC và chỉ quy đổi sang giờ Việt Nam ở lớp hiển thị.
  • Dùng timestamp có timezone rõ ràng; không trộn thời gian local không offset với UTC.
  • Trạng thái đơn hàng hoặc hội thoại ở hệ thống khác cần được ánh xạ rõ sang status của ticket, kể cả ngoại lệ như hoàn trả một phần.

Không muốn tự xây kết nối?

HexaSync cung cấp giải pháp tích hợp Freshdesk với Zalo OA và có thể khảo sát nhu cầu kết nối Sapo, KiotViet, Shopify, TikTok Shop, WooCommerce, Magento, SHOPLINE, LarkSuite, Slack, Google Sheets hoặc Microsoft 365 Excel. Phạm vi cụ thể phụ thuộc phiên bản, gói dịch vụ, quyền API, dữ liệu và quy tắc nghiệp vụ của từng doanh nghiệp.

Liên hệ HexaSync để đánh giá miễn phí yêu cầu kết nối và xác định phạm vi triển khai.

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 Freshdesk Developers, gồm mô tả từng endpoint, tham số, mã lỗi và ví dụ request.

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

Theo bảng giới hạn API của Freshdesk, gói Free có giới hạn 0 lượt gọi mỗi phút; Growth, Pro, Enterprise và tài khoản trial có giới hạn riêng. Hãy kiểm tra gói và response header của chính tài khoản trước khi triển khai.

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 khu vực Your API Key trên trang hồ sơ.

Freshdesk có webhook không?

Có. Với ticket, bạn có thể cấu hình action Trigger Webhook trong Admin › Workflows › Automations, sau đó đặt đ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?

Theo dõi các header X-Ratelimit-*, đưa request vào hàng đợi, chờ theo Retry-After khi gặp 429 và hạn chế nhúng tài nguyên không cần thiết trong response.

Nguồn tham khảo

Đã sao chép link!

Đừng bỏ lỡ