Sign inGet started

WhatsApp-Kontaktkarten empfangen

contact_cards ist der einzige Arm, der dasselbe Feld in beide Richtungen trägt. Ein Kontakt kann eine Karte aus seinem Adressbuch teilen, und ein Tippen auf eine Kontaktinfo-Anfrage, die Sie gesendet haben, kommt ebenfalls hier an – mit der Nummer, die der Kontakt preisgeben wollte.

Was eine eingehende Kontaktkarte enthält

contact_cards ist immer ein Array, und origin gibt an, wie die Karte eingetroffen ist:
Codebeispiel
{
  "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"
}
originWie die Karte eingetroffen ist
contact_requestDer Kontakt hat auf einen Button getippt, den Sie gesendet haben, um nach seiner Nummer zu fragen
otherDer Kontakt hat unaufgefordert eine Karte im Chat geteilt
Prüfen Sie origin, bevor Sie eine Karte als Antwort auf Ihre Anfrage behandeln. Es ist das einzige Signal, das die beiden Fälle unterscheidet, und eine unaufgefordert geteilte Karte kann eine völlig andere Person benennen. Die Werteliste ist offen – behandeln Sie einen unbekannten Wert als eine weitere, nachträglich hinzugefügte Art des Teilens.
Eine Karte, die dieser Workspace gesendet hat, wird ohne origin zurückgelesen. So lässt sich eine ausgehende Karte von einer eingehenden auf demselben Feld unterscheiden.

Was ein Tippen liefert und was eine geteilte Karte liefert

Die beiden kommen mit unterschiedlich vielen Details an, und kein Feld einer Karte ist Pflicht: WhatsApp sendet die Teile, die die Karte enthält, und lässt den Rest weg. Eine Karte, die nur eine origin enthält, kommt also trotzdem an, statt verworfen zu werden.
FeldBei einem Button-TippenBei einer im Chat geteilten Karte
phone_numbers[].phone_number, typeDie Nummer, die der Kontakt preisgegeben hatDie Nummern, die die Karte enthält
vcardFehlt; ein Tippen liefert nur die NummerDie Karte im vCard-Format
name, org, birthday, emails, urls, addressesWas WhatsApp sendet, in der Regel nichtsVorhanden, wenn die Karte sie enthält
Codebeispiel
{
  "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" }]
    }
  ]
}
Zwei Felder erfordern beim Parsen besondere Sorgfalt. phone_number wird nach E.164 normalisiert, wo es geparst werden kann, und exakt so durchgereicht, wie das Gerät des Kontakts es gespeichert hat, wo es nicht geparst werden kann – eine Durchwahl gehört dazu. Parsen Sie also defensiv, statt E.164 vorauszusetzen. birthday kommt unvalidiert vom Gerät und wird als Text in YYYY-MM-DD-Form durchgereicht, nicht als Datum typisiert – gehen Sie also nicht davon aus, dass es sich parsen lässt. Ein type-Label auf einer empfangenen Karte ist kleingeschrieben, und WhatsApp definiert kein Vokabular dafür. Gleichen Sie es daher ohne Berücksichtigung der Groß-/Kleinschreibung ab, statt auf CELL zu matchen.

Die Telefonnummer, die ein Kontakt preisgibt

Ein Kontakt, der einen WhatsApp-Nutzernamen angenommen hat, erreicht Sie über eine geschäftsbezogene Benutzer-ID ohne Telefonnummer auf from. Eine Kontaktinfo-Anfrage ist der Weg, nach der Nummer zu fragen, und dieser Arm ist der Ort, an dem die Antwort eintrifft – mit origin: "contact_request" und der Nummer in phone_numbers.
Die preisgegebene Nummer ist nicht garantiert die Nummer, von der aus der Kontakt chattet: Meta weist darauf hin, dass Kennung und Telefonnummer eines Nutzers nicht immer übereinstimmen müssen. Speichern Sie die preisgegebene Nummer daher als eigenständigen Fakt, statt die Identität auf from zu überschreiben.

Der Webhook-Payload

whatsapp.received trägt das contact_cards-Array auf dem Event-Envelope:
Codebeispiel
{
  "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
  }
}

Worauf Sie achten sollten

  • Eine abgelehnte Anfrage erzeugt nichts. WhatsApp zeigt dem Kontakt ein Freigabeblatt, und wenn er es schließt, wird keine Nachricht gesendet und kein Webhook ausgelöst. Ein Flow, der auf eine Nummer wartet, braucht daher einen eigenen Timeout statt eines Ablehnungsereignisses.
  • Zwei offene Anfragen sind nicht unterscheidbar. Eine Karte als Antwort auf eine Kontaktinfo-Anfrage enthält keine in_reply_to_message_id. Eine zweite Anfrage, die vor Beantwortung der ersten gesendet wird, lässt sich daher nicht ihrer eigenen Antwort zuordnen.
  • Das Array kann mehrere Karten enthalten. Teilt ein Kontakt mehrere Karten in einer Nachricht, füllt das mehrere Einträge, jeder mit eigenem origin.
  • Eine Karte enthält Kontaktdaten, die Sie nicht selbst erhoben haben. Sie kann Name, Nummern und Geburtstag einer dritten Person enthalten. Wenden Sie daher dieselben Aufbewahrungs- und Einwilligungsregeln an wie bei allen anderen personenbezogenen Daten, bevor Sie sie speichern.

Nächste Schritte