Подключение входа по звонку к вашему сайту: сайт открывает окно авторизации, пользователь звонит на выданный номер, сервис подтверждает звонок.
Сайт подключается в личном кабинете: Обзор → карточка сайта → «Настройки». Ключи показываются один раз, при активации (потеряли — выпустите новые, старые сразу погаснут):
| Ключ | Для чего |
|---|---|
api_key | Во всех запросах к API |
webhook_secret | Проверка подписи входящих вебхуков |
webhook_url | Адрес приёмника на вашем сайте. Задаётся самим сайтом через POST /api/v1/webhook (см. ниже), в ЛК не вводится — там он показывается для проверки |
Доставка вебхуков включается переключателем «Доставлять вебхуки» в ЛК → Вебхуки (при нескольких сайтах — для выбранного) либо флагом enabled в POST /api/v1/webhook. По умолчанию доставка выключена: события собираются в ЛК, но наружу не уходят. Включите её, когда обработчик на сайте готов принимать запросы.
Домен сайта задаётся при подключении сайта в ЛК и разрешает запросы к API со страниц сайта: поддомены подходят автоматически — для site.ru работают www.site.ru и shop.site.ru. Запросы с сервера без заголовков Origin/Referer проверку не проходят — плагин WordPress, ходящий через wp_remote_post, работает без изменений. ВАЖНО: для адреса вебхука правило строже — только сам домен и его www-форма, поддомены отклоняются (см. /api/v1/webhook).
Базовый адрес: https://входпономеру.рф (punycode: https://xn--b1aed1aeebbgp7ao.xn--p1ai). Если хостинг не поддерживает переписывание путей, используйте форму с параметром r — она равнозначна:
https://входпономеру.рф/api/v2/window
https://входпономеру.рф/index.php?r=/api/v2/window ← то же самое
Так работает любой путь API: /api/v1/diagnostics, /api/v1/webhook, /api/v1/window/123 — все они доступны и как /index.php?r=/api/v1/….
/api/v2/window
Открыть окно и получить номер для звонка
Открывает окно авторизации для конкретного телефона и выдаёт номер пула, на который нужно позвонить. Перед выдачей сервис проверяет баланс/пакет (логины в пакете бесплатны, сверх пакета — по ставке тарифа).
Параметры тело запроса, application/json
| Поле | Тип | Описание |
|---|---|---|
api_key | string | Обязательно. Ваш ключ. |
phone | string | Обязательно. Телефон пользователя. Приводится к цифрам, 8… → 7…. |
window | int | Время окна: 1 = 2 мин, 2 = 3 мин, 3 = 5 мин. |
Ответ 201
{
"window_id": 1287,
"dial_number": "79675550839",
"expires_at": "2026-09-23 12:41:07",
"status": "open",
"window_url": "/api/v1/window/1287"
}
Покажите пользователю dial_number и запомните window_id.
Пример
curl -X POST 'https://входпономеру.рф/api/v2/window' \
-H 'Content-Type: application/json' \
-d '{"api_key":"<ваш api_key>","phone":"79094295569","window":1}'
Ошибки
409 busy | Для этого телефона уже открыто окно. В ответе есть retry_after_seconds — через сколько можно повторить |
409 pool_exhausted | Нет свободных номеров пула |
400 bad_phone | Телефон не 10–16 цифр |
400 bad_window | window не 1, 2 или 3 |
400 insufficient_funds | Пакет входов израсходован и на балансе нет денег на вход: номер не выдаётся, вход не выполняется. В ответе — message (готовый текст для владельца сайта), price_kop (стоимость входа) и amount_kop (текущий баланс). Пополните баланс — входы заработают сразу |
403 blocked | Аккаунт заблокирован; причина — в message. Обратитесь в поддержку |
401 invalid_api_key | Ключ неизвестен или отключён |
403 domain_not_allowed | Запрос пришёл с домена, которого нет в домене сайта ключа (см. выше) |
429 rate_limited | Превышен лимит запросов |
Origin вашего сайта) поддерживаются: сервис отвечает CORS-заголовками для доменов из разрешённого списка. По умолчанию CORS закрыт — основной и рекомендуемый путь запросов со своего сервера.
/api/v1/window/{window_id}
Статус окна — опрос до подтверждения
Опрашивайте раз в секунду, пока не получите matched или expired. Запрос шлите со своего сервера, чтобы ключ не попадал в браузер.
Параметры
| Где | Значение | Описание |
|---|---|---|
| Путь | window_id | Из ответа первого метода |
| Заголовок | X-Api-Key: <ваш api_key> | Обязательно (или параметр api_key) |
Ответ 200
{
"window_id": 1287,
"status": "matched",
"expires_at": "2026-09-23 12:41:07",
"matched_at": "2026-09-23 12:39:52",
"delivery": {
"enabled": true,
"paused": false,
"paused_until": null,
"paused_forever": false,
"paused_seconds_left": null
}
}
Статусы
open | Ждём звонок — продолжать опрос |
matched | Звонок подтверждён — пускать пользователя |
expired | Время вышло — предложить повторить или вход по паролю |
delivery — состояние доставки вебхуков сайта: enabled (включена ли), paused/paused_until/paused_forever/paused_seconds_left (не приостановлена ли предохранителем). Если доставка приостановлена, вебхук не уйдёт — для входа остаётся только опрос; предупредите администратора сайта.
Пример
curl 'https://входпономеру.рф/api/v1/window/1287' \
-H 'X-Api-Key: <ваш api_key>'
/api/v1/diagnostics
Проверка связи и настроек без занятия номера пула
Служебный вызов для страницы настроек плагина: проверяет, жив ли сервис и всё ли настроено. Открытие окна для этого не подходит — оно занимает номер пула на 2+ минуты. Эндпоинт бесплатный: никаких списаний и записей в биллинге.
Параметры
| Где | Значение | Описание |
|---|---|---|
| Заголовок | X-Api-Key: <ваш api_key> | Обязательно (или параметр api_key) |
Ответ 200
{
"ok": true,
"service": true,
"key_valid": true,
"domain_ok": true,
"allowed_domains": ["site.ru"],
"allowed_domain_display": "site.ru",
"balance_kop": 250000,
"tariff": {
"code": "medium",
"name": "Средний",
"monthly_price_kop": 1500000,
"included_webhooks": 15360,
"sites_bonus": 1024,
"included_total": 16384,
"webhooks_used": 120,
"webhooks_left": 16264
},
"webhook": {
"configured": true,
"url_set": true,
"enabled": true,
"paused": false,
"pause_level": 0,
"pause_until": null,
"forever": false
},
"server_time": "2026-09-23 12:00:00",
"window_ttl_seconds": 120
}
domain_ok показывает, применилась ли привязка к домену к этому запросу: true, если запрос пришёл с разрешённого домена или без Origin/Referer вовсе (серверный вызов). allowed_domains — домен сайта, закреплённый за ключом (0–1 запись, в punycode); allowed_domain_display — тот же домен кириллицей для показа человеку; пусто = проверка отключена.
Поля тарифа: included_webhooks — пакет, включённый тарифом; sites_bonus — входы за дополнительные (сверх первого) АКТИВНЫЕ сайты по цене пакета; included_total = их сумма; webhooks_used — израсходовано в текущем расчётном периоде (30 дней); webhooks_left — остаток пакета. Сверх пакета каждый вход списывается по ставке тарифа (см. таблицу).
Тарифы (текущая сетка, этап 18)
| code | Тариф | Абонплата | Входов в пакете | Сверх пакета | Входов за доп. сайт |
|---|---|---|---|---|---|
test | Тест (без тарифа) | 0 ₽/мес | 0 | 5,00 ₽/шт | 200 |
promo | ПРОМО (первый месяц) | 1 399 ₽/мес | 1 024 | 2,50 ₽/шт | 732 |
mini | Мини | 1 999 ₽/мес | 1 024 | 2,50 ₽/шт | 512 |
small | Малый | 4 999 ₽/мес | 3 072 | 2,00 ₽/шт | 614 |
medium | Средний | 15 000 ₽/мес | 15 360 | 1,50 ₽/шт | 1 024 |
business | Бизнес | 69 900 ₽/мес | 102 400 | 1,00 ₽/шт | 1 464 |
corporate | Корпоративный | 349 000 ₽/мес | 1 024 000 | 0,50 ₽/шт | 2 934 |
Ставка сверх пакета плоская — второй ступени «свыше 5000» с отдельной ценой больше нет. Тарифы mobile, tollfree, bonus удалены миграцией 017, коды standart, optimum, maximum переименованы миграцией 018 в mini, small, medium: если в ответе встретился иной code, обновите интеграцию. Неудачные звонки не тарифицируются.
Пример
curl 'https://входпономеру.рф/api/v1/diagnostics' \
-H 'X-Api-Key: <ваш api_key>'
Ошибки
401 api_key_required | Ключ не передан |
401 invalid_api_key | Ключ неизвестен или отключён |
webhook.url_set (адрес задан), webhook.enabled (доставка включена) и webhook.paused (не приостановлена ли): если доставка выключена или приостановлена, вход по звонку у посетителей не завершается — предупредите администратора сайта.
/api/v1/webhook
Ссылка вебхука: сайт сам задаёт адрес приёмника
Новый способ задать адрес приёмника вебхуков: сам сайт сообщает его со своей стороны, а не через ЛК. Ключ определяет сайт (один ключ — один сайт), поэтому «чужая» ссылка не пройдёт: хост обязан совпасть с доменом сайта.
Аутентификация
| Где | Значение | Описание |
|---|---|---|
| Заголовок | X-Api-Key: <ваш api_key> | Обязательно (или параметр api_key) |
GET — текущее состояние
Возвращает домен сайта и текущую ссылку вебхука. В БД и в поле webhook_url ссылка лежит в punycode (его требует curl при доставке), а webhook_url_display отдаёт её кириллицей — как её писал клиент. enabled — включена ли доставка.
Ответ 200
{
"ok": true,
"domain": "xn--80aairftm.xn--p1ai",
"domain_display": "сайт.рф",
"webhook_url": "https://xn--80aairftm.xn--p1ai/wc/call-login-hook",
"webhook_url_display": "https://сайт.рф/wc/call-login-hook",
"url_set": true,
"enabled": true
}
Пример
curl 'https://входпономеру.рф/api/v1/webhook' \
-H 'X-Api-Key: <ваш api_key>'
POST — задать ссылку тело запроса, application/json
| Поле | Тип | Описание |
|---|---|---|
webhook_url | string | Обязательно. Адрес приёмника на вашем сайте: https://сайт.рф/wc/call-login-hook. Домен можно без схемы — https:// допишется сам. Разрешены путь, порт и query. |
enabled | int/bool | Необязательно. 1/true — включить доставку, 0/false — выключить. Не передано — текущее значение не меняется. |
Правило домена
www-форма с любой стороны: site.ru ≈ www.site.ru.shop.site.ru не пройдёт, даже если shop — настоящий поддомен.сайт.рф, xn--80aairftm.xn--p1ai и сайт.xn--p1ai — одно и то же.allowed_domain; если и она пуста — проверка отключена и принимается любой http(s) адрес.Пример
curl -X POST 'https://входпономеру.рф/api/v1/webhook' \
-H 'X-Api-Key: <ваш api_key>' \
-H 'Content-Type: application/json' \
-d '{"webhook_url":"https://сайт.рф/wc/call-login-hook","enabled":1}'
Ответ 200
{
"ok": true,
"domain": "xn--80aairftm.xn--p1ai",
"domain_display": "сайт.рф",
"webhook_url": "https://xn--80aairftm.xn--p1ai/wc/call-login-hook",
"webhook_url_display": "https://сайт.рф/wc/call-login-hook",
"url_set": true,
"enabled": true,
"delivery": {
"enabled": true,
"paused": false,
"paused_until": null,
"paused_forever": false,
"paused_seconds_left": null
}
}
В ответе — состояние после записи, включая delivery (как в статусе окна). Запись успешной ссылки снимает паузу предохранителя, если доставка была приостановлена из-за «мёртвого» прежнего адреса (кроме явного enabled: 0).
Ошибки
400 webhook_url_required | Поле webhook_url не передано или пустое |
400 bad_url | Не похоже на http(s)-адрес: пробелы, фрагмент #, user@host, схема не http(s), длиннее 500 символов |
400 domain_mismatch | Хост ссылки не совпадает с доменом сайта. В ответе поля expected_domain (ожидаемый домен) и got_host (что пришло) |
401 api_key_required | Ключ не передан |
401 invalid_api_key | Ключ неизвестен или отключён |
ваш webhook_url
Уведомление об успешном входе — вместо опроса
Сервис сам вызовет ваш адрес, когда звонок подтверждён. Адрес задаёт сам сайт через POST /api/v1/webhook (либо при подключении в ЛК); проверить его можно на карточке сайта в ЛК. Доставка включается переключателем «Доставлять вебхуки» в ЛК → Вебхуки или флагом enabled того же запроса.
Как происходит доставка
fastcgi_finish_request), и PHP-воркер сразу делает 3 попытки доставки — пауза между попытками 3 секунды, таймаут каждой 2 секунды. Крон в доставке не участвует.200 без тела. Тяжёлую работу делайте после ответа.failed — повторов позже нет, оно видно в ЛК → Вебхуки.Заголовок подписи
X-CallLogin-Signature: <hex>
Тело
{
"event": "auth.success",
"window_id": 1287,
"phone": "79094295569",
"call_session_id": "1718...",
"timestamp": 1789999999
}
Проверка подписи
Подпись — HMAC-SHA256 от сырого тела запроса на ключе webhook_secret. Сравнивайте безопасно:
$raw = file_get_contents('php://input');
$expect = hash_hmac('sha256', $raw, '<ваш webhook_secret>');
$got = $_SERVER['HTTP_X_CALLLOGIN_SIGNATURE'] ?? '';
if (!hash_equals($expect, $got)) {
http_response_code(403);
exit; // запрос не от сервиса
}
$e = json_decode($raw, true);
if (($e['event'] ?? '') === 'auth.success') {
// номер подтверждён — открывайте сессию по $e['phone']
}
http_response_code(200); // отвечайте быстро, 2xx
window_id — одна выдача сессии.
Если сайт не отвечает
Сервис защищает себя от «мёртвых» адресов: после 5 неудачных циклов подряд доставка ставится на паузу, которая растёт при повторе:
| Пауза | Когда наступает |
|---|---|
| 15 минут | после 5 неудачных циклов |
| 1 час | если после возобновления снова 5 неудач |
| 6 часов | дальше |
| 24 часа | дальше |
| бессрочно | дальше — снимается только вручную в ЛК |
Состояние доставки видно в ответе статуса окна (delivery) и в ответе POST /api/v1/webhook — проверяйте его, чтобы не пропустить паузу:
{
"window_id": 1287,
"status": "matched",
"delivery": {
"enabled": true,
"paused": false,
"paused_until": null,
"paused_forever": false,
"paused_seconds_left": null
}
}
История отправок
Все события с HTTP-кодом и ответом вашего сайта видны в ЛК → Вебхуки. Там же кнопка принудительного возобновления доставки после паузы (при нескольких сайтах — для выбранного).
/api/v1/window
Легаси: окно на вашем собственном номере
Старый вариант: окно привязывается к номеру, который подключён у вас, а не к номеру из пула сервиса. Для новых интеграций используйте /api/v2/window.
Параметры
| Поле | Тип | Описание |
|---|---|---|
api_key | string | Обязательно |
phone | string | Обязательно |
Ответ 201 — окно 2 минуты; статус читается тем же /api/v1/window/{id}
{ "window_id": 123, "expires_at": "…", "status": "open", "window_url": "/api/v1/window/123" }
| HTTP | error | Когда | Что делать |
|---|---|---|---|
| 400 | bad_json | Тело не разобралось как JSON | Проверить запрос |
| 400 | api_key_and_phone_required | В POST /window нет api_key или phone | Передать оба поля |
| 400 | insufficient_funds | Пакет входов израсходован, и на балансе нет денег на вход — номер не выдаётся | Пополнить баланс в ЛК |
| 403 | blocked | Аккаунт заблокирован (message — причина) | Обратиться в поддержку |
| 401 | api_key_required | Нет ключа в запросе | Добавить X-Api-Key |
| 403 | domain_not_allowed | Запрос пришёл с домена вне домена сайта ключа | Проверить домен сайта в ЛК |
| 404 | not_found | Окно не существует или чужое | Проверить window_id |
| 409 | busy | Для этого телефона уже открыто окно | Повторить после retry_after_seconds |
| 409 | pool_exhausted | Нет свободных номеров пула | Повторить позже |
| 429 | rate_limited | Больше 30 запросов в минуту на ключ | Снизить частоту |
| 503 | service_unavailable | Сервис недоступен | Повторить позже, показать вход по паролю |
Ошибки POST /api/v1/webhook (webhook_url_required, bad_url, domain_mismatch) описаны в разделе метода.
// 1) открыть окно
function startLogin(string $phone): array {
$ch = curl_init('https://входпономеру.рф/api/v2/window');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_TIMEOUT => 10,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode([
'api_key' => '<ваш api_key>',
'phone' => preg_replace('/\D+/', '', $phone),
'window' => 1,
]),
]);
$body = curl_exec($ch);
curl_close($ch);
return json_decode((string)$body, true) ?: ['error' => 'service_unavailable'];
}
// 2) статус окна — вызывается вашим AJAX-обработчиком
function loginStatus(int $windowId): array {
$ch = curl_init('https://входпономеру.рф/api/v1/window/' . $windowId);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10,
CURLOPT_HTTPHEADER => ['X-Api-Key: <ваш api_key>'],
]);
$body = curl_exec($ch);
curl_close($ch);
return json_decode((string)$body, true) ?: ['status' => 'unknown'];
}
// 2.5) задать адрес вебхука — один раз, при настройке сайта
function setWebhookUrl(string $url): array {
$ch = curl_init('https://входпономеру.рф/api/v1/webhook');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_TIMEOUT => 10,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'X-Api-Key: <ваш api_key>',
],
CURLOPT_POSTFIELDS => json_encode([
'webhook_url' => $url,
'enabled' => 1,
]),
]);
$body = curl_exec($ch);
curl_close($ch);
return json_decode((string)$body, true) ?: ['error' => 'service_unavailable'];
}
$start = startLogin('+7 909 429-55-69');
echo isset($start['dial_number'])
? 'Позвоните на ' . $start['dial_number']
: 'Ошибка: ' . ($start['error'] ?? 'unknown');
// 3) опрос статуса в браузере (ключ остаётся на сервере)
async function waitForCall(windowId, onMatched, onExpired) {
const deadline = Date.now() + 120000; // окно window:1
while (Date.now() < deadline) {
const r = await fetch('/api/my-login-status?window_id=' + windowId,
{ credentials: 'same-origin' });
const s = await r.json();
if (s.status === 'matched') return onMatched(s);
if (s.status === 'expired') return onExpired(s);
await new Promise(res => setTimeout(res, 1000));
}
onExpired({ status: 'timeout' });
}
api_key только на сервере, не в браузереwebhook_url через POST /api/v1/webhook (хост = домен сайта) и доставка включена — переключателем в ЛК или enabled: 1200 быстро (таймаут попытки — 2 сек)hash_equalswindow_id — одна сессияdelivery.paused в статусе окна проверяется: при паузе вход идёт по опросуbusy и pool_exhausted показаны как «повторите позже»tel: для мобильных