Novo O Safe Mode aquece números novos para reduzir o risco de banimento no WhatsApp. Saiba mais →

Maytapi/Blog/Features

WhatsApp Username API: Resolve, Message and Set @handles

Resolve WhatsApp usernames to contacts, send messages to @handles, handle key-protected usernames and hidden numbers, and set your own username.

Features Updated Oct 27, 2026·7 min read

WhatsApp Username API: Resolve, Message and Set @handles

WhatsApp is adding usernames: a unique handle like @john_doe that people can share instead of their phone number. For a business that changes two things. Customers may start giving you a handle on a signup form or in a support chat instead of a number, and some of them will never show you their number at all. This guide shows how to work with WhatsApp usernames through the Maytapi API: resolve a username to a contact, look up the username behind a phone number, send a message straight to @handle, deal with key-protected usernames, and read or set the username of your own connected number.

What WhatsApp usernames are

A WhatsApp username is a unique handle attached to an account. It is not the display name (the "pushname" people see at the top of a chat) and it is not the business name. One account has at most one username, and other people can start a chat with that handle without knowing the phone number behind it.

Two details matter for an integration:

  • Rollout. WhatsApp is rolling usernames out gradually, as its username announcement and help article explain. Many accounts don't have one yet, and some can't set one yet. Treat the username as an optional field and keep the phone number or chat id as your primary key.
  • Username key. A user can protect their username with a 4-digit key. Someone who doesn't already chat with them needs both the handle and the key to reach them. The key is the user's own setting; you receive it from them, you can't look it up.

Maytapi exposes usernames on these endpoints:

Task Endpoint Body or parameter
Username to contact GET /getContacts/usernameToPhone/{username} john_doe or john_doe:1234
Phone number to username GET /getContacts/phoneToUsername/{number} 55119xxxxxx67
Send to a username POST /sendMessage to_number: @john_doe or @john_doe:1234
Read your own username GET /getProfileUsername
Set your own username POST /setProfileUsername username

All of them live under https://api.maytapi.com/api/PRODUCT_ID/PHONE_ID/ and use your token in the x-maytapi-key header. If you haven't connected a phone yet, start with the getting started guide.

Resolve a username to a contact

usernameToPhone takes a handle without the @ and tells you who it belongs to. It's a lookup only: it doesn't open a chat or send anything.

Terminal
curl "https://api.maytapi.com/api/$PRODUCT_ID/$PHONE_ID/getContacts/usernameToPhone/john_doe" \
  -H "x-maytapi-key: $TOKEN"

When WhatsApp shares the phone number with your account, you get the full identity:

JSON
{
  "success": true,
  "data": {
    "id": "55119xxxxxx67@c.us",
    "name": "John Doe",
    "phone": "55119xxxxxx67",
    "lid": "123456789012345@lid",
    "username": "john_doe",
    "keyRequired": false
  }
}

id is the chat id you can use anywhere else in the API, phone is the number, and lid is the person's WhatsApp privacy id. Handles are matched in lowercase, so John_Doe and john_doe resolve to the same account.

There are three other outcomes, and your code should handle each one:

Result What you get What it means
Number hidden id and lid are the @lid id, phone is null The account exists, but WhatsApp doesn't reveal the number to you
Key required data holds only username and keyRequired: true The username is key-protected and the key is missing or wrong
Not found success: false No account uses this username

A key-protected username is not an error. The request succeeds and tells you a key is needed. Put the key after a colon in the same path segment and call again:

Terminal
curl "https://api.maytapi.com/api/$PRODUCT_ID/$PHONE_ID/getContacts/usernameToPhone/john_doe:1234" \
  -H "x-maytapi-key: $TOKEN"

With the right key you get the identity as above. With a wrong key you get keyRequired: true again. The colon format is the same one sendMessage uses, which keeps both calls consistent.

When the phone number is hidden

Usernames exist so people can talk without sharing their number, so a hidden number is a normal result, not a failure:

JSON
{
  "success": true,
  "data": {
    "id": "123456789012345@lid",
    "name": "John Doe",
    "phone": null,
    "lid": "123456789012345@lid",
    "username": "john_doe",
    "keyRequired": false
  }
}

You can still message this person. Use the @lid id or the username as the recipient. What you can't do is match them against a phone-number column in your CRM. Store them under the lid (and the username as a label), not under an empty phone. If WhatsApp shares the number later, for example after the person writes to you, the LID to phone number guide shows how to resolve a @lid id with lidToPhone and merge the records.

Flow for resolving a WhatsApp username: call usernameToPhone, retry with the key if keyRequired is true, then store by phone or by lid when phone is null

Send a message to a WhatsApp username

You don't have to resolve a username before messaging it. Pass the handle as to_number and Maytapi resolves it when the message is sent. The @ at the start is required. Without it the value is treated as a phone number.

Terminal
curl -X POST "https://api.maytapi.com/api/$PRODUCT_ID/$PHONE_ID/sendMessage" \
  -H "x-maytapi-key: $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "to_number": "@john_doe",
    "type": "text",
    "message": "Hi John, your order is ready for pickup."
  }'

For a key-protected username, add the key after a colon:

JSON
{
  "to_number": "@john_doe:1234",
  "type": "text",
  "message": "Hi John, your order is ready for pickup."
}

You only need the key for the first message from your number. Once a chat exists, WhatsApp lets your number reach that username without it. Everything else in the request works as usual, so media and the other message types from the send message guide take a username recipient too.

What the response and webhooks contain

sendMessage queues the message and answers right away, before the username is resolved. Because of that, chatId in the response is exactly the to_number you sent:

JSON
{
  "success": true,
  "data": {
    "chatId": "@john_doe:1234",
    "msgId": "b2c1f0e0-a4d2-11f0-9c41-3b2f5d7e8a10"
  }
}

Two consequences. First, don't use this chatId as the contact key in your database. Use msgId to follow the message, and take the real chat id from the ack webhook: its chatId is 55119xxxxxx67@c.us when your account knows the number, otherwise the @lid id. Second, if you sent a key, it's echoed in the response, so keep it out of logs you share.

If the username can't be used, the message fails and your webhook receives a type: "error" event with the original request in data:

Code Cause
UN5 The username is key-protected and the key is missing or wrong
E01 No account uses this username

Neither is retried, so fix the input and send again. If you want to fail fast in a form or chatbot, call usernameToPhone first and only queue the message once keyRequired is false. The webhook events guide has the full ack and error payloads.

Find the username behind a phone number

phoneToUsername goes the other way. Pass a number with country code and no special characters:

Terminal
curl "https://api.maytapi.com/api/$PRODUCT_ID/$PHONE_ID/getContacts/phoneToUsername/55119xxxxxx67" \
  -H "x-maytapi-key: $TOKEN"
JSON
{
  "success": true,
  "data": {
    "id": "55119xxxxxx67@c.us",
    "name": "John Doe",
    "phone": "55119xxxxxx67",
    "lid": "123456789012345@lid",
    "username": "john_doe"
  }
}

When the person has no username, the call still succeeds and username is null. That's the common case during the rollout. success: false means the number itself couldn't be resolved. If you're checking a whole list of numbers, filter it with checkPhones first as shown in bulk WhatsApp number check, then look up usernames only for numbers that are on WhatsApp.

You often don't need a separate call. Incoming message webhooks include user.username when the sender has a username your number knows about, and getContacts entries carry a username field under the same rule. In both places the field is simply missing when there's no username, so check for it rather than expecting null.

Note: Look up usernames only for people who gave you the handle or already chat with you. Running large lists of guessed handles through usernameToPhone is enumeration: it exposes people who chose not to share their number, and bulk lookups from one number are the kind of activity that gets it restricted.

Read and set your own username

Your connected number can have a username too, which lets customers find your business by handle. Read it with:

Terminal
curl "https://api.maytapi.com/api/$PRODUCT_ID/$PHONE_ID/getProfileUsername" \
  -H "x-maytapi-key: $TOKEN"
JSON
{
  "success": true,
  "data": { "username": "mybusiness_01", "state": "RESERVED", "pin": null }
}

state is ACTIVE or RESERVED, and null together with username: null when no username is set. pin is the username key when WhatsApp returns one for your account; it's usually null.

To set or change it, send the new handle:

Terminal
curl -X POST "https://api.maytapi.com/api/$PRODUCT_ID/$PHONE_ID/setProfileUsername" \
  -H "x-maytapi-key: $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "username": "mybusiness_01" }'

The username must be 3 to 35 characters long, use only letters, digits, underscore and dot, and contain at least one letter. WhatsApp also checks that it's available. On success the response has the same shape as getProfileUsername. On failure success is false with a code:

Code Cause
UN1 username is empty or null
UN2 The value breaks the format rules
UN3 WhatsApp refused the change, for example because the name is taken or your account can't use usernames yet

username is the only body field. The endpoint doesn't set a username key and it doesn't remove a username; sending null or an empty string returns UN1. Manage the key and removal from the WhatsApp app on the phone.

Checklist for handling WhatsApp usernames in an integration: optional field, @ prefix to send, colon for the key, store by lid when phone is null, real chat id from ack webhook

Example: accept WhatsApp usernames on a signup form

Here is a small Node.js handler for a form field that accepts either a phone number or a @handle. It resolves the handle, asks for the key when needed, and stores the contact under the best id available.

JavaScript
const base = `https://api.maytapi.com/api/${PRODUCT_ID}/${PHONE_ID}`;
const headers = { "x-maytapi-key": TOKEN, "Content-Type": "application/json" };

async function resolveRecipient(input, key) {
  const value = input.trim();
  if (!value.startsWith("@")) return { to_number: value }; // phone number

  const handle = value.slice(1) + (key ? `:${key}` : "");
  const res = await fetch(
    `${base}/getContacts/usernameToPhone/${encodeURIComponent(handle)}`,
    { headers }
  ).then((r) => r.json());

  if (!res.success) return { error: "No WhatsApp account uses this username." };
  if (res.data.keyRequired) return { needKey: true };

  return {
    to_number: res.data.id,             // @c.us, or @lid when the number is hidden
    phone: res.data.phone,              // null when hidden
    lid: res.data.lid,
    username: res.data.username,
  };
}

async function welcome(input, key) {
  const r = await resolveRecipient(input, key);
  if (r.error || r.needKey) return r;   // show an error or a "username key" field

  await saveContact(r);                 // key by phone if present, else by lid
  await fetch(`${base}/sendMessage`, {
    method: "POST",
    headers,
    body: JSON.stringify({ to_number: r.to_number, type: "text", message: "Welcome! Reply 1 to confirm your signup." }),
  });
  return { ok: true };
}

Sending to the resolved id instead of the handle means the response chatId is already a real chat id, and you never store the key. Asking for a typed reply ("Reply 1 to confirm") keeps the confirmation step simple, and the interactive messages guide covers list messages if you want something richer.

Next steps

Usernames are a new, optional way to reach people on WhatsApp. Treat them as an extra field, resolve them with usernameToPhone, send with an @ prefix, and store contacts by lid when the number stays hidden.

Published Oct 23, 2026 · Updated Oct 27, 2026 ← All posts
Comece a usar a API do WhatsApp

Pegue sua chave e envie a primeira mensagem em dez minutos

Sem aprovação, sem templates, sem cartão. Todos os endpoints liberados por três dias.