Dentolize · Hidden-Number WhatsApp Contacts Walkthrough
On this pageData model note

Glossary

BSUID (business-scoped user ID) — WhatsApp/Meta's term for an identifier that stands in for a contact's phone number when that number is hidden from a specific WhatsApp Business Account. Looks like EG.1693676845194969 (two letters, a dot, then digits). It only identifies the contact to this WABA — it is not a phone number and cannot be dialed, texted outside the existing conversation, or used to look up a patient record. Stored on OnlineConversation.bsuid.

Username privacy (WhatsApp) — a WhatsApp setting that hides a user's phone number from a business they haven't recently exchanged a message or call with (per the code's comment: no exchange in the last 30 days, and not in the business's contact book). When active, Meta's webhook sends a BSUID instead of the contact's wa_id (phone number).

wa_id — the field in Meta's webhook contacts[] payload that normally carries a contact's phone number. Omitted when username privacy applies to that contact; user_id (a BSUID) is sent in its place. See Receiving & Replying to Messages.

user_id / from_user_id — the two webhook fields that can carry a BSUID: contacts[0].user_id and messages[0].from_user_id. Dentolize reads either, treating them as the same value.

to vs recipient — the two mutually exclusive fields WhatsApp's Cloud API accepts for addressing an outbound message: to for a phone number, recipient for a BSUID. Sending a BSUID-addressed reply with to fails to deliver.

getConversationHandle — the shared UI helper (separately implemented in clinic-web and clinic-mobile) that picks what to display for a conversation's address: the phone number if there is one, else @username, else the raw BSUID.

conversationKey / waRecipient / isBsuid (server) — small helpers in packages/server/.../official-whats-app.utils.js used by the main GraphQL server to build a Prisma unique-key lookup or a Graph API address from whichever identifier is on hand. isBsuid here is a regex heuristic on the identifier's shape, distinct from the same-named boolean computed in whatsapp-official. See Identifying a Contact.

findConversationByAddress / backfill — the matching function in whatsapp-official that looks up a conversation by phone and/or BSUID and returns whether it's safe to write a newly-learned address onto the matched row (backfill: true) or whether the phone and BSUID lookups disagree and nothing should be written (backfill: false). See Identifying a Contact.

Data model note

OnlineConversation (packages/prisma/schema.prisma:4095) is the row-per-contact conversation record for Dentolize's official WhatsApp integration (distinct from the legacy/unofficial whatsapp package, which this PR does not touch). Relevant fields after this PR:

FieldTypeNotes
phoneString?Nullable as of this PR. Unique per companyId.
bsuidString?New in this PR. Unique per companyId.
usernameString?New in this PR. Not unique — a display convenience only.
patientIdString?Links to a Patient, which only ever stores a phone number — never a BSUID.
leadIdString?Links to a Lead, auto-created only when the conversation has a phone number.

A conversation can have phone and bsuid both set (the common steady state once a number is learned), just bsuid (a contact never seen by phone), or — for conversations predating this migration in a conflicting-data scenario — two separate rows that each have one but not the other, not automatically merged by this PR.