WhatsApp contact info requests
A contact info request puts one button under a WhatsApp message that asks the recipient to share a phone number. Use it when you need a number to reach someone on, such as a callback or a booking confirmation, rather than a saved address. For a location instead, use location requests.
Send a contact info request
Set interactive.type to request_contact_info, with a body_text and nothing else. WhatsApp renders the button itself, so there is nothing to label it with:
const msg = await bird.whatsapp.send({
to: "+16505551234",
from: "+13124495648",
interactive: {
type: "request_contact_info",
body_text:
"To confirm your booking we need a number to reach you on. Tap below to share yours.",
},
});
console.log(msg.id, msg.status);msg = client.whatsapp.send(
to="+16505551234",
from_="+13124495648",
interactive={
"type": "request_contact_info",
"body_text": "To confirm your booking we need a number to reach you on. Tap below to share yours.",
},
)
print(msg.id, msg.status)package main
import (
"context"
"fmt"
"log"
"os"
bird "github.com/messagebird/bird-sdk-go"
"github.com/messagebird/bird-sdk-go/option"
)
func main() {
client, err := bird.NewClient(option.WithAPIKey(os.Getenv("BIRD_API_KEY")))
if err != nil {
log.Fatal(err)
}
msg, err := client.Whatsapp.Send(context.Background(), bird.WhatsappSendParams{
To: "+16505551234",
From: "+13124495648",
Interactive: &bird.WhatsAppInteractiveSend{
Type: "request_contact_info",
BodyText: "To confirm your booking we need a number to reach you on. Tap below to share yours.",
},
})
if err != nil {
log.Fatal(err)
}
fmt.Println(msg.Id, *msg.Status)
}$interactive = (new WhatsAppMessageSendRequestInteractive())
->setType('request_contact_info')
->setBodyText('To confirm your booking we need a number to reach you on. Tap below to share yours.');
$message = $bird->whatsapp->send(
to: '+16505551234',
from: '+13124495648',
interactive: $interactive,
);
echo $message->getId(), ' ', $message->getStatus();bird whatsapp send \
--from +13124495648 \
--interactive '{"body_text":"To confirm your booking we need a number to reach you on. Tap below to share yours.","type":"request_contact_info"}' \
--to +16505551234curl -X POST "https://{region}.platform.bird.com/v1/whatsapp/messages" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"to": "+16505551234",
"from": "+13124495648",
"interactive": {
"type": "request_contact_info",
"body_text": "To confirm your booking we need a number to reach you on. Tap below to share yours."
}
}'from is required on every service message: a number your workspace owns, not a Bird-managed one. This type names no field of its own, and the schema bars a header, a footer_text, and every other type's field (buttons, list, cta_url, cards) outright, so body_text is the whole message, capped at 1024 characters. Meta states no body-length limit for this type at all; Bird applies the 1024-character bound every other interactive type but a list menu carries.
in_reply_to_message_id still works on this type, to quote an earlier message in the same conversation. See the hub's quoting a message to correlate a reply for how resolution works and what it can miss.
Reading the shared contact
A tap does not produce an interactive_reply. It arrives as an ordinary inbound message carrying a contact_cards array:
Code example
{
"id": "wam_01kyb2m4xq7whs0d8n3prv6tez",
"direction": "inbound",
"from": { "phone_number": "+16505551234", "bsuid": "US.13491208655302741918" },
"to": { "phone_number": "+13124495648" },
"status": "received",
"contact_cards": [
{
"origin": "contact_request",
"phone_numbers": [{ "phone_number": "+14155550829", "type": "cell" }]
}
],
"created_at": "2026-08-26T10:00:00Z"
}contact_cards is an array, and a contacts message that carried no card reads back as [] rather than as an absent field. The same field carries a card you send, so a card answering this ask is told apart by origin, not by the field it arrives on. Checking origin is mandatory before treating a card as your answer. origin is contact_request when the card answers this ask, or other when the contact shared a card unprompted, which may name a third party entirely and not the contact at all. A tap carries only phone_numbers[].{phone_number, type} and omits vcard; the full contact object, with name, org, birthday, and the rest, arrives only on origin: "other". You see this reply through the message list or GET /v1/whatsapp/messages/{id}; see the hub's reading a reply for that path in full.
Correlating the answer with the question
Unlike a location request, Meta puts no context on this type's reply, so in_reply_to_message_id is omitted rather than resolved. Correlate on from plus a recent send of your own, or accept that you cannot. Two outstanding asks to the same contact are indistinguishable: nothing on the reply names which ask it answers, so a workspace that sends a second contact info request before the first is answered cannot tell which card responds to which.
This is the deliberate contrast with location requests: that type's reply carries Meta's own context, so in_reply_to_message_id resolves and the hub's quoting a message to correlate a reply mechanism links the answer back on its own. A contact info request's reply has no such mechanism to lean on.
Asking inside a template instead
The request_contact_info interactive message is the free-form counterpart of the REQUEST_CONTACT_INFO template button, which asks for the same contact card but can reach a recipient whose customer service window is closed. Use the interactive message when the recipient messaged you recently and you want the ask worded for this conversation; use the template button when the window is closed, or when the ask rides on a message you already send as a template. See WhatsApp templates for sending with a template.
Things to watch
- The customer service window has to be open. A contact info request is a service message, deliverable only inside an open window; see the hub's customer service window. The window check fails open, so a 202 is not proof the window was actually open when the send goes out.
- from must be a number your workspace owns, and the window it needs open is keyed to that number, not to your workspace as a whole.
- The reply cannot be tied to the ask by id. No context on Meta's side means in_reply_to_message_id is omitted on the reply; correlate on from plus a recent send of your own.
- A decline is silent. WhatsApp shows the recipient a share sheet, and dismissing it produces no message and no webhook at all. The absence of a contact_cards message is the only signal, so any flow that waits on an answer needs its own timeout rather than a decline event to watch for.
- No header, no footer, and no button label. The schema bars a header and footer_text on this type outright, and there is no field to label the button with. Everything the recipient reads has to be in body_text.
- The disclosed number is not guaranteed to be the one the contact chats from. Meta warns that a user's ID and phone number may not always match, so do not assume the shared number equals from.phone_number. It is also not guaranteed to be E.164: Bird normalizes it where parseable and passes it through verbatim where not.
- The reply is a contact_cards message, not an interactive_reply. An integration that only watches interactive_reply for a tap will miss this type entirely, and so will one that only watches inbound location for the other request type.
Everything the schema can express here, an over-long body_text, a header, a footer_text, or any of buttons, list, cta_url, cards, is a plain request-validation failure with no catalog code. A quote that doesn't resolve fails the request before anything is created or charged: 404 E15071 when the id names no message this workspace holds, 422 E15072 when it names one that cannot be quoted. See the hub's errors for the full interactive error table and Sending WhatsApp messages for the errors any WhatsApp send can hit.
Next steps
- WhatsApp interactive messages: what all six interactive types share
- Location requests: ask for a location instead of a phone number
- WhatsApp templates: reach a recipient whose customer service window is closed
- Sending WhatsApp messages: the request envelope, the 202 model, and safe retries
Related resources
Continue with the documentation, guides and examples for this topic. Resources are in English.
Watch the guideConnecting WhatsApp to Bird: from buying a number to a live channelUnderstand the conceptWhat is the 24-hour customer service window on WhatsApp?Use the toolWhatsApp message builderExplore the capabilityWhatsApp
Try the practice and get an implementation brief