Перейти к содержанию

gRPC WhatsApp* API#

gRPC WhatsApp API — описание всех методов сервиса GREEN-API в формате Protobuf, из которого генерируется готовый gRPC-клиент под нужный язык: Go, Python, Java, C++, C#, JS/TS.

gRPC-клиенты по языкам#

  • gRPC-клиент на Go — установка, подключение и его проверка, выгрузка файла, получение QR-кода

  • gRPC-клиент на Python — установка, подключение и его проверка, выгрузка файла, получение QR-кода

Структура gRPC-контракта#

Контракт — это набор .proto-файлов, в которых заданы все методы сервиса GREEN-API, а также типы запросов и ответов к ним. Из контракта генерируется готовый gRPC-клиент под нужный язык, поэтому вызовы методов, сериализация и проверка типов не пишутся вручную. Чтобы воспользоваться API, нужно получить apiTokenInstance и idInstance в личном кабинете. Для тестирования рекомендуем воспользоваться бесплатным тарифом "Разработчик".

API#

Документация REST API доступна по ссылке. gRPC-контракт содержит соответствующие методы, поэтому описание их назначения и параметров также применимо к gRPC API.

В .proto-файлах сервисов для каждого метода добавлены комментарии со ссылками на соответствующую документацию. Благодаря этому описание метода можно открыть непосредственно из редактора кода.

Структура пакетов#

Методы сгруппированы по доменам. Для каждого домена предусмотрен отдельный каталог в proto/greenapi/.

Каталог Описание
type/v1/ Общие типы: File, Contact, варианты содержимого сообщения, enum'ы — переиспользуются во всех доменах ниже
instance/v1/ Настройка и авторизация инстанса, получение QR-кода/номера телефона и состояния инстанса
message/v1/ Отправка, редактирование, удаление сообщений; история чата; исходящая очередь отправки
contact/v1/ Работа с контактами: добавление, изменение, удаление, поиск контакта и получение аватара
chat/v1/ Работа с чатами: получение списка, архивирование, отключение звука, статус «печатает», отметки о прочтении
group/v1/ Управление групповыми чатами
status/v1/ Работа со статусами WhatsApp (историями)
notification/v1/ Получение уведомлений через webhook/long polling и работа с очередью уведомлений
call/v1/ История входящих и исходящих звонков

Каждый домен версионируется независимо: v1 относится к пакету, а не ко всему контракту. Поэтому изменение в одном домене не требует поднимать версию во всех остальных.

Единый формат сообщения#

Содержимое сообщения описано в одном месте — в type/v1/message_payload.proto. Тип MessageData использует oneof и объединяет все поддерживаемые типы содержимого сообщения.

MessageData используется как в HistoryMessage из message/v1 для представления сообщений из истории чата, так и в MessageNotification из notification/v1 для уведомлений, получаемых через webhook и long polling. Благодаря единому формату одно и то же сообщение может обрабатываться одним и тем же кодом независимо от источника — истории чата или потока уведомлений.

Авторизация в gRPC API#

Чтобы отправлять сообщения и вызывать другие методы GREEN-API, инстанс должен быть авторизован в WhatsApp. Авторизовать инстанс можно в личном кабинете, отсканировав QR-код в приложении WhatsApp на телефоне, либо программно — с помощью метода ScanQrCode.

В REST API idInstance и apiTokenInstance передаются в составе URL запроса. В gRPC эти данные передаются в метаданных каждого вызова:

Ключ метадаты Значение
x-instance-id idInstance
authorization Bearer <apiTokenInstance>

Оба значения передаются в каждом вызове: соединение само по себе авторизацию не хранит.

Получить idInstance и apiTokenInstance можно в личном кабинете после создания инстанса.

Если метаданные не переданы или указан неверный токен, вызов завершится со статусом gRPC Unauthenticated. Перечень общих для всех методов ошибок смотрите в разделе Коды ошибок gRPC API.

Метадата авторизует инстанс, но не аккаунт: сам аккаунт WhatsApp должен быть в авторизованном состоянии, иначе методы вернут FailedPrecondition.

Примеры:

Проверка подключения#

Перед выполнением рабочих вызовов рекомендуется проверить соединение с gRPC-сервером и состояние инстанса. Для этого можно использовать метод GetStateInstance сервиса InstanceService, который возвращает текущее состояние инстанса и не изменяет его.

rpc GetStateInstance(GetStateInstanceRequest) returns (GetStateInstanceResponse);

GetStateInstanceRequest не содержит параметров. В ответе возвращается поле state_instance со значением перечисления InstanceState из пакета type/v1.

Если вызов завершился со статусом gRPC OK, соединение с сервером и авторизация выполнены успешно. Значение state_instance позволяет определить текущее состояние инстанса и его готовность к работе.

Результат Описание
INSTANCE_STATE_AUTHORIZED Инстанс авторизован и готов к работе.
INSTANCE_STATE_NOT_AUTHORIZED Инстанс не авторизован в WhatsApp. Отсканируйте QR-код в личном кабинете или получите его с помощью метода ScanQrCode.
INSTANCE_STATE_STARTING Инстанс запускается. Подождите и повторите проверку состояния.
INSTANCE_STATE_BLOCKED, INSTANCE_STATE_SUSPENDED Работа инстанса ограничена. Подробнее см. описание метода GetStateInstance.
ошибка Unauthenticated Не переданы данные авторизации или указаны неверные idInstance / apiTokenInstance. Проверьте значения в личном кабинете.
ошибка Unavailable Не удалось установить соединение с gRPC-сервером. Проверьте адрес сервера. Он должен быть указан в формате grpc.green-api.com:443, без схемы https://.

Примеры:

Потоковые вызовы gRPC API#

Большинство методов gRPC API являются унарными: один запрос — один ответ. Исключение составляют три потоковых метода:

rpc UploadFile(stream UploadFileRequest) returns (UploadFileResponse);
rpc SendFileByUpload(stream SendFileByUploadRequest) returns (SendFileByUploadResponse);
rpc ScanQrCode(ScanQrCodeRequest) returns (stream ScanQrCodeResponse);

UploadFile и SendFileByUpload используют клиентский поток: файл передаётся частями в виде последовательности чанков, а не одним большим сообщением. ScanQrCode использует серверный поток и описан отдельно в разделе Получение QR-кода по gRPC.

Бинарные поля#

Бинарные данные в контракте — например, qr_png, avatar_image, jpeg_thumbnail и File.file — описываются типом bytes. В нативном gRPC такие поля передаются как бинарные данные, без преобразования в Base64.

При использовании JSON-представления поведение отличается: согласно правилам преобразования Protocol Buffers в JSON, поля типа bytes кодируются в Base64. Поэтому grpc-web, grpc-gateway и protojson представляют такие значения в JSON как Base64-строки.

Таким образом, при использовании нативного gRPC бинарные данные передаются непосредственно в бинарном виде, а при JSON-взаимодействии — в виде Base64-строки. Представление в Base64 увеличивает объём данных примерно на 33%.

Контракт выгрузки#

Для обоих методов загрузки используется следующий порядок передачи данных:

  1. Первое сообщение потока содержит UploadFileMetadata с полями file_name и content_type. Метаданные передаются один раз в начале потока.
  2. Все последующие сообщения содержат chunk с очередной частью файла. Сообщения передаются последовательно, а gRPC сохраняет их порядок в рамках одного потока, поэтому передавать дополнительные индексы или смещения для чанков не требуется.
  3. После передачи последнего чанка клиент завершает отправку сообщений (half-close). Это сообщает серверу, что файл передан полностью. После этого сервер обрабатывает полученные данные и возвращает единственный UploadFileResponse, содержащий url_file.

Half-close завершает только отправку данных со стороны клиента в рамках текущего RPC-вызова и не закрывает gRPC-соединение. Сервер по-прежнему может отправить ответ в рамках этого же вызова. Другие RPC-вызовы могут продолжать выполняться по тому же соединению независимо.

Размер чанка#

Рекомендуемый размер чанка — от 32 до 256 КБ. В качестве значения по умолчанию рекомендуется использовать 64 КБ. При меньшем размере чанков накладные расходы на передачу отдельных сообщений могут снижать эффективность, а при слишком большом размере дальнейшее увеличение чанка обычно не даёт заметного прироста скорости из-за ограничений flow control в HTTP/2.

Размер одного чанка не должен превышать 1 МБ. При превышении этого значения вызов завершается со статусом ResourceExhausted. Сервер отклоняет сообщение до обработки его содержимого. При этом завершается только текущий RPC-вызов, а gRPC-соединение остаётся открытым.

После ошибки загрузку необходимо повторить с меньшим размером чанков. Данные, полученные в рамках неуспешного вызова, не сохраняются, и url_file не формируется.

Все чанки не обязаны иметь одинаковый размер. Последний чанк, как правило, меньше остальных. Клиент может передавать данные последовательно по мере их чтения из файла или сокета.

Прерванные загрузки#

Сервер отличает корректное завершение загрузки (half-close) от её прерывания, например при отмене вызова, истечении дедлайна или разрыве соединения. Если загрузка прервана, все данные, полученные в рамках текущего вызова, отбрасываются.

Возобновление прерванной загрузки не поддерживается. Повторную загрузку необходимо начинать с начала. Дополнительная очистка частично загруженных данных со стороны клиента не требуется.

Ограничение grpc-web#

gRPC-Web не поддерживает клиентские потоковые вызовы. Поэтому методы UploadFile и SendFileByUpload, использующие клиентский поток, нельзя вызвать через сгенерированный gRPC-Web-клиент для JavaScript/TypeScript.

Серверные потоковые вызовы в gRPC-Web поддерживаются, поэтому это ограничение не распространяется на метод ScanQrCode.

Примеры:

Получение QR-кода по gRPC#

ScanQrCode — gRPC-аналог WebSocket-метода получения QR-кода GREEN-API. Метод использует серверный поток: сервер отправляет ScanQrCodeResponse каждый раз, когда доступен новый QR-код, и завершает поток после завершения попытки авторизации.

rpc ScanQrCode(ScanQrCodeRequest) returns (stream ScanQrCodeResponse);

Инстанс должен находиться в неавторизованном состоянии. Для одного инстанса одновременно допускается только один активный вызов ScanQrCode; параллельный вызов будет отклонён.

Информация об успешной авторизации не передаётся через поток ScanQrCode. Изменение состояния инстанса приходит отдельным уведомлением stateInstanceChanged в потоке уведомлений, после чего поток ScanQrCode завершается.

Чтобы завершить получение QR-кода раньше, клиент должен отменить текущий RPC-вызов.

Статусы#

Каждое сообщение содержит поле status, которое определяет тип ответа и содержимое остальных полей.

Статус Описание
QR_CODE_STATUS_QR_CODE В поле qr_png передаются бинарные данные PNG-изображения QR-кода. Для отображения в браузере их можно преобразовать в Base64 и использовать, например, в data:image/png;base64,.... Новый QR-код отправляется после истечения срока действия предыдущего.
QR_CODE_STATUS_PASSKEY_REQUIRED Для авторизации требуется passkey вместо сканирования QR-кода.
QR_CODE_STATUS_ALREADY_LOGGED Инстанс уже авторизован. Перед повторным получением QR-кода необходимо выполнить Logout.

Ошибки вызова#

Сообщения WebSocket error и timeout не имеют прямых аналогов в потоке ScanQrCode. В gRPC такие ситуации приводят к завершению RPC-вызова с соответствующим статусом.

Статус FailedPrecondition возвращается, если инстанс не готов к выполнению операции, например находится в состоянии not ready, Instance starting или выполняется процесс выхода из аккаунта (is in the logout process).

Статус DeadlineExceeded возвращается, если в течение примерно 100 секунд QR-код не был отсканирован.

Дополнительное описание ошибки передаётся в тексте gRPC-статуса, поэтому отдельного поля message в ответе нет.

Примеры:

Коды ошибок gRPC API#

Успешный вызов завершается со статусом gRPC OK (code = 0) и возвращает ответное сообщение.

В отличие от REST API, дополнительный статус внутри тела ответа проверять не требуется. Ошибочные вызовы завершаются статусом gRPC, отличным от OK, без ответного сообщения.

Текст ошибки GREEN-API передаётся в поле message gRPC-статуса.

Соответствие HTTP-кодов и статусов gRPC#

HTTP-коды ошибок GREEN-API преобразуются в статусы gRPC следующим образом:

HTTP-код Статус gRPC
400 и прочие 4xx InvalidArgument
401 Unauthenticated
403 FailedPrecondition
404 NotFound
429 ResourceExhausted
466 ResourceExhausted, если код означает превышение лимита
500 Internal
501 и выше Unavailable
503 / недоступность сервиса Unavailable
истечение дедлайна DeadlineExceeded
отмена вызова клиентом Canceled

Когда следует повторять запрос#

Повторный вызов рекомендуется выполнять для статусов ResourceExhausted и Unavailable.

Для ResourceExhausted повтор допустим, если ошибка связана с ограничением частоты запросов (429) или исчерпанием квоты (466). Для Unavailable рекомендуется использовать повторные попытки с увеличивающейся задержкой (backoff).

Ошибки InvalidArgument, Unauthenticated, FailedPrecondition и NotFound, как правило, не устраняются простым повтором запроса. Перед повторным вызовом необходимо устранить причину ошибки. Для методов отправки сообщений действуют отдельные правила — см. Повторная отправка сообщений.

ResourceExhausted также может возвращаться при превышении допустимого размера чанка в потоковой загрузке. В этом случае повтор с backoff не поможет: необходимо уменьшить размер чанка. Подробнее смотрите в разделе Потоковые вызовы gRPC API.

Повторная отправка сообщений#

Методы отправки сообщений, включая SendMessage, SendFileByUrl и SendFileByUpload, не используют ключ идемпотентности. Поэтому сервер не может однозначно определить, является повторный запрос повторной попыткой или новой отправкой, и каждый такой вызов обрабатывается как отдельная операция.

Это особенно важно для ошибок Unavailable, DeadlineExceeded и Canceled: сообщение могло быть принято и отправлено сервером, даже если клиент не получил успешный ответ. Автоматический повтор такого вызова может привести к повторной отправке одного и того же сообщения.

Перед повторной отправкой рекомендуется проверить, не было ли сообщение уже отправлено. Для этого можно использовать методы LastOutgoingMessages и ShowMessagesQueue. Если сообщение отсутствует и среди последних исходящих сообщений, и в очереди отправки, запрос можно выполнить повторно.

Примеры:

Генерация gRPC-клиента#

Получить gRPC-клиент можно двумя способами.

Готовые пакеты. Сгенерированные пакеты публикуются в Buf Schema Registry (BSR) для модуля buf.build/greenapi/whatsapp-api. Для Go их можно подключить с помощью go get; локальная генерация клиента при этом не требуется:

go get buf.build/gen/go/greenapi/whatsapp-api/protocolbuffers/go@latest
go get buf.build/gen/go/greenapi/whatsapp-api/grpc/go@latest

Локальная генерация. Используется, если для нужного языка нет готового пакета или требуется собственная конфигурация генерации. Для проверки protobuf-контрактов и генерации клиентского кода используется buf:

buf lint       # проверка стиля и корректности protobuf-контрактов
buf generate   # генерация клиентского кода

Команда buf generate генерирует клиентский код для Go, JavaScript/TypeScript, Java, C++ и C#/.NET в соответствии с конфигурацией buf.gen.yaml. Сгенерированные файлы помещаются в каталог gen/, который является артефактом сборки и не включается в репозиторий.

Клиентский и серверный код#

Для Go генерируются как клиентский, так и серверный код. Для остальных используемых языков требуется только клиентская часть, однако некоторые плагины генерации создают клиентские и серверные типы совместно. Например, для Java, C++ и C#/.NET вместе с клиентским Stub может генерироваться базовый класс для реализации сервера. При работе с API достаточно использовать клиентский Stub; серверные типы можно не использовать.

gRPC-Web предназначен для клиентской стороны и не предоставляет серверную реализацию. Кроме того, gRPC-Web не поддерживает клиентские потоковые вызовы, поэтому методы UploadFile и SendFileByUpload нельзя вызвать через JavaScript/TypeScript gRPC-Web-клиент. Подробнее см. раздел Потоковые вызовы gRPC API.

Установка плагинов#

Для генерации кода необходимо установить плагины для выбранного языка.

go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
curl -L -o protobuf-javascript.tar.gz \
  https://github.com/protocolbuffers/protobuf-javascript/releases/download/v3.21.4/protobuf-javascript-3.21.4-linux-x86_64.tar.gz
mkdir protobuf-javascript && tar -xzf protobuf-javascript.tar.gz -C protobuf-javascript
sudo mv protobuf-javascript/bin/protoc-gen-js /usr/local/bin/
rm -rf protobuf-javascript.tar.gz protobuf-javascript

curl -L -o protoc-gen-grpc-web \
  https://github.com/grpc/grpc-web/releases/download/1.5.0/protoc-gen-grpc-web-1.5.0-linux-x86_64
chmod +x protoc-gen-grpc-web
sudo mv protoc-gen-grpc-web /usr/local/bin/
GRPC_JAVA_VERSION=1.68.1
curl -L -o protoc-gen-grpc-java \
  "https://repo1.maven.org/maven2/io/grpc/protoc-gen-grpc-java/${GRPC_JAVA_VERSION}/protoc-gen-grpc-java-${GRPC_JAVA_VERSION}-linux-x86_64.exe"
chmod +x protoc-gen-grpc-java
sudo mv protoc-gen-grpc-java /usr/local/bin/
sudo apt install protobuf-compiler-grpc   # Debian/Ubuntu
brew install grpc                         # macOS
GRPC_TOOLS_VERSION=2.66.0
curl -L -o grpc.tools.nupkg \
  "https://www.nuget.org/api/v2/package/Grpc.Tools/${GRPC_TOOLS_VERSION}"
mkdir grpc-tools-extract
unzip -q grpc.tools.nupkg -d grpc-tools-extract
sudo cp grpc-tools-extract/tools/linux_x64/grpc_csharp_plugin /usr/local/bin/
sudo chmod +x /usr/local/bin/grpc_csharp_plugin
rm -rf grpc.tools.nupkg grpc-tools-extract

Для protoc-gen-js в Linux, по крайней мере в версии 3.21.4, пути к сгенерированным файлам могут содержать префикс ./. В этом случае buf выводит предупреждение:

does not conform to the Protobuf generation specification

Предупреждение выводится для каждого такого файла и не препятствует генерации: protoc допускает подобные пути.

Для плагина C# дополнительно используется параметр base_namespace, заданный в buf.gen.yaml. Он позволяет распределять сгенерированные файлы по каталогам в соответствии с пространствами имён и предотвращать конфликты файлов с одинаковыми именами из разных пакетов.

Python#

Python не включён в текущую конфигурацию buf generate. Для генерации Python-кода используется пакет grpcio-tools, который запускается напрямую через python3 -m grpc_tools.protoc:

python3 -m venv .venv
.venv/bin/pip install grpcio-tools
.venv/bin/python3 -m grpc_tools.protoc -I proto \
  --python_out=gen/python --grpc_python_out=gen/python \
  $(find proto -name "*.proto")

В результате генерации создаются Python-модули для protobuf-сообщений и gRPC-сервисов. В файле _grpc.py содержатся клиентский Stub и серверный класс Servicer.

Для работы с GREEN-API требуется только клиентский Stub; серверный класс Servicer можно не использовать.

Совместимость версий#

Каждый домен версионируется независимо: версия v1 относится к конкретному пакету, а не ко всему контракту. Поэтому изменение одного домена не требует изменения версий остальных доменов.

Проверить, нарушает ли изменение обратную совместимость с уже сгенерированным клиентским кодом, можно с помощью команды buf breaking:

buf breaking --against '.git#branch=master'
buf breaking --against '.git#tag=v1.2.0'

Команда сравнивает текущую версию protobuf-контрактов с указанной Git-веткой или тегом и выявляет несовместимые изменения, например удаление полей, изменение их типов, переименование RPC-методов и другие изменения, нарушающие обратную совместимость.

Документация по методам сервиса#