Переезжай на Whapi · от 500 ₽/мес Наш WhatsApp API работает штатно Регистрация
Запись на приём · сценарий WhatsApp API

Пусть клиенты выбирают время визита в WhatsApp из списка

Клиенты быстрее завершают запись, когда нажимают на понятное время, а не переписываются текстом. Когда ваш поток бронирования доходит до шага выбора времени, backend может отправить POST с интерактивным списком в чат клиента через Whapi.Cloud. Этот сценарий показывает интеграторам, как собрать такой поток через WhatsApp API.

type list с до десяти строк слотов Выбор приходит как list_reply на messages.post
Панель разработчика рядом с телефоном: чат записи в WhatsApp и открытый интерактивный список времён приёма.
Сценарий

Когда использовать этот поток

Свободные слоты уже в вашем расписании

Используйте этот поток, когда own_backend уже знает, какие времена визита свободны, и нужно только, чтобы клиент выбрал одно в чате.

Запись остаётся в личном чате WhatsApp

Используйте этот поток, когда клиент записывается в direct_chat с вашим business-номером, а не в группе или на канале.

Нужен структурированный тап вместо свободного текста

Используйте этот поток, когда «вторник 15:00» в свободном тексте даёт ошибки, а вы хотите строку списка со стабильным id слота, который backend может забронировать.

Чат WhatsApp на телефоне с интерактивным списком времён визита и выбранным слотом, выделенным как отправленный ответ.
Опыт клиента

Клиент нажимает свободный слот

До автоматизации клиенты угадывают время текстом, а сотрудники вручную сверяют календарь.

Когда список приходит, клиент открывает меню, нажимает строку и видит свой выбор отправленным в том же чате. Интеграторы строят такой результат через WhatsApp API.

Поток

От свободных слотов к захваченному id

1

Записи нужен выбор времени

Логика расписания в own_backend доходит до шага, где клиент должен выбрать из текущих свободных времён визита.

2

Отправьте list-сообщение со слотами

POST /messages/interactive

POST на /messages/interactive с type list, текстами header/body/footer и строками в action.list.sections (title, id, description) из свободных слотов—обычно до десяти строк в одной секции. Сопоставьте каждый id строки с ключом слота, который backend может забронировать (например slot-2026-04-02-10-00).

Нужен тап клиента в вашем webhook? После отправки списка слушайте входящий ответ на webhook канала. Подробнее о статусе доставки →

Предварительные требования

Перед запуском потока

Подключите номер WhatsApp, который будет отправлять списки записи, к Whapi.Cloud и используйте API-токен этого канала в sendMessageInteractive. Входящие события list_reply требуют URL webhook на том же канале.

По желанию — углубиться в этот поток

Реализация API

Соберите list-запрос шаг за шагом

Один POST доставляет меню. Установите type в list, заполните header, body и footer, затем action.list с подписью кнопки и sections[].rows—каждая строка нуждается в title, id и необязательном description, привязанном к свободному слоту из backend.

Получите API-токен бесплатно после регистрации на whapi.cloud и подставьте его в код вместо Your_Token из примеров.

Отправьте list-сообщение со слотами

Отправьте интерактивный список (type list) клиенту с до десяти строк слотов; клиент открывает меню через action.list.label и нажимает строку.

curl --request POST \
     --url https://gate.whapi.cloud/messages/interactive \
     --header 'accept: application/json' \
     --header 'authorization: Bearer Your_Token' \
     --header 'content-type: application/json' \
     --data '
{
  "to": "447123456789",
  "type": "list",
  "header": {
    "text": "Choose a visit time"
  },
  "body": {
    "text": "Tap View times and pick an open slot for your visit."
  },
  "footer": {
    "text": "Clinic bookings via WhatsApp"
  },
  "action": {
    "list": {
      "label": "View times",
      "sections": [
        {
          "title": "Available slots",
          "rows": [
            {
              "id": "slot-2026-04-02-10-00",
              "title": "Wed 10:00",
              "description": "Open \u00b7 Dr. Lee"
            },
            {
              "id": "slot-2026-04-02-11-30",
              "title": "Wed 11:30",
              "description": "Open \u00b7 Dr. Lee"
            },
            {
              "id": "slot-2026-04-02-14-00",
              "title": "Wed 14:00",
              "description": "Open \u00b7 Dr. Lee"
            }
          ]
        }
      ]
    }
  }
}
'
$curl = curl_init();

curl_setopt_array($curl, [
  CURLOPT_URL => "https://gate.whapi.cloud/messages/interactive",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_POSTFIELDS => "{\"to\": \"447123456789\", \"type\": \"list\", \"header\": {\"text\": \"Choose a visit time\"}, \"body\": {\"text\": \"Tap View times and pick an open slot for your visit.\"}, \"footer\": {\"text\": \"Clinic bookings via WhatsApp\"}, \"action\": {\"list\": {\"label\": \"View times\", \"sections\": [{\"title\": \"Available slots\", \"rows\": [{\"id\": \"slot-2026-04-02-10-00\", \"title\": \"Wed 10:00\", \"description\": \"Open \\u00b7 Dr. Lee\"}, {\"id\": \"slot-2026-04-02-11-30\", \"title\": \"Wed 11:30\", \"description\": \"Open \\u00b7 Dr. Lee\"}, {\"id\": \"slot-2026-04-02-14-00\", \"title\": \"Wed 14:00\", \"description\": \"Open \\u00b7 Dr. Lee\"}]}]}}}",
  CURLOPT_HTTPHEADER => [
    "accept: application/json",
    "authorization: Bearer Your_Token",
    "content-type: application/json"
  ],
]);

$response = curl_exec($curl);
curl_close($curl);
echo $response;
import requests

url = "https://gate.whapi.cloud/messages/interactive"
payload = {
    "to": "447123456789",
    "type": "list",
    "header": {
        "text": "Choose a visit time"
    },
    "body": {
        "text": "Tap View times and pick an open slot for your visit."
    },
    "footer": {
        "text": "Clinic bookings via WhatsApp"
    },
    "action": {
        "list": {
            "label": "View times",
            "sections": [
                {
                    "title": "Available slots",
                    "rows": [
                        {
                            "id": "slot-2026-04-02-10-00",
                            "title": "Wed 10:00",
                            "description": "Open \u00b7 Dr. Lee"
                        },
                        {
                            "id": "slot-2026-04-02-11-30",
                            "title": "Wed 11:30",
                            "description": "Open \u00b7 Dr. Lee"
                        },
                        {
                            "id": "slot-2026-04-02-14-00",
                            "title": "Wed 14:00",
                            "description": "Open \u00b7 Dr. Lee"
                        }
                    ]
                }
            ]
        }
    }
}
headers = {
    "accept": "application/json",
    "authorization": "Bearer Your_Token",
    "content-type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)
print(response.text)
const response = await fetch('https://gate.whapi.cloud/messages/interactive', {
  method: 'POST',
  headers: {
    accept: 'application/json',
    authorization: 'Bearer Your_Token',
    'content-type': 'application/json',
  },
  body: JSON.stringify({"to": "447123456789", "type": "list", "header": {"text": "Choose a visit time"}, "body": {"text": "Tap View times and pick an open slot for your visit."}, "footer": {"text": "Clinic bookings via WhatsApp"}, "action": {"list": {"label": "View times", "sections": [{"title": "Available slots", "rows": [{"id": "slot-2026-04-02-10-00", "title": "Wed 10:00", "description": "Open \u00b7 Dr. Lee"}, {"id": "slot-2026-04-02-11-30", "title": "Wed 11:30", "description": "Open \u00b7 Dr. Lee"}, {"id": "slot-2026-04-02-14-00", "title": "Wed 14:00", "description": "Open \u00b7 Dr. Lee"}]}]}}}),
});

console.log(await response.text());
OkHttpClient client = new OkHttpClient();

MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, "{\"to\": \"447123456789\", \"type\": \"list\", \"header\": {\"text\": \"Choose a visit time\"}, \"body\": {\"text\": \"Tap View times and pick an open slot for your visit.\"}, \"footer\": {\"text\": \"Clinic bookings via WhatsApp\"}, \"action\": {\"list\": {\"label\": \"View times\", \"sections\": [{\"title\": \"Available slots\", \"rows\": [{\"id\": \"slot-2026-04-02-10-00\", \"title\": \"Wed 10:00\", \"description\": \"Open \\u00b7 Dr. Lee\"}, {\"id\": \"slot-2026-04-02-11-30\", \"title\": \"Wed 11:30\", \"description\": \"Open \\u00b7 Dr. Lee\"}, {\"id\": \"slot-2026-04-02-14-00\", \"title\": \"Wed 14:00\", \"description\": \"Open \\u00b7 Dr. Lee\"}]}]}}}");
Request request = new Request.Builder()
  .url("https://gate.whapi.cloud/messages/interactive")
  .post(body)
  .addHeader("accept", "application/json")
  .addHeader("authorization", "Bearer Your_Token")
  .addHeader("content-type", "application/json")
  .build();

Response response = client.newCall(request).execute();
using RestSharp;

var options = new RestClientOptions("https://gate.whapi.cloud/messages/interactive");
var client = new RestClient(options);
var request = new RestRequest("");
request.AddHeader("accept", "application/json");
request.AddHeader("authorization", "Bearer Your_Token");
request.AddHeader("content-type", "application/json");
request.AddJsonBody(System.Text.Json.JsonSerializer.Deserialize<object>(@"{\"to\": \"447123456789\", \"type\": \"list\", \"header\": {\"text\": \"Choose a visit time\"}, \"body\": {\"text\": \"Tap View times and pick an open slot for your visit.\"}, \"footer\": {\"text\": \"Clinic bookings via WhatsApp\"}, \"action\": {\"list\": {\"label\": \"View times\", \"sections\": [{\"title\": \"Available slots\", \"rows\": [{\"id\": \"slot-2026-04-02-10-00\", \"title\": \"Wed 10:00\", \"description\": \"Open \\u00b7 Dr. Lee\"}, {\"id\": \"slot-2026-04-02-11-30\", \"title\": \"Wed 11:30\", \"description\": \"Open \\u00b7 Dr. Lee\"}, {\"id\": \"slot-2026-04-02-14-00\", \"title\": \"Wed 14:00\", \"description\": \"Open \\u00b7 Dr. Lee\"}]}]}}}"));
var response = await client.PostAsync(request);

Console.WriteLine("{0}", response.Content);
package main

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
)

func main() {
	body := []byte(`{"to": "447123456789", "type": "list", "header": {"text": "Choose a visit time"}, "body": {"text": "Tap View times and pick an open slot for your visit."}, "footer": {"text": "Clinic bookings via WhatsApp"}, "action": {"list": {"label": "View times", "sections": [{"title": "Available slots", "rows": [{"id": "slot-2026-04-02-10-00", "title": "Wed 10:00", "description": "Open \u00b7 Dr. Lee"}, {"id": "slot-2026-04-02-11-30", "title": "Wed 11:30", "description": "Open \u00b7 Dr. Lee"}, {"id": "slot-2026-04-02-14-00", "title": "Wed 14:00", "description": "Open \u00b7 Dr. Lee"}]}]}}}`)
	req, _ := http.NewRequest("POST", "https://gate.whapi.cloud/messages/interactive", bytes.NewReader(body))
	req.Header.Set("accept", "application/json")
	req.Header.Set("authorization", "Bearer Your_Token")
	req.Header.Set("content-type", "application/json")

	res, _ := http.DefaultClient.Do(req)
	defer res.Body.Close()
	out, _ := io.ReadAll(res.Body)
	fmt.Println(string(out))
}
Входящий выбор

Прочитайте слот из list_reply

Webhook статусов доставки по-прежнему относятся к исходящему списку. Решение о записи приходит отдельно на messages.post, когда клиент нажимает строку—ищите reply.type list_reply и reply.list_reply.id (плюс title/description), чтобы сопоставить с id строки.

  • Настройте webhook канала до тестов нажатий; в payload есть event.type messages и event.event post.

  • Сопоставьте reply.list_reply.id с отправленным id строки (Whapi может добавлять префиксы вроде ListV3:r1—нормализуйте в own_backend).

  • Если слот уже занят, когда приходит webhook, не пишите в календарь; отправьте обновлённый список или передайте сотрудникам согласно failure_mode.

Что почитать про доставку и webhook

Напишите в поддержку, если что-то пошло не так
Когда что-то ломается

Обрабатывайте сбои на каждом шаге

Если sendMessageInteractive падает после триггера записи, клиент не видит список слотов—повторите отправку или предупредите сотрудников, прежде чем считать, что время выбрано.

Когда список так и не доходит до клиента

Неудачная отправка, запрещённый получатель или отсутствующая media-ссылка оставляют клиента без строк для нажатия. Повторите с корректными параметрами, проверьте chat id в to и вернитесь к ручной записи, если окно слотов закрылось. Обратитесь в поддержку Whapi, если отправки стабильно падают с 401 или 500 на исправном канале.

Напишите в поддержку, если что-то пошло не так

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

Статус Что означает Что делать
400 Wrong request parameters Исправьте форму list payload—type list, body.text, action.list.label и минимум одна строка с title и id по OpenAPI.
401 Need channel authorization for send message Передайте Bearer token канала; убедитесь, что номер всё ещё сопряжён в панели.
402 Trial version limit exceeded
403 It is forbidden to send to this group/recipient Убедитесь, что получатель разрешён на этом канале и chat id верный.
429 Too many requests Подождите и повторите; не шлите пачками тот же список слотов.
500 Internal Error
Частые вопросы

Слоты в списке и id в webhook

Заложите до десяти строк суммарно по секциям—достаточно для меню на сегодня или ближайшие дни. Если свободных слотов больше, разбейте на новый список после выбора даты или попросите own_backend сузить набор перед отправкой.
Установите type в list, текстовые объекты в header, body и footer, вложите action.list с label и sections[].rows (каждая строка нуждается в title, id и необязательном description). Укажите телефон клиента в to—та же форма, что в эталонном curl оператора для /messages/interactive.
На messages.post читайте reply.list_reply.id и reply.list_reply.title. Сопоставьте id с id строки, который вы задали при сборке списка, затем забронируйте или зарезервируйте слот в own_backend.
Обработайте как failure_mode из каталога—отправьте обновлённый список, отмените устаревшие id строк или передайте чат сотрудникам. Не подтверждайте визит в календаре без свежего list_reply или ручной проверки.
Поддерживаемые функции WhatsApp

Всё, что нужно для создания автоматизации WhatsApp

Whapi.Cloud предоставляет доступ к полному набору функций WhatsApp — сообщениям, медиа, группам, каналам, вебхукам и не только. Создавайте ботов, автоматизации и интеграции без функциональных ограничений.

Выбор разработчиков

Нам доверяют 3 300+ разработчиков и SaaS-команд

Разработчики по всему миру используют Whapi.Cloud для создания автоматизаций, ботов, CRM-интеграций, массовых рассылок и продвинутых WhatsApp-воркфлоу. Наша инфраструктура обрабатывает миллионы API-запросов с высокой стабильностью — и этот показатель растёт каждый месяц.

Иконка функции

5,5K+

активных API-каналов

Иконка функции

21M+

API-запросов в месяц

«Всё просто, интуитивно и легко. Документация понятная, и вся нужная информация всегда под рукой. Отличная работа.»

Roberto K. / Web-разработчик

«Мы подключили WhatsApp к нашим процессам через n8n всего за несколько минут. Без кода, без сложностей — всё заработало с первого раза.»

Martin P. / Разработчик

«Whapi.Cloud стал важной частью нашей коммуникации с клиентами. Мы автоматизировали обновления по продуктам, уведомления о заказах и поддержку — без шаблонов и модерации.»

Oscar T. / CTO

Декоративный пузырь