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.
Các nhóm tài nguyên thường dùng khi tích hợp:
| Tài nguyên | Endpoint | Dùng để |
|---|---|---|
| Ticket | /api/v2/tickets | Tạo, cập nhật, tra cứu yêu cầu hỗ trợ |
| Conversation | /api/v2/tickets/{id}/reply, /notes | Gửi phản hồi, ghi chú nội bộ trên ticket |
| Contact | /api/v2/contacts | Quản lý khách hàng (người gửi yêu cầu) |
| Company | /api/v2/companies | Quản lý khách hàng doanh nghiệp |
| Agent, Group | /api/v2/agents, /api/v2/groups | Phân công và phân tuyến ticket |
| Ticket field | /api/v2/ticket_fields | Xem 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
- Đăng nhập Freshdesk bằng tài khoản agent dùng cho tích hợp.
- Bấm ảnh đại diện ở góc trên bên phải, chọn Profile settings.
- 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.
- Sao chép API key và lưu vào nơi an toàn.
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ói | Tổng lượt gọi / phút | Tạo ticket | Cập nhật ticket | Liệt kê ticket | Liệt kê contact |
|---|---|---|---|---|---|
| Free | 0 | 0 | 0 | 0 | 0 |
| Growth | 100 | 50 | 50 | 40 | 40 |
| Pro | 400 | 160 | 160 | 100 | 100 |
| Enterprise | 700 | 280 | 280 | 200 | 200 |
| Trial | 50 |
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épX-Ratelimit-Remaining: số lượt còn lạiX-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ượng | Dữ liệu bên ngoài thường gặp | Ghi chú ánh xạ dữ liệu |
|---|---|---|
| Ticket | Tin nhắn Zalo OA, yêu cầu đổi trả, khiếu nại đơn hàng | Lưu mã tham chiếu bên ngoài (mã hội thoại, mã đơn) vào custom field |
| Contact | Khách hàng trên Zalo, phần mềm bán hàng, cửa hàng online | Khớp theo email hoặc số điện thoại, xử lý trùng trước khi tạo mới |
| Company | Khách hàng doanh nghiệp | Dùng domain email hoặc mã số thuế làm khóa |
| Conversation | Tin 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 |
| Group | Nhó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 field | Mã đơn, kênh, mã khách | Tạ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/ticketsTì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.
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.
Bước 3: Chọn action Trigger webhook
Ở phần Action, chọn Trigger webhook và điền:
| Trường | Nên điền |
|---|---|
| Request type | POST khi gửi dữ liệu sang hệ thống khác |
| URL | URL endpoint nhận webhook, có thể chèn placeholder như {{ticket.id}} |
| Requires authentication | Bậ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 headers | Thêm header bí mật nếu endpoint cần, ví dụ X-Webhook-Secret: <chuỗi bí mật> |
| Encoding | JSON |
| Content | Simple để chọn sẵn các trường ticket trong ô Placeholders, Advanced để tự viết nội dung JSON |
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}}.
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ặp | Cách xử lý |
|---|---|---|
| 400 | Thiế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 |
| 401 | Sai hoặc thiếu API key | Kiểm tra key và cách mã hóa Basic Auth |
| 403 | Agent không đủ quyền hoặc tính năng chưa bật | Kiểm tra quyền agent tích hợp và gói Freshdesk |
| 404 | Không tìm thấy tài nguyên | Ticket hoặc contact đã bị xóa, cập nhật bảng ánh xạ dữ liệu |
| 429 | Vượt rate limit | Chờ 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:
- 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.
- 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.
- 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.










