Ошибки и идемпотентность
Ориентируйтесь на код ошибки, а не на статус. И делайте безопасным каждый повторный запрос, который стоит денег.
Ориентируйтесь на код, а не на статус
Ошибки возвращаются в виде { "error": "<code>" }. Одного статуса недостаточно,
чтобы решить, что делать: два ответа 403 могут требовать противоположных
действий.
| Статус | Код | Что это значит и что делать |
|---|---|---|
| 401 | invalid_key | Ключ неизвестен или отозван. Создайте новый; повторные запросы не помогут. |
| 403 | ip_not_allowed | У ключа есть список разрешённых IP-адресов, и этого адреса в нём нет. С ключом всё в порядке — добавьте адрес на developers.wasync.app/keys. Ключ менять не нужно. |
| 403 | insufficient_scope | У учётных данных нет области доступа (scope), которая нужна этому эндпоинту. |
| 403 | forbidden_portal_kind | POST /connections на портале Bitrix24. Подключения на таких порталах создаёт администратор портала. |
| 400 | invalid_phone_number | phoneNumber должен содержать только цифры, без ведущего +. |
| 400 | invalid_webhook | URL должен быть HTTPS на общедоступном хосте. |
| 402 | — | Лицензия подключения истекла. См. Лицензии и trial. |
| 409 | already_connected | Сессия активна, связывать нечего. |
| 409 | not_supported_for_provider | Операция только для qr вызвана на номере cloud_api. Это окончательно — не повторяйте запрос. |
| 422 | recipient_not_on_whatsapp | WhatsApp не нашёл аккаунт получателя. Проверьте, что номер указан в международном формате (сначала код страны, без ведущего нуля) и что человек пользуется WhatsApp. Для этого номера ошибка окончательная — не повторяйте запрос без изменений. |
| 502 | send_failed | WhatsApp не смог доставить сообщение по причине, не связанной с получателем (сессия или провайдер). Повторите через короткую паузу; если ошибка не уходит, проверьте статус подключения. |
| 429 | warmup_limited | Почасовой лимит прогрева для нового номера qr. Делайте паузу в несколько минут. |
| 429 | rate_limited | Защита от злоупотреблений. Учитывайте Retry-After, если он есть; в любом случае держите паузу по умолчанию. |
| 502 | pairing_code_unavailable | Обычная ситуация, не сбой — переключитесь на QR-код. |
Retry-After приходит не в каждом ответе 409/429, поэтому не стройте паузу
между повторами только на нём.
Идемпотентность для POST /connections
Создание подключения запускает сессию WhatsApp и занимает платный слот. Если
клиент получит тайм-аут и повторит запрос, он создаст второе подключение, и вы
незаметно заплатите за два слота для одного клиента. Необязательный заголовок
Idempotency-Key закрывает эту лазейку. Он поддерживается только в
POST /connections; если его не передавать, поведение остаётся прежним.
Ключ — любая непрозрачная строка длиной до 255 символов. Он привязан к вашему рабочему пространству (два партнёра с одинаковой строкой никогда не пересекутся) и действует 24 часа с первого запроса, в котором был использован.
201 Created.200 OK и заголовок ответа Idempotency-Replayed: true. Значение qr в этом ответе запрашивается заново, а не берётся из сохранённого при первом создании: коды сопряжения меняются примерно каждые 20 секунд, поэтому устаревший QR просто не отсканируется. Считайте 200 успехом, а не ошибкой.400 { "error": "idempotency_key_reuse" }. Сравнивается хеш канонического тела, поэтому порядок ключей JSON не имеет значения.409 { "error": "idempotency_in_progress" } с Retry-After: 1. Учтите его и повторите запрос с тем же ключом.Ключ длиннее 255 символов отклоняется с ошибкой
400 { "error": "idempotency_key_invalid" } — он никогда не обрезается. Пустой
заголовок или заголовок из одних пробелов считается отсутствующим. Структура
тела ответа во всех случаях не меняется.
Создавайте один ключ на каждую попытку подключения клиента
Новый UUID (crypto.randomUUID()), созданный непосредственно перед вызовом и
используемый только в повторах этого вызова. Не используйте один ключ на
процесс, на API key, на день или константу. При таком грубом ключе второму
подключаемому клиенту вернётся подключение первого вместо его собственного.
Идемпотентность при отправке
POST /messages принимает idempotencyKey в теле запроса (не в заголовке).
Передавайте его всегда — по одному UUID на каждую логическую отправку.
- При любой ошибке или тайм-ауте повторяйте запрос с тем же ключом. Новый ключ означает второе настоящее сообщение WhatsApp на чужом телефоне.
- При
409 in_progressопрашивайте с тем же ключом: учитывайтеRetry-After, если он есть, иначе делайте паузу около 5 с. - Медленная отправка — не неудачная отправка. Установите HTTP-тайм-аут не менее 180 с.