Sign inGet started

WhatsApp-contactkaarten ontvangen

contact_cards is het enige onderdeel dat hetzelfde veld in beide richtingen draagt. Een contact kan een kaart uit het adresboek delen, en een tik op een contactgegevensverzoek dat je hebt gestuurd komt hier ook aan, met het nummer dat ze hebben gekozen om vrij te geven.

Wat een inkomende contactkaart bevat

contact_cards is altijd een array, en origin geeft aan hoe de kaart is binnengekomen:
Codevoorbeeld
{
  "id": "wam_01kyg9v3timy1w7n0r4cbh9ukf",
  "direction": "inbound",
  "from": { "phone_number": "+14155550100" },
  "to": { "phone_number": "+13124495569" },
  "status": "received",
  "contact_cards": [
    {
      "origin": "contact_request",
      "phone_numbers": [{ "phone_number": "+14155550100", "type": "cell" }]
    }
  ],
  "created_at": "2026-08-25T09:27:45Z"
}
originHoe de kaart is binnengekomen
contact_requestHet contact tikte op een knop die je stuurde om hun nummer te vragen
otherHet contact deelde uit zichzelf een kaart in de chat
Controleer origin voordat je een kaart als antwoord op je verzoek behandelt. Het is het enige signaal dat de twee onderscheidt, en een kaart die uit zichzelf is gedeeld kan volledig een derde partij benoemen in plaats van het contact. De waardenlijst is open, dus behandel een waarde die je niet herkent als een andere manier van delen die sindsdien is toegevoegd.
Een kaart die deze werkruimte heeft gestuurd, wordt teruggelezen zonder origin, en zo onderscheid je een uitgaande kaart van een inkomende op hetzelfde veld.

Wat een tik bevat, en wat een gedeelde kaart bevat

De twee komen binnen met verschillende hoeveelheden detail, en niets op een kaart is verplicht: WhatsApp stuurt de onderdelen die de kaart bevat en laat de rest weg, dus een kaart met alleen een origin komt gewoon binnen in plaats van te worden weggegooid.
VeldBij een knoptikBij een kaart gedeeld in de chat
phone_numbers[].phone_number, typeHet nummer dat het contact koos om vrij te gevenDe nummers die de kaart bevat
vcardWeggelaten; een tik bevat alleen het nummerDe kaart in vCard-formaat
name, org, birthday, emails, urls, addressesWat WhatsApp stuurt, wat meestal niets isAanwezig wanneer de kaart ze bevat
Codevoorbeeld
{
  "contact_cards": [
    {
      "origin": "other",
      "vcard": "BEGIN:VCARD\nVERSION:3.0\nN:Johnson;Barbara;;;\nTEL;type=CELL:+16505551234\nEND:VCARD\n",
      "name": {
        "formatted_name": "Barbara J. Johnson",
        "first_name": "Barbara",
        "last_name": "Johnson"
      },
      "org": { "company": "Northside Plumbing" },
      "phone_numbers": [{ "phone_number": "+16505551234", "type": "cell" }]
    }
  ]
}
Twee velden vragen aandacht bij het parsen. phone_number is genormaliseerd naar E.164 waar het geparsed kan worden, en wordt exact doorgegeven zoals het apparaat van het contact het opsloeg waar dat niet kan, inclusief een extensie, dus parse defensief in plaats van E.164 aan te nemen. birthday komt ongevalideerd van dat apparaat en wordt als tekst in YYYY-MM-DD-vorm doorgegeven in plaats van als datum getypeerd, dus neem niet aan dat het parsbaar is. Een type-label op een ontvangen kaart is in kleine letters, en WhatsApp definieert er geen vocabulaire voor, dus match het hoofdletterongevoelig in plaats van te switchen op CELL.

Het telefoonnummer dat een contact vrijgeeft

Een contact dat een WhatsApp-gebruikersnaam heeft aangenomen bereikt je via een bedrijfsgebonden gebruikers-ID zonder telefoonnummer op from. Een contactgegevensverzoek is hoe je om het nummer vraagt, en dit onderdeel is waar het antwoord binnenkomt, met origin: "contact_request" en het nummer in phone_numbers.
Het nummer dat ze vrijgeven is niet gegarandeerd het nummer waarmee ze chatten: Meta waarschuwt dat de identifier en het telefoonnummer van een gebruiker niet altijd overeen hoeven te komen, dus sla het vrijgegeven nummer op als een eigen gegeven in plaats van de identiteit op from te overschrijven.

De webhook-payload

whatsapp.received draagt de contact_cards-array op de event-envelope:
Codevoorbeeld
{
  "type": "whatsapp.received",
  "timestamp": "2026-08-25T09:27:45.019Z",
  "data": {
    "whatsapp_id": "wam_01kyg9v3timy1w7n0r4cbh9ukf",
    "workspace_id": "ws_01ky7m235keycbnwyajabe1a6b",
    "direction": "inbound",
    "from": { "phone_number": "+14155550100", "bsuid": "US.13491208655302741918" },
    "to": { "phone_number": "+13124495569" },
    "contact_cards": [
      {
        "origin": "contact_request",
        "phone_numbers": [{ "phone_number": "+14155550100", "type": "cell" }]
      }
    ],
    "tags": null,
    "metadata": null
  }
}

Aandachtspunten

  • Een afgewezen verzoek levert niets op. WhatsApp toont het contact een deelvenster, en het sluiten ervan stuurt geen bericht en activeert geen webhook, dus een flow die op een nummer wacht heeft een eigen timeout nodig in plaats van een afwijzingsevent.
  • Twee openstaande verzoeken zijn niet te onderscheiden. Een kaart als antwoord op een contactgegevensverzoek bevat geen in_reply_to_message_id, dus een tweede verzoek dat is gestuurd voordat het eerste is beantwoord kan niet aan zijn eigen antwoord worden gekoppeld.
  • De array kan meerdere kaarten bevatten. Een contact dat meerdere kaarten in één bericht deelt vult meerdere items, elk met een eigen origin.
  • Een kaart is contactdata die je niet hebt verzameld. Het kan de naam, nummers en geboortedatum van een derde partij bevatten, dus pas dezelfde bewaar- en toestemmingsregels toe als bij alle andere persoonsgegevens voordat je het opslaat.

Volgende stappen