
🤖 Viber-Chatbot in PHP: Strukturierte Nachrichten mit Tastaturmenüs senden
Der Nutzer drückt im Chat eine Taste und erhält kein bloßes Textfeld, sondern ein Raster aus Bildern, Links und farbigen Schaltflächen. Es wirkt wie eine native App. In Wirklichkeit ist es schlichtes JSON, das Ihr PHP-Skript über die Viber REST API zurücksendet.
Das Problem der meisten Tutorials: Sie lehren, auf Text mit Text zu antworten. Ein echter Business-Bot muss ein Tastaturmenü mit Link-Buttons, Bildern und Karussells anzeigen. Andernfalls versteht der Nutzer schlicht nicht, was der Bot leisten kann, und springt ab. Seit Februar 2024 hat Viber die Bot-Erstellung auf eine kommerzielle Basis gestellt (100 € pro Monat über offizielle Rakuten-Viber-Partner), und die Authentifizierung erfolgt nun über den HTTP-Header X-Viber-Auth-Token statt im Request-Body. Code-Schnipsel mit auth_token im JSON funktionieren nicht mehr.
Hier ist ein funktionierender Viber-Bot in PHP von Grund auf: vom Einrichten des Webhooks bis zum Versand eines strukturierten Tastaturmenüs mit Antwort- und URL-Buttons. Der Code ist aktuell für API-Version 7.3.
💡 Kurzüberblick:
- Registrieren Sie einen kommerziellen Bot über einen Viber-Partner und beziehen Sie ein Authentifizierungs-Token
- Konfigurieren Sie den Webhook via
set_webhookmit demX-Viber-Auth-Token-Header - Empfangen Sie Callback-Ereignisse von Viber: Webhook → subscribed → message
- Bauen Sie ein Tastaturmenü (ein Button-Raster mit benutzerdefinierten Farben, Größen und Aktionen)
- Senden Sie eine strukturierte Antwort: Text, Bilder, Links, Karussells via
send_message
So funktioniert die Viber Bot API
Die Viber Bot API arbeitet nach einem REST-Modell: Ihr Server empfängt Callback-Anfragen auf dem Webhook und antwortet durch Aufruf von https://chatapi.viber.com/pa/send_message. Jede Anfrage wird mit einem Token im X-Viber-Auth-Token-Header authentifiziert.
Der grundlegende Zyklus sieht so aus:
- Sie registrieren einen Bot über einen Viber-Partner und erhalten ein Token im Bereich „Edit Info".
- Sie konfigurieren einen Webhook (die URL Ihres Servers mit gültigem SSL; Let's Encrypt funktioniert, da es in Vipers Liste vertrauenswürdiger Java-Zertifikate enthalten ist; selbstsignierte Zertifikate werden nicht akzeptiert).
- Viber sendet bei jedem Ereignis POST-Anfragen an diese URL: Ein Nutzer hat abonniert, eine Nachricht gesendet, eine Taste gedrückt.
- Ihr PHP-Skript liest das eingehende JSON, parst das Feld
eventund antwortet durch Aufruf vonsend_message.
Der erste Schritt zum Verständnis ist ein Blick auf einen Live-Bot. Öffnen Sie Viber und suchen Sie nach dem öffentlichen Konto einer beliebigen bekannten Marke. Fast jedes hat einen Chatbot mit einem Menü. Der Screenshot unten zeigt ein typisches Suchergebnis für ein öffentliches Konto.

Nach dem Abonnieren gelangen Sie in einen Eins-zu-eins-Chat. Das sieht ungefähr so aus: ein Avatar, eine Willkommensnachricht und eine Schaltfläche zum Starten der Konversation.

Tippen Sie auf das Nachrichtensymbol oben rechts und senden Sie „Hallo". Wenn der Bot mit einem Tastaturmenü konfiguriert ist, sehen Sie eine Antwort mit einem Button-Raster:

Das ist eine strukturierte Nachricht. Es gibt zwei Button-Typen: reply sendet Text an den Bot zurück (beim Drücken von „News" oder „Artikel"), während open-url einen Link im Browser öffnet. Schreiben wir nun den Code, der dies erzeugt.
Schritt 1: Token beziehen und Webhook konfigurieren
Das Token befindet sich im Viber-Admin-Panel: Bereich „Edit Info" → Feld „App Key". Es ist eine Zeichenfolge aus Buchstaben und Ziffern, die Sie in jede API-Anfrage einbinden.
Der Webhook wird mit einer einzigen POST-Anfrage an https://chatapi.viber.com/pa/set_webhook gesetzt. Der Request-Body ist JSON mit der URL Ihres Handlers und einer Liste der Ereignisse, die Sie abonnieren. Der Header ist X-Viber-Auth-Token mit Ihrem Token.
Skript für die Webhook-Einrichtung (speichern Sie es als setup.php und führen Sie es einmal aus):
1 <?php 2 $token = 'ВАШ_X_VIBER_AUTH_TOKEN'; 3 4 $data = json_encode([ 5 'url' => 'https://your-domain.com/webhook.php', 6 'event_types' => ['message', 'subscribed', 'conversation_started'], 7 ]); 8 9 $ch = curl_init('https://chatapi.viber.com/pa/set_webhook'); 10 curl_setopt($ch, CURLOPT_POST, 1); 11 curl_setopt($ch, CURLOPT_POSTFIELDS, $data); 12 curl_setopt($ch, CURLOPT_HTTPHEADER, [ 13 'Content-Type: application/json', 14 'X-Viber-Auth-Token: ' . $token, 15 ]); 16 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 17 18 $result = curl_exec($ch); 19 $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); 20 curl_close($ch); 21 22 echo "HTTP {$httpCode}: {$result}\n"; 23 24 if ($httpCode === 200) { 25 $response = json_decode($result, true); 26 if (($response['status'] ?? -1) === 0) { 27 echo "Вебхук установлен успешно.\n"; 28 } else { 29 echo "Ошибка Viber: " . ($response['status_message'] ?? 'неизвестная') . "\n"; 30 } 31 }
Was hier passiert: cURL sendet einen POST an set_webhook. Das Token steht strikt im Header, nicht im Body. Viber gibt bei Erfolg {"status":0} zurück und sendet umgehend einen webhook-Callback an die angegebene URL, um deren Verfügbarkeit zu prüfen. Die Antwort mit {"status":0,"status_message":"ok"} auf diesen Callback ist zwingend erforderlich (das behandeln wir im nächsten Schritt).
Wenn Sie invalidUrl erhalten, prüfen Sie Ihr SSL-Zertifikat. Let's Encrypt funktioniert; selbstsignierte nicht. Auf Ihrem Server genügt es, certbot --nginx -d your-domain.com auszuführen und die automatische Verlängerung via Cron einzurichten.
Schritt 2: Callback-Ereignisse von Viber empfangen
Wenn ein Nutzer mit dem Bot interagiert, sendet Viber eine POST-Anfrage mit JSON an Ihren Webhook. Ihre Aufgabe ist es, das Feld event zu lesen und zu reagieren.
Ein minimaler Handler webhook.php, der korrekt auf alle Ereignisse antwortet:
1 <?php 2 $request = file_get_contents("php://input"); 3 $input = json_decode($request, true); 4 5 if ($input['event'] === 'webhook') { 6 $response = [ 7 'status' => 0, 8 'status_message' => 'ok', 9 'event_types' => ['delivered', 'seen', 'message', 'subscribed', 'conversation_started'], 10 ]; 11 echo json_encode($response); 12 exit; 13 } 14 15 if ($input['event'] === 'subscribed') { 16 $sender_id = $input['sender']['id']; 17 sendWelcomeMessage($sender_id); 18 } 19 20 if ($input['event'] === 'conversation_started') { 21 $sender_id = $input['sender']['id']; 22 sendMainMenu($sender_id); 23 } 24 25 if ($input['event'] === 'message') { 26 $type = $input['message']['type']; 27 $text = $input['message']['text']; 28 $sender_id = $input['sender']['id']; 29 $sender_name = $input['sender']['name']; 30 31 $data = match ($text) { 32 'News' => getNewsList($sender_id), 33 'Articles' => getArticleList($sender_id), 34 'Gallery' => getGalleryList($sender_id), 35 default => getMainMenu($sender_id), 36 }; 37 38 sendToViber($data); 39 }
Ereignisaufschlüsselung:
webhooktrifft einmalig ein, wenn der Webhook gesetzt wird. Sie müssen{"status":0,"status_message":"ok"}mit einer Liste der unterstützten Ereignisse zurückgeben. Ohne dies bestätigt Viber die URL nicht und der Bot startet nicht.subscribedbedeutet, dass ein Nutzer den Bot abonniert hat. Dies ist der ideale Zeitpunkt, um ein Willkommensmenü zu senden.conversation_startedbedeutet, dass ein Nutzer den Chat geöffnet hat (erstmalig oder erneut). Ebenfalls geeignet, um das Hauptmenü anzuzeigen.messageist das zentrale Arbeitsereignis. Das Feldtextenthält entweder eine beliebige Nutzernachricht oder denActionBodyeiner gedrückten Schaltfläche (sofern deren Typreplyist). Darüber versteht der Bot, was ausgewählt wurde: „News", „Artikel" oder „Galerie".
Das Konstrukt match() steht ab PHP 8 zur Verfügung. Falls Sie PHP 7.4 einsetzen, ersetzen Sie es durch switch.
Schritt 3: Das Tastaturmenü aufbauen
Eine Tastatur wird jeder Nachricht über das Feld keyboard im JSON-Objekt send_message angehängt. Es handelt sich um ein Array von Schaltflächen mit separaten Einstellungen für Breite (Columns, 1-6), Höhe (Rows, 1-2), Hintergrundfarbe, Text und Aktion.
Eine Funktion, die ein Hauptmenü aus sieben Reply-Buttons und einem Link-Button zusammensetzt:
1 <?php 2 3 function getMainMenu(string $user_id): array 4 { 5 $buttons = []; 6 7 $addReplyButton = function (string $label, string $actionBody, int $cols = 2, int $rows = 2) use (&$buttons) { 8 $buttons[] = [ 9 'Columns' => $cols, 10 'Rows' => $rows, 11 'Text' => $label, 12 'TextSize' => 'regular', 13 'TextVAlign' => 'bottom', 14 'TextHAlign' => 'center', 15 'TextOpacity' => 100, 16 'ActionType' => 'reply', 17 'ActionBody' => $actionBody, 18 'BgColor' => '#FFFFFF', 19 ]; 20 }; 21 22 $addReplyButton('NEWS', 'News'); 23 $addReplyButton('ARTICLES', 'Articles'); 24 $addReplyButton('INTERVIEWS', 'Interviews'); 25 $addReplyButton('GALLERY', 'Gallery'); 26 $addReplyButton('POLL', 'Poll'); 27 $addReplyButton('PLAYER OF THE MONTH','POTM'); 28 $addReplyButton('QUOTE OF THE DAY', 'Quote'); 29 30 $buttons[] = [ 31 'Columns' => 4, 32 'Rows' => 2, 33 'Text' => 'VISIT OUR WEBSITE', 34 'TextSize' => 'regular', 35 'TextVAlign' => 'bottom', 36 'TextHAlign' => 'center', 37 'TextOpacity' => 100, 38 'ActionType' => 'open-url', 39 'ActionBody' => 'https://your-site.com', 40 'BgColor' => '#FFFFFF', 41 ]; 42 43 return [ 44 'receiver' => $user_id, 45 'type' => 'text', 46 'text' => 'Please select one of the options below:', 47 'keyboard' => [ 48 'Type' => 'keyboard', 49 'BgColor' => '#FFFFFF', 50 'Buttons' => $buttons, 51 ], 52 ]; 53 }
Schaltflächen mit Columns=2 und Rows=2 sind quadratisch, drei pro Zeile (2+2+2=6). Der Link-Button mit Columns=4 belegt eine eigene Zeile. Das Raster wird von links nach rechts und von oben nach unten aufgebaut. Die Summe der Columns in einer Zeile bestimmt das Layout.
Parameter der Schaltflächen:
Parameter | Werte | Zweck |
|---|---|---|
| 1-6 | Schaltflächenbreite in bedingten Spalten |
| 1-2 | Schaltflächenhöhe in Zeilen |
|
|
|
| Zeichenkette | Bei |
| Zeichenkette | Beschriftung der Schaltfläche, unterstützt HTML-Tags b, i und Schriftfarbe |
| HEX | Hintergrundfarbe der Schaltfläche |
| URL | Bild oberhalb der Schaltfläche, JPEG, optional |
Schritt 4: Daten per send_message versenden
Eine Sender-Funktion, die Sie aus dem Event-Handler aufrufen:
1 <?php 2 3 function sendToViber(array $data): void 4 { 5 $token = 'ВАШ_X_VIBER_AUTH_TOKEN'; 6 7 $ch = curl_init('https://chatapi.viber.com/pa/send_message'); 8 curl_setopt($ch, CURLOPT_POST, 1); 9 curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); 10 curl_setopt($ch, CURLOPT_HTTPHEADER, [ 11 'Content-Type: application/json', 12 'X-Viber-Auth-Token: ' . $token, 13 ]); 14 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 15 16 $result = curl_exec($ch); 17 $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); 18 curl_close($ch); 19 20 if ($httpCode !== 200) { 21 error_log("Viber API error: HTTP {$httpCode} - {$result}"); 22 } 23 }
Der wesentliche Unterschied zu älteren Tutorials: Der Token steht im Header, nicht im JSON-Body. Der Body enthält nur die Felder receiver, type, text, keyboard und optional sender.name, sender.avatar, tracking_data. Die maximale JSON-Größe beträgt 30 KB. Wenn Sie diese überschreiten, verwirft Viber die Nachricht stillschweigend; prüfen Sie strlen(json_encode($data)) vor dem Senden.
Schritt 5: Inhalte für Schaltflächen zusammenstellen
Wenn ein Nutzer eine Reply-Schaltfläche drückt, wird deren ActionBody als Nachrichtentext an den Webhook gesendet. Sie parsen diesen in match() und rufen die entsprechende Funktion auf. Hier ein Beispiel für eine Nachrichtenliste mit Bildern:
1 <?php 2 3 function getNewsList(string $user_id): array 4 { 5 $newsItems = [ 6 [ 7 'title' => 'Your Article Title', 8 'link' => 'https://your-site.com/article-1', 9 'image' => 'https://your-site.com/images/article-1.jpg', 10 ], 11 [ 12 'title' => 'Another Article', 13 'link' => 'https://your-site.com/article-2', 14 'image' => 'https://your-site.com/images/article-2.jpg', 15 ], 16 ]; 17 18 $buttons = []; 19 foreach ($newsItems as $item) { 20 $buttons[] = [ 21 'Columns' => 2, 22 'Rows' => 2, 23 'ActionType' => 'open-url', 24 'ActionBody' => $item['link'], 25 'BgColor' => '#FFFFFF', 26 'Image' => $item['image'], 27 ]; 28 $buttons[] = [ 29 'Columns' => 4, 30 'Rows' => 2, 31 'Text' => $item['title'], 32 'TextSize' => 'regular', 33 'TextHAlign' => 'left', 34 'TextVAlign' => 'top', 35 'ActionType' => 'open-url', 36 'ActionBody' => $item['link'], 37 'BgColor' => '#F5F5F5', 38 ]; 39 } 40 41 return [ 42 'receiver' => $user_id, 43 'type' => 'text', 44 'text' => 'Here are the latest updates:', 45 'keyboard' => [ 46 'Type' => 'keyboard', 47 'BgColor' => '#DDDDDD', 48 'Buttons' => $buttons, 49 ], 50 ]; 51 }
Auf Nutzerseite sieht dies wie ein Raster aus Karten aus: Bild links, Titel rechts. Ein Tippen auf einen beliebigen Bereich öffnet den Link im Browser.

Eine Galerie, Artikelliste oder Umfragen werden exakt auf dieselbe Weise zusammengestellt; lediglich der Inhalt des Arrays $buttons und der Nachrichtentext ändern sich. Falls viel Inhalt vorhanden ist und das JSON sich 30 KB nähert, teilen Sie es mit einem „Weiter"-Button in Seiten auf.
Wenn Sie lieber mit einer fertigen PHP-Bibliothek arbeiten möchten statt mit der rohen API, sehen Sie sich viber-bot-php von Bogdaan an. Diese übernimmt für Sie die Signaturvalidierung, das Event-Routing und die JSON-Generierung.
Zusammenfassung: vollständige Startsequenz
- Token beschaffen im Viber Admin Panel: Bereich „Info bearbeiten" → App Key.
- Handler bereitstellen auf einem Server mit HTTPS. Let's Encrypt funktioniert; ein selbstsigniertes Zertifikat nicht. Viber validiert Zertifikate gegen die vertrauenswürdige Java Root CA-Liste.
- Webhook setzen mit einer POST-Anfrage an
https://chatapi.viber.com/pa/set_webhookmit Body{"url":"https://your-domain/webhook.php","event_types":[...]}und HeaderX-Viber-Auth-Token. - Antwort prüfen:
{"status":0}bedeutet Erfolg. Viber sendet sofort einenwebhook-Callback an Ihre URL. Stellen Sie sicher, dass das Skript{"status":0,"status_message":"ok"}zurückgibt. - Erstes Menü senden: beim Event
conversation_startedgetMainMenu()aufrufen und das Ergebnis ansendToViber()übergeben.
⁉️🤔 Häufig gestellte Fragen
Kann ich ein selbstsigniertes SSL-Zertifikat für den Webhook verwenden?
Nein. Viber validiert das Zertifikat gegen die Liste der vertrauenswürdigen Java-Root-Zertifizierungsstellen. Ein selbstsigniertes Zertifikat verursacht beim Setzen des Webhooks einen
invalidUrl-Fehler. Let's Encrypt ist in dieser Liste enthalten und kostenlos. Führen Sie auf Ihrem Servercertbot --nginx -d your-domain.comaus, hinterlegen Sie die automatische Verlängerung im Cron, und Viber akzeptiert das Zertifikat problemlos.
Was ist der Unterschied zwischen reply und open-url beim ActionType?
replysendetActionBodyals Nachrichtentext an den Webhook zurück. Das PHP-Skript sieht ihn in$input['message']['text']und leitet ihn übermatch()weiter. Verwenden Sie dies für die Navigation innerhalb des Bots.open-urlöffnet einen Link in einem externen Browser und löst keinen Webhook aus. In der Praxis kombinieren Menüs beide Typen: fünf oder sechs Reply-Buttons für Bereiche und einen breiten Open-URL-Button für den Sprung zur Website.
Welche Nachrichtentypen unterstützt die Viber Bot API?
Die Viber Bot API unterstützt neun
type-Werte insend_message:text(reiner Text),picture(JPEG-Bild),video(Videodatei),file(beliebige Datei bis 50 MB),location(Geopunkt),contact(Kontaktkarte),sticker(Sticker),rich_media(Kartenkarussell) undurl(Linkvorschau). Die aktuelle Liste mit den erforderlichen Feldern finden Sie in der Dokumentation des Viber Developers Hub. Das häufigste Szenario isttext+keyboardfür Menüs undpicturefür den Bildversand. Karussells eignen sich hervorragend für Shops und Kataloge, erfordern aber mehr Code.
Was tun, wenn der Nutzer die Tastatur nicht sieht?
Es gibt drei häufige Ursachen. Erstens: Das JSON mit der Tastatur hat 30 KB überschritten, und Viber verwirft solche Nachrichten stillschweigend. Prüfen Sie
strlen(json_encode($data))vor dem Senden. Zweitens: Die Antwort aufset_webhookenthielt kein"status":0, der Webhook wurde nicht gesetzt, und der Bot empfängt keine Nachrichten. Drittens: Sie verwenden das alte Format mitauth_tokenim JSON-Body. Seit API 7.0 wird dies ignoriert; Sie benötigen denX-Viber-Auth-Token-Header. Aktivieren Sie zum Debuggen das Logging der Viber-API-Antwort: Sie liefert lesbares JSON mit Fehlercodes wie invalidAuthToken, badData oder missingData.
Kann ich die Tastatur nach dem Senden ändern?
Ja. Mit jeder neuen Nachricht können Sie eine andere Tastatur senden. Der Viber-Client zeigt immer die zuletzt empfangene an. So lassen sich mehrstufige Menüs aufbauen: Hauptmenü → Bereichs-Untermenü → spezifischer Inhalt. Jede Ebene hat ihren eigenen Satz an Schaltflächen, und der Nutzer bewegt sich durch Drücken der Reply-Tasten zwischen ihnen.
Was kostet der Start eines Viber-Bots im Jahr 2026?
Seit dem 5. Februar 2024 kostet die Erstellung eines neuen Bots 100 € pro Monat über offizielle Rakuten-Viber-Partner. Bots, die vor diesem Datum erstellt wurden, laufen zu den alten Konditionen weiter. Die Kosten umfassen einen dedizierten Account mit Admin-Panel, Analysefunktionen und Zugriff auf alle Nachrichtentypen einschließlich rich_media und Viber Pay. Der technische Teil der API ist für kommerzielle und ältere kostenlose Bots identisch.
Der Bot ist bereit: was nun kommt
Ein Tastaturmenü ist nur ein Einstiegspunkt. Sobald die grundlegende Mechanik funktioniert, ergänzen Sie Inhaltskarussells über rich_media, Zahlungen über Viber Pay und eine Nutzersegmentierung danach, welche Schaltflächen am häufigsten gedrückt werden. Jede neue Ebene ändert nichts am Fundament: Sie lesen weiterhin event und senden weiterhin send_message mit dem X-Viber-Auth-Token-Header.
Wenn Sie ein funktionierendes Codebeispiel benötigen, sehen Sie sich das viber-bot-php-Repository auf GitHub an. Es deckt alle Events, die Anfragensignierung und den Aufbau einer Tastatur mit Bildern ab. Und für einen visuellen Einstieg hier ein halbstündiges Tutorial zur Erstellung eines Viber-Bots von Grund auf:
Das Wichtigste, was Sie sich merken sollten: Die Viber Bot API ist am Anfang einfach, aber anspruchsvoll bei den Details. Ein korrekter Authentifizierungs-Header, vertrauenswürdiges SSL, gültiges JSON unter 30 KB und ein klares ActionBody-Routing genügen, damit der Bot störungsfrei läuft. Nehmen Sie die obigen Codeausschnitte, setzen Sie Ihren Token und Ihre Domain ein und starten Sie noch heute Ihr erstes Menü.



