Документация API Axle
Интеграция внешних сервисов (POS/касса, собственные разработки) с платформой
Axle: отправка данных к нам и чтение наших данных.
Базовый адрес: https://axleapp.ru
Авторизация и ключи
Все запросы — по HTTPS. Ключ передаётся в заголовке Api-Key.
Api-Key: <ваш ключ>
Content-Type: application/json
Accept: application/json
Ключи бывают двух видов:
| Ключ | Где взять | Особенности |
|---|---|---|
| Открытый (для собственных интеграций) | Кабинет: Интеграции → API | Доступен на тарифе «Про». Работает с любого сервера. |
| Сервисный ключ POS | Кабинет: Интеграции → Axle-CRM POS, блок «Ключ для входящих запросов» | Для запросов самой кассы (вебхуки, чтение клиента). Принимается только с серверов POS. Тариф «Про» не требуется. |
Перевыпуск любого ключа мгновенно отзывает старый. Не публикуйте ключи и не встраивайте их в клиентский код (сайт/приложение гостя).
Приём событий — POST /no-auth/api/v1/webhook/
Присылайте события при изменениях на вашей стороне. Тело — JSON с полем
event, меткой source и данными. Ответ: { "success": true }
(HTTP 200) либо ошибка с описанием (4xx).
1. client.upserted — профиль и агрегаты клиента
Создание/обновление клиента (мэтчинг у нас: по client_id → телефону → номеру карты).
Поля — как в вашем client/list.
{
"event": "client.upserted",
"source": "pos",
"client": {
"client_id": 12345,
"phone": "+79001234567",
"card_number": "1234",
"first_name": "Иван",
"last_name": "Иванов",
"middle_name": "Иванович",
"sex": "male", // male | female | null
"dob": "1990-01-15", // YYYY-MM-DD | null
"subscription_sms": true,
"comment": "пример комментария",
"bonus_balance": 500.00, // текущий баланс бонусов (1 бонус = 1 ₽)
"number_of_visits": 10,
"average_bill_sum": 15000.00, // итог покупок, ₽
"loyalty_bill_sum": 9000.00,
"loyalty_id": 1, "loyalty_name": "Базовая",
"cohort_id": 2, "cohort_name": "Пример кампании",
"last_visit_at": "2026-07-01T20:00:00+03:00",
"updated_at": "2026-07-08T12:00:00+03:00"
}
}
2. bonus.changed — изменился бонусный баланс
Лёгкое событие только про баланс (если не хотите слать весь профиль).
Клиента ищем по client_id → телефону → номеру карты.
{
"event": "bonus.changed",
"source": "pos",
"client": { "client_id": 12345, "bonus_balance": 650.00 }
}
3. receipt.closed — закрыт чек
Присылайте закрытый чек со строками (снимок названия/цены/количества на момент
продажи). Чек попадает в историю покупок гостя и в аналитику (меню-инжиниринг,
RFM) практически сразу. Суммы — в рублях (float), у нас хранятся в копейках.
Объект shift необязателен (если чеки привязаны к сменам — присылайте).
{
"event": "receipt.closed",
"source": "pos",
"receipt": {
"receipt_id": 98765,
"receipt_opened_at": "2026-07-08 19:02:11",
"receipt_closed_at": "2026-07-08 20:15:40",
"tile_name": "Стол 4", "tile_number": "4",
"payed_amount": 2350.00,
"is_fiscal": 1, "is_return": 0,
"sales": [
{
"sale_id": 555001,
"client_id": 12345, // клиент строки (на шапке чека его нет)
"price_id": 101, // id позиции вашего прайса
"menu_group_id": 7,
"price_name": "Цезарь с курицей",
"price_type_id": 1, // 1 = обычная цена, 2 = повременная
"price_menu": 590.00, // цена за единицу по меню
"quantity": 2,
"payed_sum": 1080.00, // фактически оплачено за строку
"unit_name": "порц"
}
]
},
"shift": { "shift_id": 3210 } // необязательно
}
Скидка выводится у нас: price_menu × quantity − payed_sum
(на строку и на чек). Повторная отправка того же receipt_id обновляет
чек, дубли не создаются.
Чтение клиента — GET /no-auth/api/v1/customer/
Параметры (query): card или phone.
GET https://axleapp.ru/no-auth/api/v1/customer/?card=1234
{
"success": true,
"client": {
"external_id": 100, // наш id клиента
"first_name": "Иван", "last_name": "Иванов", "middle_name": "Иванович",
"phone": "+79001234567", "card_number": "1234",
"sex": "male", "dob": "1990-01-15",
"bonus_balance": 500.00
}
}
Коды ответов и лимиты
| Код | Когда |
|---|---|
200 | Успех. Тело: { "success": true, ... }. |
401 | Нет заголовка Api-Key, ключ неверный или не проходит условия своего вида
(открытый — организация не на тарифе «Про»; сервисный — запрос не с сервера POS). |
404 | Клиент не найден (/customer/). |
422 | Событие не распознано или не хватает данных — описание в message. |
429 | Слишком много запросов: лимит 120 запросов в минуту с одного IP. Повторите позже. |
Ответ ошибки всегда JSON: { "success": false, "message": "…" }.
Правила
| Правило | Как работает |
|---|---|
| Единицы | bonus_balance — бонусы, 1 бонус = 1 ₽, до 2 знаков. Суммы чеков — рубли (float). |
| Идемпотентность | Присылайте updated_at; повтор с не более свежим временем игнорируется. Чеки идемпотентны по receipt_id. |
| Разрыв эха | Если изменение инициировали МЫ (пуш в вашу сторону), присылайте его обратно с source: "axle" — мы такое проигнорируем. Свои изменения — source: "pos". |
| Удаление | Мягкое: помечаем неактивным, историю не трогаем. |
Вопросы по интеграции и расширению форматов (доп. поля, новые события) — напишите нам, добавим.