Số điện thoại không còn là cách WhatsApp định danh khách hàng của bạn. Phần lớn CRM vẫn chưa bắt kịp.
WhatsApp đang dịch định danh khách hàng ra khỏi số điện thoại, và nếu bạn vận hành một CRM hay bất kỳ kiểu messaging integration nào, sự thay đổi đã chạm tới bạn rồi. Kể từ đợt rollout cuối tháng 3 đến đầu tháng 4 năm 2026, mọi message webhook của WhatsApp Cloud API đều mang một trường định danh mới gọi là Business-Scoped User ID, hay BSUID, một token mờ mà Meta phát hành theo từng portfolio doanh nghiệp. [1][2] Nó đến như một trường của riêng nó chứ không phải một giá trị mới nhồi vào trường số điện thoại cũ, và bản thân số điện thoại giờ có thể vắng mặt một khi một user chọn một WhatsApp username. Nếu bạn chỉ thay đổi một thứ sau khi đọc bài này, hãy để nó là thứ này: xem BSUID như khóa định danh trên mọi tin nhắn inbound, giữ số điện thoại làm một alias nullable, và ngừng giả định rằng to, from, hay wa_id sẽ chứa một số điện thoại. [2] Phần còn lại của bài viết này là bản đồ từng trường một, đã đối chiếu với tài liệu gốc, cộng với những sai lầm vốn đã lan truyền khắp nơi.
Hai thứ đang hạ cánh cùng lúc và gần như mọi người chạy chúng chung làm một. Một là một tính năng riêng tư cho user, WhatsApp username, vốn cho phép ai đó tiếp cận một doanh nghiệp mà không phải đưa số của mình. Cái còn lại là một thay đổi định danh cho developer, BSUID, vốn hiện ra trong Cloud API bất kể một user cụ thể có bao giờ đặt username hay không. Username chiếm các tiêu đề, nhưng BSUID mới là cái âm thầm phá vỡ các integration, nên đáng để giữ hai cái này tách bạch. Chúng chạy trên những timeline khác nhau và chúng chạm vào những phần khác nhau trong stack của bạn.
Hai tầng, không phải một
Phần lớn các bài viết coi "WhatsApp usernames" và "BSUID" là một đợt ra mắt. Thực ra chúng là hai tầng, nhắm vào những người khác nhau, với bán kính tác động rất khác nhau.
| Tầng |
Nó là gì |
Ai bị ảnh hưởng |
Trạng thái tính đến tháng 6 năm 2026 |
| WhatsApp username |
Một handle công khai tùy chọn cho phép một user được tiếp cận mà không phải chia sẻ số điện thoại của họ [2][6] |
Người dùng cuối (opt-in, không ai bị buộc phải dùng) |
Beta giới hạn từ tháng 4 năm 2026, rollout rộng hơn bắt đầu từ tháng 6 năm 2026 [2][3][5] |
| Business-Scoped User ID (BSUID) |
Một token định danh mờ mới trong Cloud API, hiện diện cho mọi user bất kể có chọn username hay không [1][2] |
Mọi doanh nghiệp, CRM, và integration BSP trên nền tảng |
Đã hoạt động trong message webhook kể từ đợt rollout cuối tháng 3 đến đầu tháng 4 năm 2026 [1][2][5] |
Chính khoảng cách đó là cái làm các đội vấp ngã. Bạn không thể chờ usernames rollout xong rồi mới làm việc, vì phía developer đã ship rồi. BSUID đã ở trong webhook của bạn ngay bây giờ, kể cả với những user sẽ chẳng bao giờ đụng tới tính năng username.
Lộ trình rollout, kèm ngày tháng
Các mốc có ngày bên dưới được rút từ tài liệu BSP vốn phản chiếu hướng dẫn dành cho partner của Meta. Ở đâu một ngày là rollout-đang-diễn-ra chứ không phải một thời điểm chuyển đổi cố định, chúng tôi nói rõ.
| Ngày |
Mốc |
Tầng |
| Cuối tháng 3 / đầu tháng 4 năm 2026 |
BSUID bắt đầu xuất hiện trong message webhook của Cloud API và BSP. Trang chính của Meta ghi đầu tháng 4; bảng timeline của Azure và 360dialog ghi 31 tháng 3 [1][2][5] |
Developer |
| Đầu tháng 4 năm 2026 |
Contact Book ra mắt: một kho do Meta lưu trữ, bật mặc định, chứa các ánh xạ số-điện-thoại-tới-BSUID [2] |
Developer |
| Tháng 4 năm 2026 |
Beta giới hạn WhatsApp username cho một nhóm nhỏ user [3][5] |
User |
| Tháng 5 năm 2026 (ngày chính xác đang chờ) |
Cloud API trực tiếp của Meta bắt đầu hỗ trợ gửi tới một BSUID qua trường recipient mới [1] |
Developer |
| Tháng 6 năm 2026 |
Username bắt đầu chạm tới người dùng cuối và doanh nghiệp có thể đăng ký handle; Azure và Twilio đặt khung khả dụng gửi qua wrapper của họ quanh mốc này [2][3] |
User |
| Phần còn lại của năm 2026 |
Mở rộng theo từng giai đoạn, từng quốc gia một, hướng tới khả dụng rộng [5] |
User |
Có một mốc đáng có một lưu ý, và nó là một minh họa rõ ràng cho sự chia tách raw-API-so-với-BSP mà bài này cứ quay lại nhắc tới. Trang BSUID của chính Meta nói rằng Cloud API trực tiếp sẽ không hỗ trợ gửi tới một BSUID cho đến tháng 5 năm 2026, với ngày chính xác đang chờ. [1] Azure và Twilio đặt khung khả dụng production quanh mốc tháng 6 năm 2026, gắn với việc username chạm tới người dùng cuối. [2][3] Vì vậy hãy xem khả dụng outbound như đặc thù theo từng nhà cung cấp: hợp đồng thô là trường recipient mới, nhưng việc bạn thực sự dùng được nó khi nào thì phụ thuộc vào việc bạn đang ở trên API trực tiếp hay một BSP, và mỗi bên có thể hạ cánh vào ngày riêng của nó. Hãy xác nhận với nhà cung cấp của bạn.
Webhook inbound thực sự trông như thế nào
Đây là chỗ mà phần lớn các bài viết đi sai. Trên Cloud API trực tiếp, BSUID là trường của riêng nó. Nó không phải wa_id cũ mang theo một kiểu giá trị mới.
| Trường (Cloud API thô) |
Mang gì |
Hiện diện khi |
contacts[].user_id |
BSUID của user |
Luôn luôn, trong mọi message webhook [1][6] |
messages[].from_user_id |
BSUID của người gửi |
Luôn luôn, trong mọi message webhook [1] |
contacts[].profile.username |
WhatsApp username |
Chỉ khi user đã đặt một cái [1][6] |
contacts[].wa_id |
Số điện thoại |
Khi số điện thoại còn khả dụng; bị bỏ qua một khi một username được chọn và các điều kiện đính kèm số điện thoại không được thỏa mãn [2] |
messages[].from |
Số điện thoại của người gửi |
Cùng điều kiện như wa_id [2] |
statuses[].recipient_user_id |
BSUID của người nhận |
Trên các status webhook, dù lần gửi gốc dùng số điện thoại hay một BSUID. Ngoại lệ duy nhất bị bỏ qua: một status thất bại mà tin nhắn của nó được đặt địa chỉ bằng số điện thoại [1][6] |
Hình dạng cần nhớ là user_id và from_user_id luôn ở đó, trong khi các trường số điện thoại thì không. Khi số điện thoại còn khả dụng, bạn nhận được cả hai cùng lúc, số điện thoại trong wa_id và from, BSUID trong user_id và from_user_id. [2] Một khi một user chọn một username và không có lịch sử gần đây với bạn, các trường số điện thoại có thể đến rỗng hoặc thiếu, và BSUID là thứ duy nhất định danh người gửi.
Meta giữ cho số điện thoại tiếp tục chảy khi ít nhất một trong các điều kiện này thỏa mãn, được kiểm theo từng số điện thoại doanh nghiệp chứ không theo từng portfolio: [2]
- Bạn đã nhắn tin hoặc gọi tới số của user trong vòng 30 ngày qua.
- Bạn đã nhận một tin nhắn hoặc cuộc gọi từ số của user trong vòng 30 ngày qua.
- User nằm trong Contact Book của bạn.
Vậy nên một cuộc đối thoại đang diễn ra thì không sao. Số điện thoại biến mất với những contact mới, chỉ-có-username, không có lịch sử, mà tình cờ đó lại đúng là nhóm mà một doanh nghiệp lead-gen làm việc cùng suốt ngày: một tin nhắn đầu tiên từ ai đó bạn chưa từng nói chuyện.
Tên trường trên Cloud API trực tiếp khác với tên trường của BSP
Nếu bạn không ở trên Cloud API trực tiếp, Business Solution Provider của bạn đã đổi tên các trường này. Đọc một hướng dẫn integration của BSP rồi đi tìm những cái tên đó trong một payload Cloud API thô là một ngõ cụt phổ biến.
| Bề mặt |
Tên trường BSUID |
Nguồn |
| Direct Cloud API |
contacts[].user_id và messages[].from_user_id |
[1] |
| Twilio |
ExternalUserId |
[3] |
| Infobip |
contact.userId |
[4] |
| Azure Communication Services |
fromBSUID (inbound) và toBSUID (delivery status) |
[2] |
Bên dưới thì đằng nào cũng là cùng một BSUID mờ. Chỉ có lớp wrapper bao quanh nó là thay đổi.
Địa chỉ outbound: cùng endpoint, nhưng API thô thêm recipient
Endpoint gửi không thay đổi, nhưng trường trên Cloud API thô thì có. Gửi theo số điện thoại vẫn dùng to. Gửi theo BSUID dùng một trường recipient mới. [1] Phải có ít nhất một trong hai hiện diện, và nếu bạn gửi cả hai, Meta ưu tiên to, vì vậy chúng là những đầu vào địa chỉ riêng biệt chứ không phải một trường duy nhất tự nhận diện cái bạn đưa cho nó. [1] Đây là chỗ mà các wrapper BSP lệch xa nhất khỏi hợp đồng trực tiếp: Azure Communication Services, chẳng hạn, nhận hoặc một số điện thoại hoặc một BSUID trong mảng to duy nhất của nó và tự xử lý cho bạn [2], một việc chuẩn hóa tiện lợi nhưng không phải là cái API thô làm. Nếu bài của bạn tuyên bố ánh xạ Cloud API trực tiếp, như bài này, thì recipient là trường có ý nghĩa.
Định dạng kỹ tính cả hai đằng. Một BSUID là một mã quốc gia ISO 3166 alpha-2, rồi một dấu chấm, rồi tới 128 ký tự chữ và số, như US.13491208655302741918. Mã quốc gia và dấu chấm là một phần của giá trị [2], vì vậy lược bỏ chúng hay "chuẩn hóa" BSUID theo cách bạn có thể chỉnh gọn một số điện thoại sẽ làm hỏng lần gửi.
Có một ngoại lệ thật sự. Các template thuộc nhóm authentication vẫn cần một số điện thoại. Các template auth one-tap, zero-tap, và copy-code không thể gửi tới một BSUID, và việc thử sẽ trả về Meta error 131062. [6] Nếu luồng one-time-passcode của bạn chạy qua WhatsApp, nó cần số điện thoại, đó là thêm một lý do nữa để chộp lấy cặp số-điện-thoại-tới-BSUID khi bạn vẫn còn số điện thoại.
Mô hình định danh: mờ, scope theo phạm vi, và không phải lúc nào cũng đảo ngược được
Cách BSUID hành xử quyết định nó thuộc về đâu trong mô hình dữ liệu của bạn. Mỗi dòng bên dưới ánh xạ tới một quyết định thiết kế.
| Thuộc tính |
Hành vi |
| Scope |
Duy nhất theo từng portfolio doanh nghiệp. Cùng một user có một BSUID khác nhau với mỗi doanh nghiệp mà họ tương tác, vì vậy nó không phải một khóa nhận dạng người dùng toàn cục. [1][2] |
| Tính mờ |
Một token mờ. Nó không phải một số điện thoại và không mang ý nghĩa có thể phân tích nào ngoài tiền tố quốc gia. [2] |
| Định dạng |
{ISO 3166 alpha-2}.{tới 128 ký tự chữ và số}, dùng nguyên vẹn, bao gồm cả mã quốc gia và dấu chấm. [2] |
| Đổi username |
Ổn định. Đổi một username không làm đổi BSUID. [2] |
| Đổi số điện thoại |
Được tạo lại. Đổi số điện thoại tạo ra một BSUID mới, và Meta gửi một webhook user_id_update mang cả BSUID cũ lẫn mới để bạn có thể relink. [1][2] |
Relink khi đổi định danh, đừng tạo bản trùng
Khi ai đó đổi số điện thoại trên tài khoản của họ, BSUID được tạo lại, và Meta thông báo điều đó qua một webhook user_id_update đã được tài liệu hóa, vốn mang cả BSUID cũ lẫn mới. [1][2] Dùng BSUID cũ để tìm bản ghi hiện có và cái mới để cập nhật nó, để sự thay đổi hạ cánh như một thao tác merge chứ không phải một contact mới. Coi nó như một user hoàn toàn mới thì bạn sẽ kết thúc với lịch sử của một người bị chia tách trên hai bản ghi.
Một điều cần làm cho đúng: đây là payload thay-đổi-định-danh của riêng nó, không phải một delivery status, vì vậy đừng nối việc relinking vào các callback statuses[] ở chỗ khác trong bản đồ này. Một số tài liệu BSP cũng phơi ra một system message song song cho cùng sự thay đổi, vì vậy hãy xác nhận hình dạng payload chính xác đối chiếu với tài liệu tham chiếu trực tiếp của Meta trước khi bạn dựng dựa trên nó. Hành vi thì giống nhau ở mọi nơi: định danh đã đổi, vậy hãy relink thay vì tạo bản trùng.
Khôi phục số điện thoại chỉ đi một chiều về phía trước
Contact Book của Meta lưu các ánh xạ số-điện-thoại-tới-BSUID một cách tự động. Nó do Meta lưu trữ, bật mặc định, và scope theo portfolio doanh nghiệp. [2] Điều bất ngờ với nhiều người là nó chỉ ghi lại các tương tác từ sau khi nó ra mắt vào tháng 4 năm 2026, không bao giờ backfill, và chẳng có gì để ghi với một contact chỉ-có-username hoàn toàn mới vốn chưa từng chia sẻ một số nào. [2] Vì vậy bạn không thể trông cậy vào việc khôi phục một số điện thoại cho một contact chỉ-có-BSUID sau này.
Điều đó dẫn tới một thói quen đơn giản: bất cứ khi nào một webhook có kèm số điện thoại, hãy lưu cặp số-điện-thoại-tới-BSUID ngay lúc đó. Đừng để dành cho sau.
Pattern mô hình dữ liệu chuẩn
Mọi CRM và messaging integration đều đi tới cùng một hình dạng, và đó là một thay đổi nhỏ dựng trên một quy tắc. BSUID là khóa chính; số điện thoại là alias.
- Lưu BSUID làm khóa định danh chính bền vững cho mỗi cặp (doanh nghiệp, contact). Giữ số điện thoại làm một alias bổ sung, nullable trên cùng bản ghi. [2][5]
- Đọc trường BSUID (
user_id hoặc from_user_id, hoặc tương đương của BSP) làm định danh đáng tin cậy trên mọi tin nhắn inbound. Ngừng đọc to, from, hay wa_id như một số điện thoại được bảo đảm. [2]
- Capture cặp số-điện-thoại-tới-BSUID bất cứ khi nào số điện thoại hiện diện, vì Contact Book sẽ không backfill nó cho bạn. [2]
- Merge khi có định danh kép. Nếu bạn đã có một contact theo số điện thoại và một BSUID mới đến cho cùng người đó trong một cuộc đối thoại đang hoạt động, hãy liên kết chúng thay vì tạo một bản ghi thứ hai.
- Khi có sự kiện thay-đổi-định-danh, relink contact hiện có sang BSUID mới. [2]
Nếu schema của bạn khóa các contact WhatsApp theo số điện thoại, đó là thứ đầu tiên cần sửa, vì số điện thoại giờ là trường có thể biến mất còn BSUID là trường luôn đến.
Những hiểu lầm phổ biến
Những điều này đã lan truyền trong các bài viết của vendor và các thread integration. Phần lớn là kiểu lối tắt nghe có vẻ hợp lý vốn lọt qua review trơn tru rồi đổ sập ngay lần đầu một lead chỉ-có-username xuất hiện.
BSUID chỉ là trường wa_id với một kiểu giá trị mới. Không phải vậy. Nó là một trường riêng biệt, contacts[].user_id và messages[].from_user_id, nằm cạnh các trường số điện thoại. [1] Code canh wa_id để tìm "một giá trị trông khác đi" sẽ bỏ sót BSUID hoàn toàn trên bất kỳ payload nào mà số điện thoại cũng hiện diện.
Số điện thoại luôn ở đó, nên phân tích from như một số điện thoại là an toàn. Không còn nữa. Một khi một user chọn một username và không có lịch sử gần đây với bạn, from và wa_id có thể rỗng hoặc vắng mặt. [2] Bất cứ thứ gì kiểm tra hợp lệ hay định dạng các trường đó như một số E.164 sẽ vỡ đúng vào những contact mà bạn cần nhất, những cái mới.
Bạn chỉ cần thả BSUID vào trường to và API sẽ tự lo. Điều đó đúng trên một số wrapper BSP, như Azure ACS [2], nhưng không đúng trên Cloud API thô. API trực tiếp giữ to cho số điện thoại và thêm một trường recipient riêng cho việc gửi BSUID, với to được ưu tiên nếu cả hai cùng hiện diện. [1] Đặt một BSUID vào to đối với API thô thì bạn không gửi đi cái bạn nghĩ đâu. Các template authentication là một ngoại lệ nữa: chúng vẫn cần một số điện thoại và trả về error 131062 nếu bạn trỏ chúng tới một BSUID. [6]
Bạn có thể lược bỏ tiền tố quốc gia và dấu chấm để "dọn dẹp" BSUID. Bạn không thể. Mã quốc gia và dấu chấm là một phần của giá trị, và thay đổi bất kỳ phần nào của nó khiến request thất bại. [2]
BSUID định danh một người xuyên suốt nền tảng. Không phải. Nó scope theo portfolio, vì vậy cùng một người mang một BSUID khác nhau với mỗi doanh nghiệp. Bạn không thể dùng nó để nhận ra ai đó qua hai doanh nghiệp hay để chia sẻ định danh giữa các portfolio không liên quan. [1][2] Nó là định danh bên trong thế giới của bạn, không phải xuyên suốt nền tảng.
Contact Book nghĩa là bạn luôn có thể tra cứu một số điện thoại sau này. Nó chỉ đi về phía trước. Nó ghi các ánh xạ từ sau lần ra mắt tháng 4 năm 2026 của nó, không bao giờ backfill, và chẳng có gì để ghi với một contact chỉ-có-username vốn chưa từng chia sẻ một số. [2] Hãy tự capture cặp đó khi bạn còn nó.
Một sự kiện đổi-số-điện-thoại nghĩa là một user mới. Đó là cùng một user với một BSUID được tạo lại, vậy hãy relink bản ghi hiện có. [2] Tạo bản trùng thay vì vậy thì bạn chia tách lịch sử của một người trên hai contact.
Một lưu ý cho các đội làm trên giao thức không chính thức: BSUID không phải @lid
Nếu stack của bạn cũng chạm vào giao thức multi-device không chính thức qua một thư viện như Baileys, bạn có lẽ đã gặp một định danh khác: @lid "LinkedID" JID xuất hiện khi JID số-điện-thoại thật của một user bị ẩn. [8] Chúng trông như cùng một thứ, nhưng không phải.
BSUID là một cấu trúc Cloud API chính thức, scope theo portfolio và mờ, được giao trong các trường webhook đã tài liệu hóa. @lid JID sống bên trong việc đặt địa chỉ multi-device của WhatsApp và toàn cục theo từng user, không scope vào một doanh nghiệp duy nhất. [8] Cả hai đều đuổi theo cùng một ý tưởng, đưa định danh ra khỏi số điện thoại, nhưng chúng là những cơ chế khác nhau trên những bề mặt khác nhau, và một ánh xạ bạn dựng cho cái này sẽ không chuyển sang cái kia.
Deadline ràng buộc trên WhatsApp hơn so với các kênh khác
Trên WhatsApp, sự thay đổi định danh hạ cánh lên trên một kênh vốn đã chạy theo đồng hồ. Business Platform của Meta cho bạn một cửa sổ customer-service 24 giờ: một khi một user nhắn cho bạn, bạn có 24 giờ để phản hồi ở dạng free-form, và sau đó lựa chọn outbound duy nhất của bạn là một template đã được duyệt trước, có tính phí. [7] Một tin nhắn đầu tiên từ một lead chỉ-có-username có thể đến với một BSUID, không có số điện thoại, và đồng hồ 24 giờ đó đã đang đếm ngược. Một integration không thể nhận ra, lưu, và phản hồi contact đó theo BSUID của nó thì không chỉ thiếu một mô hình dữ liệu gọn gàng. Nó có thể bỏ lỡ cửa sổ trả lời miễn phí, và mất luôn cả lead.
Vì vậy chúng tôi không coi sự sẵn sàng cho BSUID là tùy chọn, và chúng tôi không chờ đợt rollout buộc tay mình. StaffOS vốn đã chạy pattern mà bài này lập luận. Chúng tôi khóa các contact WhatsApp trên định danh nền tảng bền vững, giữ số điện thoại làm một alias nullable, capture cặp số-điện-thoại-tới-BSUID bất cứ khi nào số điện thoại hiện diện, và relink khi có sự kiện user_id_update thay vì tạo bản trùng. Với chúng tôi, một first touch chỉ-có-username là một contact bình thường ngay từ tin nhắn đầu tiên, không phải một trường hợp đặc biệt phải dựa vào logic số điện thoại. Nếu bạn đang cân một vendor WhatsApp này với vendor khác, hãy lấy phần audit ở trên làm thước đo: công việc đó lẽ ra đã xong, chứ không phải đang nằm trên roadmap.
Cần kiểm gì trước khi bạn ship
Tài liệu nền tảng là nguồn sự thật, và chúng vẫn đang được điền vào trong khi đợt rollout hướng tới người dùng tiếp diễn. Trước khi bạn viết code đối với một payload cụ thể, hãy kiểm ba thứ đối chiếu với tài liệu tham chiếu trực tiếp của Meta: hình dạng chính xác của payload thay-đổi-định-danh user_id_update, liệu BSP của bạn trao cho bạn các trường thô hay phiên bản đổi tên của riêng nó, và liệu có trường mới nào đã xuất hiện trong contacts object kể từ khi bài này được viết hay không. Bản đồ ở trên phản ánh tài liệu gốc và tài liệu partner tính đến tháng 6 năm 2026, và chúng tôi sẽ cập nhật nó khi Meta thay đổi bề mặt.
Nếu có điều gì ở đây không còn khớp với tài liệu trực tiếp, hãy báo cho chúng tôi và chúng tôi sẽ sửa. Toàn bộ vấn đề là nó vẫn kiểm chứng được.