Интеграции

Возврат брошенных корзин голосовым ИИ-агентом

← Все статьи

Человек зашёл в магазин, собрал корзину, нажал «оформить» — и пропал на шаге оплаты. Классика: отвлёкся, засомневался, не прошла карта, решил «подумаю вечером» и забыл. Это не холодный лид. Это человек, который минуту назад хотел купить и почти купил.

Стандартный ответ — письмо «вы забыли товар в корзине». Его открывают редко и ещё реже по нему возвращаются. А теперь представьте, что через десять минут после ухода раздаётся звонок: «Здравствуйте! Вы у нас собирали корзину — всё в порядке, ничего не помешало оформить?» На это реагируют иначе.

Соберём такую интеграцию целиком. Голосовой ИИ-агент, который на звонке сам подтягивает состав корзины из вашего API, разговаривает с клиентом, а итог отправляет менеджерам в Telegram. Весь код — ниже, повторяется за вечер.

Что получится

1
Магазин видит брошенную корзину и одним запросом запускает звонок в AutoCall.kz
2
ИИ-агент звонит клиенту и в начале разговора дёргает GET /cart вашего магазина по номеру — узнаёт, что в корзине
3
Разговор: агент выясняет, почему не оформлено, помогает, при желании клиента шлёт SMS со ссылкой на оплату
4
Итог прилетает на ваш callback_url, а оттуда — аккуратной карточкой в Telegram-группу менеджеров

Обратите внимание на второй шаг: агент не получает корзину заранее — он сам запрашивает её у вас во время звонка. Это делает агента одним на весь магазин: он не привязан к конкретному заказу, а каждый раз узнаёт актуальную корзину по номеру звонящего.

Шаг 1. Создаём агента — один раз

Агент создаётся единожды и потом обслуживает все звонки. Внутри у него три части: сценарий разговора (prompt), поля, которые он должен вынести (data_schema), и инструменты (tools) — запрос корзины и отправка SMS.

POST
/api/v1/agents
POST https://autocall.kz/api/v1/agents Authorization: Bearer {ваш_токен} Content-Type: application/json { "name": "Аружан", "voice": "Sulafat", // голоса — GET /api/v1/agents/voices "max_seconds": 180, "client_id": "cart-recovery", "prompt": "## Кто ты\nАружан — женский голос интернет-магазина «SHOP». Звонишь клиенту,\nкоторый собрал корзину и начал оформление, но не оплатил. Характер:\nдоброжелательная, лёгкая, без давления. Ты помощник, а не продавец.\n\n## Задача звонка\nПонять, почему заказ не завершён, и помочь довести до конца, если человек\nэтого хочет. Не хочет — вежливо попрощаться и не давить.\n\n## Ход разговора\n1. Первая фраза РОВНО: «Здравствуйте! Это Аружан из магазина SHOP.\n Вы недавно собирали у нас корзину — удобно сейчас говорить?»\n2. Сразу после приветствия узнай состав корзины через инструмент.\n3. Назови, что в корзине, и мягко спроси, всё ли в порядке, не помешало\n ли что-то оформить.\n4. Техническая проблема (не прошла оплата, вопрос по доставке) — предложи\n помощь; если клиент готов вернуться, отправь ссылку на оплату.\n5. Передумал или просто смотрел — спокойно прими, поблагодари, попрощайся.\n\n## Границы\nНе дави и не уговаривай после отказа. Скидок, которых нет, не обещай.\nО товаре и цене говори только то, что вернул инструмент.", "data_schema": [ { "key": "outcome", "label": "Итог" }, // готов оформить / передумал / нужна помощь / перезвонить { "key": "reason", "label": "Причина" }, // почему не завершил оформление { "key": "comment", "label": "Комментарий" } ], "tools": [ { "type": "http", "name": "order", // агент вызовет это как функцию call_order "when": "сразу после приветствия, чтобы узнать состав корзины", "method": "GET", "url": "https://shop.kz/api/cart?phone={{phone}}", "headers": [{ "key": "Authorization", "value": "Bearer SHOP_TOKEN" }], "response_template": "В корзине: {{items}} на сумму {{total}} тенге.", "fallback": "Заказ поднять не удалось, но давайте разберёмся вместе." }, { "type": "sms", "name": "link", // функция send_sms_link "when": "если клиент готов вернуться к оформлению", "text": "Ваша корзина ждёт вас: https://shop.kz/cart" } ] }

Несколько вещей, которые стоит проговорить.

Секции промпта обязательны. ## Кто ты, ## Задача звонка и ## Ход разговора должны присутствовать — без них создание агента вернёт 422. Правила безопасности мы дописываем сами, в промпт их включать не нужно.

Инструмент order — это и есть та самая интеграция. Во время звонка агент вызовет его как функцию, мы сходим GET на ваш магазин, подставив в URL {{phone}} — номер звонящего. Что вернёт ваш сервер, агент озвучит по шаблону response_template. Подробнее про подстановку — чуть ниже.

Ответ придёт со статусом generating. Агент не готов сразу — пару секунд мы считаем его параметры. Дождитесь ready, опрашивая GET /api/v1/agents/{id}, и запомните id — он понадобится при запуске звонков.

Шаг 2. Ваш магазин отдаёт корзину по номеру

Это единственный эндпоинт, который вам нужно поднять у себя. Агент дёрнет его на звонке. Формат ответа определяете вы — важно лишь, чтобы имена полей совпали с теми, что стоят в response_template агента ({{items}} и {{total}}).

GET
ваш магазин · /api/cart
GET https://shop.kz/api/cart?phone=77010000000 ← 200 OK { "items": "робот-пылесос Samsung и набор насадок", "total": "45 000" }

Мы возьмём этот JSON, подставим items и total в шаблон, и агент произнесёт: «В корзине: робот-пылесос Samsung и набор насадок на сумму 45 000 тенге». Если ваш сервер не ответит или вернёт не то — агент скажет fallback и продолжит разговор, звонок не оборвётся.

Эндпоинт ходит в публичный интернет, поэтому закройте его токеном (мы отправим ваш Authorization из настроек инструмента) и отдавайте по номеру только состав корзины — без адресов, карт и прочего лишнего.

Шаг 3. Ловим брошенную корзину и запускаем звонок

Теперь сторона магазина. Когда ваша система решила, что корзина брошена (скажем, прошло 10 минут после шага оплаты без успеха) — один запрос запускает звонок.

Python
shop_backend.py
import requests AUTOCALL_TOKEN = "ваш_токен_autocall" AGENT_ID = 42 # id готового агента из шага 1 def call_about_cart(phone: str, name: str): requests.post( "https://autocall.kz/api/v1/autocalls", headers={"Authorization": f"Bearer {AUTOCALL_TOKEN}"}, json={ "name": "Возврат корзины", "type": "agent", "agent_id": AGENT_ID, "time_from": "10:00:00", # звоним только в приличные часы "time_to": "20:00:00", "max_tries": 1, # один звонок, не долбим "callback_url": "https://your-service.kz/autocall/callback", "list_id": [ { "number": phone, "variables": {"phone": phone.lstrip("+"), "name": name} } ] } )

Здесь весь фокус — в variables. Ключ phone оттуда и подставится в {{phone}} URL-а инструмента, когда агент полезет за корзиной. Что положите в переменные — тем инструмент и сможет пользоваться.

Тот же запрос через curl, если ваш бэкенд не на Python:

cURL
запуск звонка
curl -X POST https://autocall.kz/api/v1/autocalls \ -H "Authorization: Bearer ваш_токен" \ -H "Content-Type: application/json" \ -d '{ "name": "Возврат корзины", "type": "agent", "agent_id": 42, "time_from": "10:00:00", "time_to": "20:00:00", "max_tries": 1, "callback_url": "https://your-service.kz/autocall/callback", "list_id": [{ "number": "+77010000000", "variables": { "phone": "77010000000", "name": "Айгерим" } }] }'

Шаг 4. Готовим Telegram-бота

Бот нужен, чтобы писать итог в группу менеджеров. Три коротких действия:

  1. Напишите @BotFather команду /newbot, задайте имя — в ответ получите токен вида 7712345678:AAExxxxxxxxxxxx.
  2. Добавьте бота в вашу рабочую группу и дайте право писать сообщения.
  3. Узнайте chat_id группы: временно добавьте в неё @getidsbot или откройте https://api.telegram.org/bot{ТОКЕН}/getUpdates — id группы будет отрицательным числом.

Шаг 5. Принимаем результат и пишем в Telegram

Осталось поднять маленький сервис, который примет наш callback и переложит его в сообщение. Мы дёргаем callback_url на каждое изменение звонка, поэтому первым делом — отфильтровать финал разговора от промежуточных событий.

Надёжный признак «разговор состоялся» — последний элемент массива status_tries равен success. Тогда в data уже лежат поля, которые собрал агент.

Python
callback_service.py
from flask import Flask, request import requests app = Flask(__name__) BOT_TOKEN = "7712345678:AAExxxxxxxxxxxx" CHAT_ID = "-1001234567890" # id группы менеджеров @app.post("/autocall/callback") def callback(): call = request.json.get("call", {}) tries = call.get("status_tries") or [] # звонок ещё идёт или не дозвонились — ждём финала, ничего не шлём if not tries or tries[-1] != "success": return "", 204 data = call.get("data") or {} text = ( "🛒 Недобитая корзина — итог звонка\n\n" f"📞 {call.get('number', '—')} · {call.get('duration', 0)} сек\n\n" f"Итог: {data.get('outcome', '—')}\n" f"Причина: {data.get('reason', '—')}\n" f"Комментарий: {data.get('comment', '—')}" ) requests.post( f"https://api.telegram.org/bot{BOT_TOKEN}/sendMessage", json={"chat_id": CHAT_ID, "text": text, "parse_mode": "HTML"} ) return "", 204

Запускается как обычное Flask-приложение за любым обратным прокси с HTTPS. Адрес /autocall/callback — ровно тот, что вы указали в callback_url при запуске звонка.

Если хотите класть результат ещё и в CRM, а не только в чат — callback для этого же и предназначен. В data лежат все поля из data_schema плюс data["_transcript"] — полная расшифровка разговора, если она вам нужна.

Как это звучит на звонке

Живой разговор
АружанЗдравствуйте! Это Аружан из магазина SHOP. Вы недавно собирали у нас корзину — удобно сейчас говорить?
КлиентЭ-э, да, а что там?
Аружан(вызывает call_order, магазин отвечает) Секундочку, подниму ваш заказ… Вижу: робот-пылесос Samsung и набор насадок на 45 000. Всё верно, ничего не помешало оформить?
КлиентДа я хотел, но карта почему-то оплату отклонила, я и бросил.
АружанПонимаю, бывает. Могу прислать вам ссылку на оплату SMS — попробуете другой картой или Kaspi, как удобнее. Отправить?
КлиентДа, давайте.
Аружан(вызывает send_sms_link) Отправила. Там же ваша корзина, всё сохранилось. Спасибо, что уделили время!

А менеджеры в этот момент получают в группу вот такую карточку:

🛒 Недобитая корзина — итог звонка
📞 +7 701 000 00 00 · 58 сек
Итог: готов оформить, отправлена ссылка
Причина: не прошла оплата картой
Комментарий: попробует Kaspi

Менеджеру не нужно слушать запись и гадать — агент уже разложил разговор по полям. Видно, кто реально хотел купить и на чём споткнулся, а кто просто смотрел.

Тонкости, без которых будет плохо

Звоните один раз и в приличное время. В запросе стоят max_tries: 1 и окно 10:00–20:00 не случайно. Тёплый лид превращается в раздражённого человека ровно в тот момент, когда вы звоните ему второй раз или в девять вечера.

Фильтруйте не только success. Если последний status_triesno_answer или busy, разговора не было и полей в data не будет. Такие события можно просто игнорировать, а можно по ним отправить то самое письмо «вы забыли корзину» — теперь уже как запасной канал.

Не звоните тем, кто не давал номер осознанно. Здесь всё чисто: клиент сам ввёл телефон на оформлении заказа и сам начал покупку. Это не купленная база и не холодный обзвон — именно поэтому такой звонок работает и не выглядит навязчивым. Не переносите эту механику на аудиторию, которая вас об этом не просила.

Проверьте на себе. Прежде чем пускать на клиентов, запустите звонок на свой номер с тестовой корзиной. И отдельно — кнопка «Протестировать» в карточке агента звонит вам в браузер, чтобы вживую услышать, как он говорит, ещё до первого реального звонка.

Что дальше

Мы собрали одну связку, но кубики переиспользуемы. Тот же callback_url кладёт данные в CRM, тот же HTTP-инструмент агента ходит не только за корзиной, а за чем угодно в вашей системе, тот же запуск звонка вешается на любое событие — не только на брошенную корзину, но и на «заявка без ответа сутки», «подписка заканчивается», «доставка приехала».

Полная спецификация методов — в openapi.yaml, обзор с примерами — на странице API и интеграции. А про то, как устроен сам агент и чем он отличается от сценария, мы писали отдельно.

Соберите свою интеграцию

Получите API-токен и запустите первого агента сегодня.

Попробовать бесплатно →