Chào anh em! Shipper Giao Hàng Tiết Kiệm (GHTK) giao xong từ ba hôm trước, khách đã nhận hàng, vậy mà đơn trên website vẫn nằm im ở “Đang xử lý”. Báo cáo doanh thu thiếu, nhân viên phải mở từng đơn ra bấm kiểm tra. Những ca “GHTK không cập nhật đơn hàng” mình từng hỗ trợ thường quy về một chỗ: webhook GHTK chưa chạy.

Đọc xong, anh em tự đăng ký webhook trên trang khách hàng GHTK và tự dò ra được vì sao đơn không đổi trạng thái. Thông số kỹ thuật lấy từ tài liệu API chính thức của GHTK, phần còn lại là kinh nghiệm hỗ trợ khách dùng plugin GHTK cho WooCommerce mà mình viết.
Webhook GHTK là gì, có bắt buộc không?
Bình thường website phải tự hỏi GHTK “đơn này tới đâu rồi”. Webhook đảo chiều lại: mỗi khi vận đơn đổi trạng thái, máy chủ GHTK chủ động gửi một request POST về đường dẫn của website. Website nhận tin và tự đổi trạng thái đơn: giao xong thì hoàn thành, trả hàng thì huỷ.
Để duy trì blog nên mình có làm aff cho 1 số bên hosting. Nhưng dù aff mình cũng chọn 1 số nhà cung cấp uy tín về chất lượng và support nên các bạn cứ yên tâm nhé.
Nếu có mua hosting mà có trong list dưới đây các bạn click vào link trước khi mua để ủng hộ mình nhé. Mình cảm ơn nhiều
- Azdigi: Giá rẻ thì dùng gói Pro Gold Hosting còn chất lượng hơn thì em khuyên dùng Business Hosting. Có điều kiện thì lên VPS nhé
- Tino hosting với mã giảm giá độc quyền lên tới 40%. Xem tại đây
- iNet
- Nước ngoài thì Vultr
Không bắt buộc. Thiếu webhook thì anh em vẫn cập nhật được bằng tay (với plugin là nút Check đơn hàng trong từng đơn). Shop vài đơn một ngày làm tay cũng ổn. Từ vài chục đơn một ngày trở lên thì nên có webhook: không ai phải ngồi bấm kiểm tra từng đơn, và báo cáo doanh thu khớp với hàng đã giao.
Cách đăng ký webhook
GHTK nay cho shop tự cấu hình webhook trên trang khách hàng, không còn phải gửi thư nhờ GHTK bật như trước. Việc gồm hai phần: lấy đường dẫn trong plugin, rồi dán vào trang GHTK.
Với plugin GHTK cho WooCommerce
- Vào WooCommerce → Cài đặt GHTK → tab Cài đặt GHTK, kéo xuống khối Webhook nền hồng.
- Bấm Lưu thay đổi rồi tải lại trang. Lần đầu mở khối này, mã hiện ra mới là mã tạm, chưa lưu; dán mã đó vào GHTK là dán nhầm.
- Chép nguyên dòng Webhook Link, kể cả phần
&hash=…ở cuối.

Cấu hình webhook trên trang khách hàng GHTK
- Đăng nhập trang khách hàng GHTK, bấm tên shop ở góc trên bên trái, chọn Thông tin tài khoản, rồi chọn Cấu hình API ở cột bên trái.
- Ở khối Webhook, bấm Cấu hình webhook. GHTK có thể hỏi mật khẩu tài khoản để xác thực: nhập mật khẩu rồi bấm Xác thực.

- Trong hộp Cấu hình Webhook: Trạng thái chọn Hoạt động, Data format chọn Json, dán Webhook Link vừa chép vào ô URL đích, để trống Headers.
- Bấm Lưu thông tin. Khối Webhook hiện dòng URL đích với trạng thái Đang hoạt động là xong; đăng thử một đơn và theo dõi trạng thái có tự đổi không.


Chi tiết từng ô có ở trang webhook và đồng bộ trạng thái trong tài liệu plugin.
Tự code
Tạo một endpoint nhận POST (REST route hoặc admin-ajax), đường dẫn chứa một mã bí mật dạng ?hash=… để chặn request giả, rồi dán đường dẫn đó vào Cấu hình webhook trên trang khách hàng GHTK như trên. Đoạn code mẫu có ở bài tích hợp GHTK vào WordPress, phần client gọi API ở bài GHTK API sandbox bằng PHP.
Những trường GHTK gửi về
Mỗi lần vận đơn đổi trạng thái, GHTK POST về các trường sau:
label_idlà mã vận đơn GHTK, cònpartner_idlà mã đơn bên anh em, chính làorder.idđã gửi lúc đăng đơn.status_idlà mã trạng thái mới,action_timelà thời điểm cập nhật theo định dạng ISO 8601.reason_codevàreasonlà mã và nội dung lý do khi chậm lấy, chậm giao, không giao được…weightlà khối lượng tính bằng kg,feelà phí ship,pick_moneylà tiền thu hộ, cònreturn_part_packagebằng 1 nghĩa là đơn giao một phần.
Ví dụ trong tài liệu GHTK gửi dạng form (application/x-www-form-urlencoded), còn plugin của mình đăng ký kiểu JSON. Endpoint tự viết nên đọc được cả hai.
Endpoint phải trả về HTTP 200. Không nhận được phản hồi hoặc nhận mã khác 200 thì GHTK gửi lại đúng một lần nữa rồi thôi. Lỗi hai lần liền là mất luôn bản tin đó, đơn đứng yên cho tới khi có trạng thái kế tiếp hoặc anh em tự kiểm tra.
Mã trạng thái nào nên dùng để chốt đơn?
GHTK có hơn hai mươi mã trạng thái. Những mã anh em sẽ gặp thường xuyên:
- Đơn còn đang xử lý mang mã 1 (chưa tiếp nhận), 2 (đã tiếp nhận), 12 (đang lấy hàng), 3 (đã lấy hàng/nhập kho) hoặc 4 (đang giao hàng).
- Đơn giao thành công mang mã 5 (đã giao hàng/chưa đối soát) hoặc 6 (đã đối soát).
- Đơn có vấn đề mang mã 7 (không lấy được hàng), 8 (hoãn lấy hàng), 9 (không giao được hàng) hoặc 10 (delay giao hàng).
- Đơn bị huỷ, trả hoặc bồi hoàn mang mã -1 (huỷ đơn), 20 (đang trả hàng), 21 (đã trả hàng), 11 (đã đối soát công nợ trả hàng) hoặc 13 (đơn hàng bồi hoàn).
- Tin báo của shipper mang mã 123 (báo đã lấy hàng), 127 (báo không lấy được), 128 (báo delay lấy), 45 (báo đã giao), 49 (báo không giao được) hoặc 410 (báo delay giao).
Nhóm cuối cần để ý. GHTK ghi rõ các mã 123, 127, 128, 45, 49, 410 chỉ là thông báo, không phải trạng thái chính thức của đơn, và có thể bị sửa lại: shipper báo 123 rồi sau đó báo 127 vì thao tác nhầm. Muốn chắc ăn thì chốt “Hoàn thành” ở mã 5 hoặc 6; tin báo của shipper chỉ nên ghi chú vào đơn. Dùng plugin thì quyết định này nằm ở bảng Cài đặt trạng thái đơn hàng trong tab Cài đặt GHTK: dòng nào không muốn đơn đổi theo thì chọn Không đồng bộ trạng thái.
Mã lý do (reason_code) cũng chia nhóm: 100–107 chậm lấy hàng, 110–115 không lấy được hàng, 120–129 và 1200 chậm giao hàng, 130–135 không giao được hàng, 140–144 delay trả hàng. Ghi lý do vào ghi chú đơn giúp nhân viên chăm sóc khách biết ngay vì sao đơn trễ.
GHTK không cập nhật đơn hàng: kiểm theo thứ tự này
- Mở lại Cấu hình API trên trang khách hàng GHTK: webhook phải ở trạng thái Đang hoạt động, và URL đích phải đúng nguyên đường dẫn hiện tại trong plugin, kể cả phần
hash=. - Kiểm tra website có gọi được từ Internet không, vì site chạy trên máy local hay tên miền chưa trỏ ra ngoài thì webhook không bao giờ tới.
- Cloudflare, tường lửa máy chủ hay plugin bảo mật có thể chặn request POST từ máy chủ lạ vào
admin-ajax.php, nên tạo quy tắc cho phép đúng đường dẫn webhook đi qua. - Dán vào URL đích đúng đường dẫn cuối cùng, vì dán bản
http://trong khi site tự chuyển sanghttps://, hoặc lệch có/khôngwww, thì GHTK có thể nhận mã chuyển hướng 301 thay vì 200. - Vừa bấm Đổi Webhook Key thì đường dẫn cũ đã hết hiệu lực, phải bấm Sửa ở khối Webhook trên GHTK và dán đường dẫn mới.
- Lỗi PHP, chế độ bảo trì hay máy chủ quá tải đều làm endpoint trả mã khác 200, và lỗi hai lần liền thì GHTK bỏ luôn bản tin đó.
- Dòng nào trong bảng ánh xạ trạng thái để Không đồng bộ trạng thái thì GHTK vẫn báo về nhưng đơn giữ nguyên, và đó là đúng thiết kế.
- Đơn tạo trên trang GHTK hay phần mềm khác thì
partner_idkhông khớp đơn nào trên website, nên webhook không có đơn nào để cập nhật.
Cách kiểm tra webhook đã chạy
Với plugin: đăng một đơn, chờ shipper nhận đơn, rồi mở đơn ra xem hộp Đăng đơn GHTK. Dòng Cập nhật lúc đổi mà anh em không bấm Check đơn hàng lần nào là webhook đang chạy. Cần soi kỹ hơn thì bật Debug trong tab Cài đặt GHTK: mỗi lần GHTK gửi tin, nội dung được ghi vào WooCommerce → Trạng thái → Nhật ký (nguồn devvn-ghtk). Xong việc nhớ tắt Debug cho nhẹ máy chủ.
Muốn tự bắn thử một bản tin thì dùng curl, nhưng chỉ làm trên bản sao website hoặc đơn thử: webhook ghi đè mã vận đơn và trạng thái vào đơn có partner_id tương ứng. Mình chọn mã 3 vì mặc định plugin không đổi trạng thái đơn với mã này:
curl -i -X POST 'https://ten-mien-cua-ban/wp-admin/admin-ajax.php?action=update_shipping_status&hash=MA_WEBHOOK' \
--data-urlencode 'partner_id=123' \
--data-urlencode 'label_id=S1.A1.TEST' \
--data-urlencode 'status_id=3' \
--data-urlencode 'action_time=2026-10-16T08:30:00+07:00'
Dòng đầu kết quả phải là HTTP/1.1 200 OK (hoặc HTTP/2 200). Ra 403 hay 503 thường là tường lửa chặn; ra 301 là đường dẫn đang bị chuyển hướng. Plugin trả 200 cả khi mã hash sai, nên 200 chỉ chứng tỏ request đã vào tới WordPress. Muốn chắc tin đã được nhận thì mở đơn thử ra xem, hoặc xem Nhật ký khi đang bật Debug. Dùng --data-urlencode chứ đừng dùng -d cho trường thời gian, vì dấu + trong +07:00 sẽ bị hiểu thành khoảng trắng.
Tra trạng thái định kỳ khi tự code
Vì GHTK chỉ gửi lại một lần, hệ thống tự viết nên có thêm một tác vụ định kỳ (Action Scheduler hoặc WP-Cron), ví dụ vài giờ một lần, gọi API tra trạng thái GET /services/shipment/v2/{mã vận đơn} cho các đơn đã đăng mà chưa kết thúc. Webhook lo phần nhanh, tác vụ định kỳ lo phần chắc. Plugin thì có sẵn nút Check đơn hàng trong từng đơn cho trường hợp lỡ mất tin.
Câu hỏi thường gặp
Đổi tên miền thì webhook có chạy tiếp không?
Không. GHTK gửi đúng đường dẫn đã đăng ký, nên đổi tên miền (hay chuyển từ http sang https) xong phải sửa URL đích trên GHTK theo đường dẫn mới.
GHTK gửi JSON hay form?
Ví dụ trong tài liệu GHTK là form (x-www-form-urlencoded), còn khi đăng ký có thể ghi rõ kiểu JSON như plugin của mình. Endpoint tự viết cứ đọc cả hai cho chắc: trong WordPress, WP_REST_Request::get_param() làm được việc đó.
Lỡ mất bản tin thì GHTK có gửi lại không?
Chỉ một lần. Endpoint không trả 200 thì GHTK gửi lại thêm một lần rồi thôi. Sau đó phải tự tra trạng thái qua API hoặc bấm kiểm tra trong đơn.
Muốn có sẵn phần nhận webhook, bảng ánh xạ trạng thái và nút kiểm tra từng đơn mà không phải viết gì thì xem plugin GHTK cho WooCommerce. Còn vướng chỗ nào trong danh sách kiểm tra ở trên thì cứ để lại bình luận, nhớ che mã hash trong đường dẫn nhé.
Bài viết trong series
Kết nối WooCommerce với Giao Hàng Tiết Kiệm
0/4đã đọc- 1 Tích hợp Giao Hàng Tiết Kiệm vào WordPress, WooCommerce: tự code API hay dùng plugin? Đang đọc Đã đọc
- 2 GHTK API sandbox: tích hợp API Giao Hàng Tiết Kiệm bằng PHP trong WordPress Đang đọc Đã đọc
- 3 Webhook GHTK: đăng ký, xử lý và sửa lỗi GHTK không cập nhật đơn hàng Đang đọc Đã đọc
- 4 Cách lấy API token GHTK theo giao diện mới: tạo token, chọn quyền, ngày hết hạn Đang đọc Đã đọc




