← Tất cả bài viết
Hướng dẫn

Triển khai send guard WhatsApp 24 giờ cho phản hồi trong queue

Phản hồi WhatsApp trong queue có thể vượt qua cửa sổ 24 giờ khi chờ duyệt, retry hoặc worker nhận job. Một send guard đáng tin cậy phải đọc lại state ở server ngay trước lúc gửi, tính hạn từ tin nhắn người dùng mới nhất đã xác minh và chặn free-form text đã hết hạn. Hãy dùng cây quyết định service và utility message cho category và pricing; bài này chỉ tập trung vào biên thực thi ngăn gửi nhầm.

Điểm chính

  • Lưu hai mốc hết hạn và state_version tăng đơn điệu, không chỉ một biến boolean.
  • Chỉ inbound message của người dùng đã xác minh và deduplicate mới được đặt lại cửa sổ 24 giờ.
  • Sau khi lấy job, worker đọc lại state trong cùng transaction hoặc lock rồi mới chọn đường gửi.
  • Draft đã hết hạn phải dừng và route lại, không âm thầm đổi thành template.
  • Kiểm thử event trùng, event sai thứ tự, worker cạnh tranh và ranh giới chính xác đến giây.

Xây send guard quanh phản hồi trong queue

Trang giá Business Platform chính thức nêu rằng tin nhắn người dùng mở hoặc đặt lại cửa sổ 24 giờ. Ở lớp triển khai, biên cho phép này phải là điều kiện cuối cùng trước khi gửi. Category và thay đổi pricing tháng 10/2026 đã được giải thích trong hướng dẫn hiện có nên không lặp lại ở đây.

Với mỗi job trong queue, sender phải trả lời ba câu hỏi triển khai:

  1. Đã đọc phiên bản state mới nhất chưa? Worker cũ không được ghi đè cửa sổ đã cập nhật.
  2. Cửa sổ còn mở tại thời điểm gửi thật không? Không tái sử dụng kết quả lúc tạo hoặc duyệt draft.
  3. Đường gửi đã chọn còn được phép không? Sau khi cửa sổ đóng, chỉ dùng template đã duyệt và khớp đúng intent; nếu không thì dừng và trả cho agent.

Lưu hai đồng hồ thay vì một trạng thái

Các timestamp rõ ràng cho phép retry, job trễ và chuyển agent được đánh giá lại.

Giá trịĐiều gì mở hoặc đặt lạiĐiều gì được kiểm soát
service_window_expires_atMỗi tin nhắn inbound của người dùngCó được gửi service reply không dùng template không
free_entry_expires_atNgười dùng vào từ quảng cáo Click-to-WhatsApp hoặc nút CTA Facebook Page hợp lệGiao tin có được miễn phí trong 72 giờ không
last_user_message_idMỗi tin nhắn người dùng đã chấp nhậnIdempotency và bằng chứng audit
state_versionMỗi event làm đổi trạng tháiChặn job cũ ghi đè trạng thái mới

Free entry point 72 giờ không phải cửa sổ gửi kéo dài 72 giờ. Tin nhắn người dùng mới có thể đặt lại quyền gửi 24 giờ, còn hạn miễn phí vẫn là một ranh giới riêng.

Triển khai send guard

Đây là ví dụ TypeScript ở lớp ứng dụng, không phải schema payload của Meta. Quyền gửi và phí dự kiến được trả về riêng:

type WindowState = {
  serviceWindowExpiresAt: Date | null;
  freeEntryExpiresAt: Date | null;
};

function evaluateWhatsAppSend(state: WindowState, now: Date) {
  const serviceWindowOpen =
    state.serviceWindowExpiresAt !== null && now < state.serviceWindowExpiresAt;
  const freeEntryActive =
    state.freeEntryExpiresAt !== null && now < state.freeEntryExpiresAt;

  return {
    maySendNonTemplate: serviceWindowOpen,
    expectedDeliveryCharge: serviceWindowOpen && !freeEntryActive,
    requiredPath: serviceWindowOpen ? "service" : "approved_template",
  } as const;
}

Hãy dùng kết quả như chốt kiểm tra cuối cùng, không chỉ để hiển thị UI. Một phản hồi soạn lúc 10:00 có thể chờ duyệt đến sau khi cửa sổ đóng. Khi nhận job, sender phải đọc lại trạng thái hiện tại rồi chọn:

  1. Gửi service reply không dùng template khi cửa sổ còn mở.
  2. Chuyển sang template đã được phê duyệt khi cửa sổ đóng và ý định phù hợp.
  3. Dừng gửi và trả hội thoại cho agent nếu cả hai đường đều không hợp lệ.

Không tự động biến nội dung tự do thành template hoặc cắt nội dung để vừa template. Category, biến và phê duyệt template là các contract riêng.

Không kéo dài cửa sổ bằng event sai

Chỉ tin nhắn do người dùng gửi mới được đặt lại cửa sổ. Delivery receipt, status update, bản nháp của agent, ghi chú nội bộ, retry và echo của tin nhắn doanh nghiệp không được kéo dài nó.

Checklist xử lý:

  1. Xác minh webhook của provider trước khi thay đổi state.
  2. Loại trùng bằng message ID hoặc event ID ổn định.
  3. Xác nhận đây là inbound message do người dùng gửi, không phải receipt hoặc echo.
  4. Đặt service_window_expires_at bằng thời gian tin nhắn đã chấp nhận cộng 24 giờ.
  5. Chỉ tạo hạn miễn phí 72 giờ cho referral đủ điều kiện.
  6. Tăng state_version và lưu event nguồn để audit.
  7. Tính lại cả hai đồng hồ ngay trước mỗi lần gửi.

Không cộng 24 giờ vào hạn cũ. Nếu người dùng gửi lúc 09:00 và 12:00, hạn mới là 12:00 ngày hôm sau.

Kiểm thử biên queue và thứ tự event

Dùng fixed clock để kiểm thử chính xác đến một giây.

Tình huốngKết quả mong đợi
Người dùng gửi 10:00; phản hồi 09:59:59 hôm sauCho phép phản hồi không dùng template
Phản hồi đúng 10:00 hôm sauCoi cửa sổ đã đóng
Người dùng gửi tiếp lúc 09:50 hôm sauHạn mới là 09:50 của ngày kế tiếp
Duyệt trước hạn nhưng job được lấy sau hạnChặn và route lại
Cùng một tin nhắn người dùng được giao hai lầnDeduplicate để chỉ chuyển state một lần
Tin nhắn cũ đến sau tin nhắn mớiGiữ hạn mới hơn, không làm state lùi lại
Hai worker cùng lấy một phản hồiChỉ một worker qua kiểm tra version và gửi

Sau khi chạy thật, đối chiếu dự báo với status và pricing record chính thức. Hướng dẫn theo dõi phí service message tách volume giao tin khỏi mức giá theo thị trường. Nếu đang chọn Meta Business Agent hay AI riêng, xem so sánh giá và kiến trúc.

UnifyPort phù hợp ở đâu

State machine trên áp dụng cho WhatsApp Business Platform chính thức. Giao diện không chính thức của UnifyPort là một đường khác cho messaging account thông thường và không cung cấp trạng thái cửa sổ hay Pricing Analytics của Meta.

Trên đường riêng này, tin nhắn WhatsApp inbound đến dưới dạng event chuẩn hóa message.received. Nếu webhook endpoint có signing_secret, hãy xác minh X-Device-TimestampX-Device-Signature trên raw request body trước khi xử lý. Phản hồi chuẩn được hỗ trợ dùng POST /v1/messages. Xem tài liệu giao webhook và chữ ký cùng event message.received.

Không đưa event UnifyPort vào state machine tính phí Cloud API rồi nói rằng Meta đã phân loại nó. Nếu dùng cả hai đường, hãy lưu transport hoặc control_plane và tách sổ theo dõi.

Giới hạn và đánh đổi

WhatsApp Business Platform chính thức phù hợp khi cần template đã duyệt, campaign, attribution Click-to-WhatsApp, analytics của Meta hoặc dịch vụ BSP. Record chính thức là nguồn quyết định phí thực tế của delivery chính thức.

Giao diện không chính thức không phê duyệt template, không kéo dài cửa sổ Meta, không cung cấp Pricing Analytics và không thay đổi chính sách WhatsApp. Giá trị của nó là đường kết nối khác cho messaging account thông thường và event đa nền tảng được chuẩn hóa. Cả hai đường đều cần idempotency, kiểm soát concurrency và audit log.

Giá và quy tắc có thể thay đổi. Hãy kiểm tra lại tài liệu chính thức trước ngày 1/10 và không hard-code mức giá dự báo vào logic chuyển state.

FAQ

Send guard nên dùng timestamp nào?

Dùng thời điểm của tin nhắn người dùng mới nhất đã xác minh và được hệ thống chấp nhận, không dùng lúc nhận webhook, lúc tạo job hoặc đồng hồ đếm ngược trên UI.

Webhook sai thứ tự có làm cửa sổ ngắn lại không?

Không nên. Deduplicate bằng event ID ổn định và chỉ cập nhật hạn cùng state_version khi inbound message mới hơn record hiện tại.

Phản hồi trong queue hết hạn trước khi gửi thì sao?

Dừng free-form text và route lại. Chỉ chuyển sang template khi intent thực sự khớp một template đã duyệt; nếu không, trả hội thoại cho agent.

Có thể tự động đổi free-form text hết hạn thành template không?

Không được đổi âm thầm. Category, variable và approval của template là contract riêng cần được chọn và xác minh rõ ràng.

Làm sao tránh event trùng gây gửi hai lần?

Lưu message ID hoặc event ID, rồi để worker kiểm tra idempotency key và state_version trong transaction hoặc lock trước khi gửi.

Bước tiếp theo

Hãy làm đúng biên inbound trước: đọc tài liệu giao webhook và chữ ký, rồi kiểm thử event trùng hoặc sai thứ tự không làm cửa sổ bị kéo dài nhầm.

Nguồn

Nguồn chính thức được kiểm tra ngày 27/7/2026: