AnmeldenKostenlose Testphase starten
Meta Tech Provider

WhatsApp aus PHP und Laravel senden und empfangen

Der Empfang ist eine Laravel-Route, die Metas Verifizierungs-GET beantwortet und POSTs annimmt. Die Parameter lesen Sie als hub_mode, hub_verify_token und hub_challenge, weil PHP Punkte in Unterstriche umwandelt. Das Senden ist ein einziger POST mit Http::withToken() an den messages-Endpoint der Cloud API, mit der Phone-Number-ID und dem Token der Nummer. Ein SDK ist nicht nötig.

hub_challenge

PHP wandelt Punkte in den Namen eingehender Variablen in Unterstriche um, daher wird hub.challenge als hub_challenge gelesen.

routes/api.php

Die zustandslosen API-Routen von Laravel, angelegt mit install:api, werden unter /api ausgeliefert und liegen außerhalb des CSRF-Schutzes der Web-Gruppe.

v25.0

Die Graph-API-Version aus Metas aktuellen Beispielen zum Senden von Nachrichten, unter POST /{phone-number-id}/messages.

Wie empfangen Sie WhatsApp-Nachrichten in Laravel?

Mit einem GET und einem POST auf demselben Pfad in routes/api.php. Führen Sie zuerst php artisan install:api aus, falls die Datei nicht existiert. API-Routen sind zustandslos und liegen außerhalb der Web-Gruppe. Deshalb weist Laravel Metas POST nicht wegen eines fehlenden CSRF-Tokens ab, was bei einer Route in routes/web.php passiert.

Der GET beantwortet Metas Verifizierung. Meta sendet hub.mode, hub.verify_token und hub.challenge, doch PHP schreibt Punkte in Namen eingehender Variablen zu Unterstrichen um, sodass Laravel hub_mode, hub_verify_token und hub_challenge sieht. Code, der die Namen mit Punkt liest, erhält null und verifiziert nie. Geben Sie die Challenge als reinen Text zurück, nicht über response()->json().

Der POST übergibt die Payload an einen Job in der Queue und antwortet sofort mit 200. Legen Sie einen langen, zufälligen Schlüssel in den Pfad und prüfen Sie ihn auf beiden Routen: Meta signiert Zustellungen mit dem App-Secret des Tech Providers, daher können Sie den Signatur-Header auf Ihrer Seite nicht validieren.

routes/api.php: verification and event intake
use App\Jobs\HandleWhatsAppEvent;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

Route::get('/whatsapp/{key}', function (Request $request, string $key) {
    abort_unless(hash_equals(config('services.whatsapp.url_key'), $key), 404);

    // PHP turns hub.mode into hub_mode: read the underscored names
    if ($request->query('hub_mode') === 'subscribe'
        && hash_equals(config('services.whatsapp.verify_token'),
                       (string) $request->query('hub_verify_token'))) {
        return response((string) $request->query('hub_challenge'), 200)
            ->header('Content-Type', 'text/plain');
    }

    abort(403);
});

Route::post('/whatsapp/{key}', function (Request $request, string $key) {
    abort_unless(hash_equals(config('services.whatsapp.url_key'), $key), 404);

    HandleWhatsAppEvent::dispatch($request->json()->all());

    return response('', 200);
});

Wie senden Sie eine WhatsApp-Nachricht aus Laravel?

Mit dem HTTP-Client von Laravel: ein POST an den messages-Endpoint der Phone-Number-ID, mit dem Zugriffstoken als Bearer-Token. Beide Werte stammen aus der Verbindung, werden im Dashboard angezeigt und von get_api_credentials zurückgegeben. Sie gehören in config/services.php, gespeist aus Umgebungsvariablen, und nicht in den Code.

Die Form des Bodys hängt vom Zeitpunkt ab. Innerhalb von 24 Stunden nach der letzten Nachricht des Kunden funktioniert ein text-Objekt, wie unten gezeigt. Außerhalb dieses Fensters akzeptiert Meta nur ein template-Objekt, das ein freigegebenes Template und seine Sprache nennt, und Freitext scheitert mit dem Fehler 131047. Die Antwort zeigt es Ihnen: Ein fehlgeschlagener Aufruf liefert ein error-Objekt, dessen code sagt, was schiefging. Protokollieren Sie es, statt es zu verwerfen.

Nichts an der Anfrage ist spezifisch für EasyCoexistence. Es ist der Aufruf aus Metas eigener Dokumentation, daher funktioniert jeder PHP-HTTP-Client, Guzzle oder reines cURL, auf dieselbe Weise.

Send a text reply inside the 24 hour window
use Illuminate\Support\Facades\Http;

$response = Http::withToken(config('services.whatsapp.token'))
    ->post('https://graph.facebook.com/v25.0/'
        . config('services.whatsapp.phone_number_id') . '/messages', [
        'messaging_product' => 'whatsapp',
        'to' => '14155550188', // digits only, with country code
        'type' => 'text',
        'text' => ['body' => 'Thanks, we are on it.'],
    ]);

if ($response->failed()) {
    // error.code 131047: outside the window, send a template instead
    logger()->warning('WhatsApp send failed', $response->json('error', []));
}

Was braucht ein produktiver Laravel-Handler darüber hinaus?

Eine echte Queue, Deduplizierung und eine Fensterprüfung.

Die Queue ist wichtig, weil Meta bei einer langsamen Antwort erneut zustellt. HandleWhatsAppEvent::dispatch() kehrt nur dann schnell zurück, wenn die Queue-Verbindung eine echte ist und ein Worker läuft. Beim sync-Treiber läuft der Job innerhalb der Anfrage, und ein langsamer Modellaufruf oder Datenbankzugriff führt zu einer doppelten Zustellung.

Dedupliziert wird über die Nachrichten-ID, die wamid in jeder Nachricht, denn Wiederholungen sind der Normalfall und keine Ausnahme. Ein eindeutiger Index auf dieser Spalte oder ein Cache-Lock mit ihr als Schlüssel genügt.

Speichern Sie außerdem, wann jeder Kontakt zuletzt geschrieben hat. Mit diesem Zeitstempel wählt der Sendepfad selbst zwischen Text und Template, statt erst über den Fehler 131047 zu erfahren, dass der Kunde schon wartet. Antworten, die am Telefon in der WhatsApp Business App getippt werden, kommen als echo-Events auf derselben Route an. So erkennt der Handler auch, wann eine Person eine Unterhaltung übernommen hat.

Häufige Fehler

  • hub.challenge mit Punkt lesen. PHP hat es in hub_challenge umbenannt, der Handler gibt einen leeren Body zurück und Meta verifiziert nie.
  • Den Webhook in routes/web.php anlegen. Metas POST hat kein CSRF-Token und wird mit 419 abgewiesen.
  • An die sync-Queue übergeben. Der Job läuft vor dem 200, langsame Verarbeitung wird erneut zugestellt und Nachrichten werden doppelt verarbeitet.
  • Die Challenge mit response()->json() zurückgeben. Die Anführungszeichen um den Wert lassen Metas Prüfung scheitern.
Mit EasyCoexistence

Verbinden Sie die Nummer auf easycoexistence.com, setzen Sie das Ziel des Webhooks auf Ihre Laravel-Route mit ihrem Schlüssel im Pfad und lesen Sie Phone-Number-ID und Token im Dashboard ab. Ab US$ 9 pro Nummer und Monat, sinkend auf US$ 1, je mehr Nummern Sie hinzufügen, die ersten 3 Tage kostenlos.

Häufig gestellte Fragen

Gibt es ein PHP-SDK?

Von uns nicht, und es ist auch nicht nötig. Die API gehört Meta und wird von Meta dokumentiert, und der HTTP-Client von Laravel oder Guzzle erreicht sie direkt.

Funktioniert das auch ohne Laravel?

Ja. In reinem PHP lesen Sie $_GET['hub_challenge'], geben es als text/plain aus und senden mit cURL. Die Regel mit den Unterstrichen gilt für jedes PHP-Framework.

Warum braucht die URL einen Schlüssel im Pfad?

Weil er die Authentifizierung ist, die tatsächlich funktioniert. Metas Signatur nutzt das App-Secret des Tech Providers, das nie weitergegeben wird. Das Geheimnis in der URL verhindert, dass Fremde gefälschte Events senden.

Kann das Team weiter das Telefon nutzen?

Ja. Coexistence hält die WhatsApp Business App auf der Nummer funktionsfähig, und am Telefon gesendete Nachrichten erreichen Ihre Route als echo-Events.

Weiterlesen

Bereit für den Start?

Richten Sie WhatsApp Coexistence in wenigen Minuten statt Monaten ein. Die App funktioniert weiterhin auf dem Telefon.

Kostenlose Testphase starten

Verifiziert am

WhatsApp aus PHP und Laravel senden