← All posts
Tutorial

Check Whether a WhatsApp Contact Is Saved via API

To check whether a person is saved in the connected WhatsApp account’s contact list, use UnifyPort’s GET /v1/accounts/{account_id}/contacts/membership with the contact’s returned LID as contact_id. A successful response with data.is_in_contacts: false means not saved, not a failed request. This checks the connected account’s list—not whether the other person saved your number.

Key takeaways

  • Use the LID returned as conversation_id by the contact APIs; do not construct it from a phone number.
  • Keep three application outcomes: saved, not saved, and unknown.
  • Contact-list membership is separate from chat history, block status, and permission to send marketing.
  • Checking is read-only. Adding a contact must remain a separate, deliberate action.

What does the saved-contact check establish?

WhatsApp’s official contact guide says deleting a contact does not delete the chat history. A chat row is therefore not evidence that its participant is still saved. The same guide describes sharing a contact and the recipient subsequently choosing to add it or message it: sharing details and saving them are different operations.

The UnifyPort membership reference answers a narrower question: does this contact belong to this connected account’s contact list?

QuestionAppropriate evidence
Is this person saved by the connected account?Successful membership response and is_in_contacts
Has the other person saved our number?Not answered by this endpoint
Is this person blocked?Separate blocklist workflow
Does a chat exist, or did someone share a contact card?Separate conversation or message evidence
May our application contact this person?Your independently established permission and communication policy

For address-book writes versus sharing details, read Add a contact vs send a vCard. Do not call the add endpoint merely to make a membership check easier: that changes the state you intended to inspect.

Prepare the account and the returned LID

UnifyPort provides an unofficial interface for a connected messaging account; this is not a WhatsApp Cloud API endpoint. The current provider action support reference maps membership checks to whatsapp, not LINE, Telegram, Zalo, or the separate whatsapp-protocol provider.

Keep the selected account and contact together. Contact objects can expose different id, provider_user_id, and conversation_id values. For this WhatsApp operation, the documented input is the LID returned as conversation_id by contact APIs. Retain it from a legitimate existing contact workflow; never append @lid to a phone number.

If your application has only a phone number and no verified returned LID, leave the check unavailable until identity is resolved. This endpoint is not documented as an arbitrary phone-number lookup.

The following illustrative request has not been executed here. Populate the environment variables from your backend’s selected account and stored contact mapping; keep the API key off the browser:

curl --get \
  "https://api.unifyport.ai/v1/accounts/${UNIFYPORT_ACCOUNT_ID}/contacts/membership" \
  -H "X-Api-Key: ${UNIFYPORT_API_KEY}" \
  --data-urlencode "contact_id=${WHATSAPP_CONTACT_LID}"

Encoding the query preserves identifiers containing @. The successful response contains data.contact_id and the boolean data.is_in_contacts.

Render three outcomes, not one checkbox

A common application mistake is converting every falsy or missing value to “not saved.” That turns a timeout, unsupported provider, or malformed response into a false conclusion.

Use an explicit result classifier. This illustrative JavaScript interprets an already captured HTTP status and parsed JSON; it performs no network call:

function classifyMembership(httpStatus, body) {
  if (httpStatus !== 200) return 'unknown';
  const value = body?.data?.is_in_contacts;
  if (value === true) return 'saved';
  if (value === false) return 'not_saved';
  return 'unknown';
}

These strings are application labels, not API response fields. Handle connection failures and non-JSON responses as unknown before calling the classifier.

ObservationUI resultRecommended next action
200 and boolean trueSavedShow the observation time
200 and boolean falseNot savedOffer a separate authorized add action only if needed
501 unsupported_by_providerUnsupported / unknownCheck the selected provider; do not add automatically
Timeout, failed response, or missing booleanUnknownKeep diagnostics and investigate or refresh

Store observations with the account, contact LID, and your local check time. Do not share one cached result across messaging accounts. Ignore a late response if the operator has since selected a different contact, and do not present an old observation as a permanent guarantee.

Keep follow-up actions independent

A negative result is not permission to write. If the operator genuinely wants to save the person, use the separate Add contact reference, retain its returned identifiers, and check membership again when current confirmation is needed.

Likewise, “not saved” is not “blocked.” The mute versus block guide explains the independent controls. Do not unblock, send a test message, or modify the address book as a side effect of displaying membership.

For failures, retain HTTP status and request_id when available, without logging API keys or entire contact records. Application access controls should restrict who can inspect each account’s contacts.

FAQ

Can this tell whether someone saved my number?

No. It checks membership in the connected account’s contact list, not the other person’s address book.

Is is_in_contacts: false an error?

Not in a successful 200 response. It is a successful negative result. Missing data or a failed request is unknown, not false.

Can I supply a phone-number JID instead of a LID?

The documented WhatsApp input is the LID returned as conversation_id by contact APIs. Use that value, not a guessed identifier.

Does receiving a contact card prove that it was saved?

No. A contact message and an address-book operation are separate. Check membership when that distinction matters.

Next step and sources

Build the read-only control against Check contact membership. Before release, test true, false, missing data, an unsupported provider, a timeout, and a contact-selection change while a request is pending. These are proposed checks, not reported test results.

References checked on 2026-10-31:

UnifyPort API

Turn messaging integration into a stable product pipeline.

Start by sending through one API, then bring every inbound message back into your business system with standard events.