Разработчикам

WhatsApp API не работает: что проверить по шагам

Обновлено 8 мин чтения

Сообщения перестали уходить, вебхук молчит, клиент говорит, что ничего не получил. Обычно причина находится за пару минут: API почти всегда сообщает, что случилось, — в поле code ответа или в статусе номера.

Ниже — порядок проверки, коды ошибок, разбор частых ситуаций и скрипт мониторинга по расписанию.

Диагностика по шагам

Шаг 1. Посмотрите статус номеров

bash
curl https://wapi.kz/api/v1/status -H "Authorization: Bearer $WAPI_KEY"

У каждого номера смотрите status и wa_status: нужны active и WORKING. paused — кончился баланс, FAILED или STOPPED — номер отключился от WhatsApp, SCAN_QR_CODE — ждёт привязки, STARTING — запускается, подождите минуту.

Шаг 2. Проверьте баланс

В том же ответе — balance и days_left. Отдельно баланс отдаёт GET /balance: там ещё число активных номеров и номеров на паузе.

Шаг 3. Проверьте лимиты номера

bash
curl "https://wapi.kz/api/v1/limits?from=1" -H "Authorization: Bearer $WAPI_KEY"

Сравните used с limits: не исчерпан ли суточный лимит. cold_blocked_until покажет, не приостановлены ли первые сообщения новым людям, warmup: true — что номер ещё на прогреве.

Шаг 4. Найдите само сообщение

Если запрос на отправку прошёл, у сообщения есть id. GET /messages/{id} покажет его status и error.

Коды ошибок: причина и что делать

Ошибка всегда приходит как {"error": "…", "code": "…"}. В error — подсказка по-русски, её стоит писать в лог целиком.

codeHTTPПричинаЧто делать
unauthorized401Нет заголовка с ключомДобавить Authorization: Bearer <API_KEY>
invalid_key401Ключ неверный, перевыпущен или отозванВзять актуальный ключ в кабинете
forbidden_for_number_key403Ключ номера запрашивает баланс или данные аккаунтаИспользовать ключ аккаунта
invalid_json400Тело — не JSON-объектПроверить Content-Type и сериализацию
invalid_to, invalid_phone400Номер не из 10–15 цифрПривести к виду 77011234567
empty_text, text_too_long400Текст пустой или длиннее 4096 символовИсправить или разбить на части
invalid_param400Неверный since, until, direction или formatПроверить формат параметра
from_required400Номеров несколько, from не указанПередавать from всегда
invalid_from400В from не id и не телефонВзять id из GET /numbers
invalid_media, media_too_large, media_fetch_failed400Проблема с вложениемСм. гайд про отправку файлов
number_paused402Номер на паузе: закончился балансПополнить — номер включится сам
number_not_found404Номера нет в аккаунте или он недоступен этому ключуПроверить from и ключ
not_found404Сообщения нет в вашем аккаунтеПроверить id
no_numbers409В аккаунт не добавлен номерДобавить номер в кабинете
not_connected409Номер не подключён к WhatsAppПереподключить по QR-коду или коду
rate_limited429Слишком часто: больше 1 сообщения или проверки в секундуОчередь с паузами
daily_limit, new_contacts_limit, checks_limit429Исчерпан лимит на сегодняЖдать полуночи по Алматы
cold_blocked, spam_detected429Отправка похожа на рассылкуЖдать 24 часа; отвечать клиентам можно
send_failed, check_failed502WhatsApp не принял сообщение или проверкуПовторить позже, проверить номер
capacity503Номер перезапускаетсяПовторить через пару минут

На 502 и 503 делайте 2–3 повтора с паузой в минуты. Из ошибок 429 быстрый повтор помогает только при rate_limited. Ошибки вложений разобраны в гайде как отправить фото и файлы, полный справочник — в документации.

Номер отключился

Признаки: ответы not_connected (409), wa_status FAILED или STOPPED, вебхук session.status. Мы тоже пришлём уведомление. Частые причины:

  • Телефон долго был без интернета: по правилам WhatsApp связанные устройства отключаются, если телефон не в сети около 14 дней.
  • На телефоне удалили связанное устройство: WhatsApp → Настройки → Связанные устройства.
  • WhatsApp переустановили или перенесли на другой телефон — связанные устройства в таком случае обычно приходится привязывать заново.

Что делать: переподключите номер в кабинете по QR-коду или коду по номеру — так же, как при первом подключении. Держать телефон всё время онлайн не нужно, но надолго без сети его оставлять нельзя.

Номер на паузе

Код number_paused (402) и status: "paused" значат, что на балансе не хватило денег на сутки: номер стоит 330 ₸ в сутки, списание — в 00:05 по Алматы. На паузе номер не отправляет и не принимает сообщения через сервис, но привязка WhatsApp сохраняется, а на телефоне всё работает как обычно.

После пополнения номер включится сам. Мы предупреждаем, когда баланса остаётся на 3 дня или меньше; следить автоматически поможет days_left из GET /balance. Как пополнить — на странице цен.

Ошибки 429: лимиты

  • rate_limited — слишком часто. С номера — не чаще 1 сообщения в секунду, первые сообщения новым людям — не чаще раза в 5 секунд. Нужна очередь, пример есть в гайде про отправку сообщений.
  • daily_limit, new_contacts_limit — исчерпан лимит на сутки. Он зависит от индекса доверия, а в первые две недели номер на прогреве: дни 1–3 — 200 сообщений и 20 новых контактов в сутки, дни 4–7 — 400 и 40, дни 8–14 — 700 и 80.
  • cold_blocked, spam_detected — отправка похожа на рассылку: один текст ушёл 25+ новым людям за час или за час появилось 40+ новых контактов. Первые сообщения новым людям закрыты на 24 часа, время окончания — в cold_blocked_until. Отвечать тем, кто пишет вам, можно.
  • checks_limit — больше 200 проверок номеров за сутки. Сохраняйте результаты проверок у себя.

Не пытайтесь обойти защиту — перефразировать текст или переключаться на другой номер. Такой поток выглядит как рассылка и для WhatsApp, а это главная причина блокировок. Что делать вместо этого — в гайде как снизить риск блокировки.

Вебхук не приходит

  • Адрес начинается с https:// и доступен из интернета: не localhost, не внутренний IP, не адрес за VPN.
  • Нет перенаправлений. Мы не следуем за 301 и 302, поэтому http вместо https, адрес без www или без слеша на конце, который сервер перенаправляет, — частые причины.
  • Токен в адресе совпадает с тем, что проверяет обработчик, — иначе ваш же сервер отвечает 403.
  • Обработчик отвечает 200 быстрее 10 секунд. Если ИИ думает дольше, отвечайте сразу, а работайте после.
  • Сертификат действителен, а защита от ботов не режет запросы с User-Agent: wapi.kz-webhook.
  • Адрес задан у нужного номера, а сам номер подключён и не на паузе.

Свои отправки через API в вебхук не приходят — так задумано. Проверить адрес снаружи:

bash
curl -i -X POST "https://crm.example.kz/whatsapp/webhook?token=СЕКРЕТ" \
  -H "Content-Type: application/json" -H "User-Agent: wapi.kz-webhook" \
  -d '{"event":"message","payload":{"from":"77011234567@c.us","body":"тест"},"wapi":{"number_id":1}}'

В первой строке ответа должен быть код 200, а не 301, 302 или 403. Повторной отправки событий нет: пропущенное заберите через GET /messages?since=…. Подробнее о приёме — в гайде про вебхуки.

«Отправлено», но не доставлено

Ответ 200 значит, что сообщение ушло в WhatsApp. Дальше смотрите статус в GET /messages/{id} или в вебхуке message.ack:

  • Долго sent (одна галочка) — получатель не в сети, сменил номер или номера нет в WhatsApp. Перед первым сообщением проверяйте номер через POST /contacts/check (документация).
  • failed — в error причина: send_failed, capacity, number_paused — не ушло; not delivered — WhatsApp сообщил, что не доставил.
  • delivered, но клиент «не видел» — сообщение на его телефоне; возможно, чат в архиве. «Прочитано» не приходит, если получатель отключил отчёты о прочтении.
  • Номер записан через 8: 87011234567 — формально 11 цифр, но для WhatsApp это другой номер. Приводите к виду 77011234567.

Мониторинг: скрипт для cron

Вебхук session.status сообщает об отключении сразу, но если упал ваш обработчик, вы об этом не узнаете. Подстрахуйтесь скриптом: раз в 10 минут он проверяет GET /status и пишет в Telegram, если номер отключился, встал на паузу или баланса осталось на 3 дня и меньше. Нужен ключ аккаунта: с ключом номера /status не отдаёт баланс.

Python
#!/usr/bin/env python3
import os

import requests

API = "https://wapi.kz/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['WAPI_KEY']}"}


def alert(text):
    token = os.environ["TG_BOT_TOKEN"]
    requests.post(f"https://api.telegram.org/bot{token}/sendMessage",
                  json={"chat_id": os.environ["TG_CHAT_ID"], "text": text}, timeout=10)


def main():
    try:
        r = requests.get(f"{API}/status", headers=HEADERS, timeout=15)
        s = r.json()
        r.raise_for_status()
    except (requests.RequestException, ValueError) as e:
        alert(f"wapi.kz: не удалось получить статус — {e}")
        return
    problems = []
    for n in s["numbers"]:
        name = n.get("label") or n.get("phone") or f"#{n['id']}"
        if n["status"] == "paused":
            problems.append(f"{name}: на паузе, пополните баланс")
        elif n["wa_status"] != "WORKING":
            problems.append(f"{name}: {n['wa_status']}, переподключите в кабинете")
        if n.get("cold_blocked_until"):
            problems.append(f"{name}: первые сообщения новым людям закрыты до {n['cold_blocked_until']}")
    days = s.get("days_left")
    if days is not None and days <= 3:
        problems.append(f"Баланса хватит на {days} дн. (остаток {s['balance']} ₸)")
    if problems:
        alert("wapi.kz:\n" + "\n".join(problems))


if __name__ == "__main__":
    main()

Запуск каждые 10 минут — ключи лежат в файле с переменными, а не в самой строке crontab:

*/10 * * * * set -a; . /etc/wapi-monitor.env; set +a; /usr/bin/python3 /opt/wapi-monitor.py

Куда писать

Если по шагам выше причина не нашлась, напишите в поддержку в Telegram — @wapi_kz_support_bot, отвечаем в рабочее время. Чтобы разобраться быстрее, пришлите email аккаунта, id номера, id сообщения или время запроса, а также code и error из ответа. API-ключ не присылайте никогда.

Если вы только выбираете сервис, начните с регистрации и подключения номера — это около 5 минут.

Частые вопросы

Почему API отвечает not_connected, хотя WhatsApp на телефоне работает?

Телефон работает сам по себе, а связанное устройство, через которое работает сервис, отключилось. Переподключите номер в кабинете по QR-коду или коду по номеру.

Как понять, что WhatsApp заблокировал номер?

Об этом сообщит само приложение WhatsApp на телефоне. Снять блокировку может только WhatsApp — через запрос на проверку в приложении; мы на это повлиять не можем.

Есть ли у вас SLA?

Отдельного SLA и процентов доступности мы не обещаем. Если от WhatsApp зависят заказы, настройте мониторинг (скрипт выше) и запасной канал уведомлений.

Почему в вебхук не приходят сообщения, отправленные через API?

Так задумано: о своей отправке вы знаете из ответа на запрос. В вебхук приходят её статусы — событием message.ack.

Подключите WhatsApp к своим системам

9 900 ₸ в месяц за номер, без платы за сообщения. Сервер в Казахстане, оплата Kaspi или счётом на ТОО/ИП. Подключение — около 5 минут.