waix / waix-php
WAIX WhatsApp API v1: messages, templates, OTP and signed webhooks
Requires
- php: >=8.1
- ext-curl: *
- ext-json: *
Requires (Dev)
None
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Клиент WAIX для PHP 8.1 и новее. Нужны расширения cURL и JSON. Установка через Composer, пространство имён Waix, автозагрузка PSR-4.
Установка
composer require waix/waix-php:^0.2
Пакет Packagist · Исходный код
Дополнительный VCS-репозиторий в настройках Composer не нужен.
Перед первым запросом
Подключите номер в WAIX, получите Connection ID и серверный ключ с правом messages:write. Пример использует одобренный шаблон order_ready на русском языке с одной переменной в теле.
Отправка шаблона
<?php require 'vendor/autoload.php'; $waix = new Waix\Client(getenv('WAIX_API_KEY')); // $eventId — UUID, уже сохранённый в записи заказа или очереди уведомлений. $result = $waix->messages->send([ 'connection_id' => getenv('WAIX_CONNECTION_ID'), 'to' => '+77071234567', 'type' => 'template', 'template' => [ 'name' => 'order_ready', 'language' => ['code' => 'ru'], 'components' => [['type' => 'body', 'parameters' => [['type' => 'text', 'text' => '42']]]], ], ], $eventId);
OTP: отправка и проверка
$otp = new Waix\Client(getenv('WAIX_OTP_PROJECT_KEY')); $sent = $otp->otp->send(['to' => '+77071234567', 'ttl' => 300], $eventId); // Сохраните $sent['data']['id'] в серверной сессии пользователя. $status = $otp->otp->status($sent['data']['id']); // $suppliedCode — код, введённый пользователем в той же сессии. $verified = $otp->otp->verify($sent['data']['id'], $suppliedCode);
Ошибки, файлы и параметры клиента
Перехватывайте Waix\WaixError. Поля: status (0 при сетевой ошибке), errorCode, requestId, retryAfter, body. Таймаут задаётся в миллисекундах:
$waix = new Waix\Client(getenv('WAIX_API_KEY'), timeoutMs: 30000);
Загрузка файла: $waix->media->upload($connectionId, '/path/invoice.pdf', 'application/pdf', ['type'=>'document']).
Пагинация: $waix->messages->list(['limit'=>50, 'before'=>$cursor, 'before_id'=>$cursorId]).
Проверка вебхука: Waix\Webhook::verify($rawBody, $timestampHeader, $signatureHeader, $secret).
Разработка
Запустите composer validate --strict и composer test. Контрактные тесты подменяют транспорт и не отправляют сообщения клиентам. Проверка выпуска также запускает cURL против локального HTTP-сервера и проверяет запрет перенаправлений.
Какие методы есть
| Раздел | Возможности |
|---|---|
| Сообщения | Отправка, список с пагинацией, просмотр, явный повтор |
| Подключения | Список номеров, чтение и изменение профиля компании |
| Шаблоны | Список, просмотр, создание, изменение, удаление, предварительный просмотр |
| Медиа | Загрузка файла, список, получение URL, удаление |
| Вебхуки | Чтение и изменение настроек, тест, удаление, смена секрета |
| OTP | Отправка кода, проверка, статус запроса |
Все запросы идут на https://waix.kz/api/v1. SDK возвращает полный JSON-ответ: data, а также pagination, если она есть. Для остальных операций API v1 можно использовать метод request с относительным путём. Не передавайте в него адрес, полученный от непроверенного пользователя.
Некоторым операциям нужны права управления и ключ компании. Ключ отдельного OTP-проекта не даёт доступа к настройкам вебхука компании. Список прав и полей: спецификация API.
Повторные запросы и доставка
Создайте UUID один раз при записи события в своей базе. Передайте его как ключ идемпотентности. При потере ответа повторяйте запрос с тем же UUID и теми же параметрами: новый ключ означает новое сообщение.
HTTP 202 означает, что сообщение поставлено в очередь. Доставку проверяйте по вебхуку, журналу WAIX или методу просмотра сообщения. У SDK нет автоматических повторов и переходов по HTTP redirect. Для 429 учитывайте Retry-After; ошибки 400, 401, 403 требуют исправления параметров или доступа. Сообщение со статусом outcome_unknown нельзя повторять вслепую.
Проверка подписи вебхука
Передавайте в функцию проверки исходные байты тела HTTP-запроса до разбора JSON, заголовки X-Waix-Timestamp, X-Waix-Signature и секрет вебхука. Подпись: HMAC-SHA256 от timestamp + "." + rawBody, с префиксом v1=. Сравнение выполняется за постоянное время; допустимое отклонение времени по умолчанию — 300 секунд.
Отклоняйте неверную подпись. Повторные события определяйте по X-Waix-Delivery: верная подпись сама по себе не защищает от повторной доставки в пределах допустимого времени. Сначала надёжно сохраните событие, затем ответьте кодом 2xx.
Ключи, OTP и данные клиентов
- Храните ключи на сервере. Не включайте их в код сайта, мобильного приложения или общий файл сценария. Выдавайте только нужные права.
- Для первого сообщения клиенту обычно нужен одобренный шаблон. Произвольный текст разрешён в рамках действующего окна обслуживания Meta. Проверяйте согласие клиента и учитывайте отказ от сообщений.
- OTP использует отдельный ключ проекта. Начните с sandbox: он возвращает
test_codeи не отправляет сообщение WhatsApp. Тестовый код нельзя показывать человеку, чью личность вы проверяете. - Сохраните ID OTP-запроса в серверной сессии пользователя. Проверять код должна именно эта сессия. Выдавайте доступ только после успешной проверки; ограничивайте попытки по аккаунту и IP.
- Для рабочих OTP нужны доступный тариф и одобренный отправитель. Проверьте их состояние в кабинете WAIX до включения реальной отправки.
- SDK не записывает ключи, сообщения и коды в лог. Если добавляете свои логи, скрывайте эти данные и сохраняйте
request_idдля диагностики.
Документация и поддержка
Документация WAIX · Поддержка · Тарифы.
SDK работает с API v1 WAIX. Это не клиент Meta Graph API. Версии SDK следуют SemVer. Лицензия — MIT.
Поведение версии 0.2.0
SDK не повторяет запрос за вас. HTTP-ошибка от прокси остаётся HTTP-ошибкой, даже если вместо JSON пришёл HTML: сохраняются статус, request ID и Retry-After. Перенаправления запрещены. Некорректный успешный ответ вызывает INVALID_RESPONSE; ответ больше установленного лимита — RESPONSE_TOO_LARGE. Лимит по умолчанию — 2 МиБ, его можно увеличить до 16 МиБ.
| Ситуация | Что делать |
|---|---|
400 / 422 |
Исправить поля, формат телефона, шаблон или код OTP. |
401 / 403 |
Проверить ключ, права и принадлежность подключения/OTP-проекта. |
409 |
Проверить конфликт ключа идемпотентности: под одним ключом нельзя менять тело. |
429 |
Отложить запрос на срок из Retry-After, сохранив прежний ключ и тело. |
5xx, TIMEOUT, TRANSPORT_ERROR |
Результат отправки может быть неизвестен. Сначала проверить сохранённый ID; если ID не получен, повторять прежний запрос с прежним ключом через ограниченную очередь повторов. |
INVALID_RESPONSE / RESPONSE_TOO_LARGE |
Проверить прокси, адрес API и размер страницы. Не создавать новую отправку. |
OTP_INVALID |
Код неверен, истёк или уже использован. Не выдавать сессию приложения. |
body исключения доступен для диагностики, но может содержать данные клиента. В журнал записывайте только безопасные метаданные из примера ниже. Не сериализуйте целиком ответ sandbox OTP.
Обновление с 0.1.x
Имена существующих методов сохранены. У otp.verify код должен быть строкой из шести цифр: '012345', а не число. Значения query — только строки, конечные числа и boolean; сложные объекты нужно разобрать на параметры. Ошибки HTML от прокси теперь имеют API_ERROR, а перенаправления — REDIRECT_DISALLOWED. При обработке ошибок ориентируйтесь также на HTTP-статус.
Пагинация и диагностика
$waix = new Waix\Client(getenv('WAIX_API_KEY'), timeoutMs: 30000, maxResponseBytes: 2097152); foreach ($waix->messages->iterate(['connection_id' => $connectionId, 'limit' => 100], maxPages: 100) as $message) { saveStatus($message['id'], $message['status']); }
Генератор запрашивает страницы по мере чтения, переносит оба курсора и сохраняет фильтры. Повторный курсор вызывает INVALID_PAGINATION; достижение maxPages — PAGINATION_LIMIT. По умолчанию предел — 1000 страниц.
try { $result = $waix->messages->get($savedMessageId); } catch (Waix\WaixError $error) { error_log(json_encode($error, JSON_THROW_ON_ERROR)); // только безопасные метаданные $delayMs = $error->retryDelayMs(); // миллисекунды или null // Решение о повторе принимает ваша очередь. }
SDK использует cURL с проверкой TLS. timeoutMs ограничивает весь запрос, подключение — максимум 10 секунд. Сертификаты на сервере должны быть актуальны; отключать их проверку не нужно.