POS API · касса әзірлеушілеріне
Касса жүйелеріне арналған ашық API
Мекеменің кассасы Unemi клиентін өзі таниды, оның бонустары мен сыйлықтарын чекке қолданады және төлемнен кейін соманы Unemi-ге жібереді — мөртаңба, бонус немесе абонемент Unemi Staff кассасындағыдай өтеді. Касса жүйелерін әзірлеушілерге және өз кассасы бар мекемелерге арналған.
Қалай қосуға болады
-
Pro тарифі
Ашық API Pro тарифінде жұмыс істейді. Басқа тарифтерде кілт жасалмайды, ал бұрын жасалған кілтпен келген сұрауларға бас тартылады.
-
Кабинеттегі кілт
Иесі кабинетте «API и интеграции» (API және интеграциялар) бөлімін ашып, кілт жасайды: атауы — мысалы, касса не нүкте бойынша — және құқықтары.
-
Құқықтар: нүкте немесе бүкіл мекеме
Нүкте кілті тек сол нүктеде жұмыс істейді. Бүкіл мекемеге арналған кілт клиентті танығанда және чекті жойғанда нүктені көрсетеді — нүктелердің id-і сол бөлімде.
-
Кілт бір рет көрсетіледі
Оны сервердегі касса баптауларына көшіріңіз. Unemi тек хэшін сақтайды: жоғалған кілт қалпына келмейді — жаңасын жасап, ескісінің күшін жойыңыз.
Касса Unemi-мен қалай жұмыс істейді
Әр чекке төрт қадам. Клиенттің келісімі — әр чекке: оның телефонындағы QR не код бір чекке арналған сессияны ашады.
-
Клиент QR көрсетеді
Немесе оның астындағы алты санды айтады. Касса клиентті танып, оның баланстарын, сыйлықтарын, купондарын және жүріп жатқан акцияларды алады.
posIdentify -
Кассир жеңілдікті қолданады
Бонустарды есептен шығаруды, сыйлықты не купонды кассир өз кассасында кәдімгі жеңілдік сияқты өткізеді.
-
Чек жабылды — сома Unemi-ге
Касса чек нөмірін, бағдарламаны, соманы, есептен шығаруды және өтелген сыйлықтарды, қажет болса — кассир мен чектегі тауарларды да жібереді. Клиентке Unemi Staff кассасынан кейінгідей пуш келеді.
posApply -
Болдырмау мен қайтару — 48 сағат ішінде
Чек жойылса не қайтарылса, касса оны Unemi-де де чек нөмірі бойынша жояды: бәрі бұрынғы күйіне оралады. Ішінара қайтаруды касса сомасымен жібереді — Unemi оны мекеме иесіне көрсетеді.
posUndo
Лимиттер
- Бір кілтке минутына 120 сұрау
- Тану сессиясы бір чекті өткізеді және 2 сағат жарамды, касса кілтінде — 12 сағат
- Чекті 48 сағат ішінде жоюға не қайтаруға болады
- Бір чекте — бір бағдарлама және 5-ке дейін сыйлық пен купон
- 15 минуттағы тану қателері: 5-тен кейін — 1 минут үзіліс, 10-нан кейін — 5 минут, 15-тен кейін — 30 минут
- Бір мекемеге 10-ға дейін белсенді кілт
Әдістер анықтамалығы
Анықтамалық орыс тілінде: Қазақстандағы касса әзірлеушілері оны осы тілде оқиды. Әдістердің, өрістердің және қате кодтарының атаулары кез келген тілде бірдей. Анықтамалық ағылшын тілінде
Общие правила
| Параметр | Значение |
|---|---|
| Адрес | https://api.unemi.kz/<метод> |
| Методы | posIdentify, posApply, posUndo — только POST |
| Заголовки | Authorization: Bearer unemi_<id>_<секрет>, Content-Type: application/json |
| Тело | JSON-объект; ответ — JSON |
| Время | ISO 8601 в UTC: "2026-10-07T09:30:00.000Z" |
| Деньги и бонусы | Целые тенге; 1 бонус = 1 ₸ |
| Id запроса | Заголовок ответа X-Unemi-Request-Id (и requestId в ошибке) — его просят у поддержки |
| Точка | Ключ одной точки работает только на ней; ключ на всё заведение передаёт venueId в posIdentify и posUndo, а posApply берёт точку из сессии |
| Ключ кассы | Ключ одной точки с кассовой системой и правилами точки: сессия 12 часов и программа по умолчанию — раздел «Ключ кассы» |
| Лимит | 120 запросов в минуту на ключ |
| CORS | Нет: ключ живёт на сервере кассы, не в браузере |
| Тексты | Названия программ, наград, купонов и акций — как их записало заведение в кабинете; названия уровней и message в ошибках — по-русски |
Сессия и согласие клиента
- Согласие клиента — на каждый чек: QR или шесть цифр с экрана клиента открывают сессию, она проводит один чек и живёт 2 часа, у ключа кассы — 12 часов. Следующий чек — новый QR.
- QR и код одноразовые:
posIdentifyгасит их, как скан кассира. Повтор того же запроса тем же ключом (ответ не дошёл) отдаёт ту же сессию — пока по ней не проведён чек и она не истекла; кассе Unemi и другому ключу —code_used. - У ключа кассы тот же код или номер телефона в пределах 12 часов отдаёт ту же открытую сессию и после того, как сам код устарел (живёт около минуты): касса спрашивает карту клиента несколько раз за заказ. Свежий код другого клиента с теми же цифрами важнее — он гасится и открывает новую сессию.
- Чек отменили (
posUndo) — согласие на него не израсходовано: та же сессия, пока жива, проводит его заново. - По номеру телефона находятся только клиенты этого заведения (у них уже есть карта, бонусный счёт или абонемент), а сессия — только для начислений:
accrualOnly: true, штампы и бонусы без списания. - Номер ничем не подтверждён: списать бонусы, оформить или выдать абонемент, погасить награду можно только по QR или коду с телефона клиента — иначе
consent_required. Нового клиента по номеру API не заводит.
Повторы и идемпотентность
- Ответ не дошёл — повторите тот же запрос: второй раз операция не проводится.
-
posIdentifyс тем же QR или кодом от того же ключа отдаёт ту же сессию, пока по ней не проведён чек и она не истекла. -
posApplyс тем жеreceiptIdи теми же данными отдаёт сохранённый ответ сreplayed: true— без второй операции и второго пуша клиенту. Тот жеreceiptIdс другими данными или по другой сессии —receipt_conflict. Кассир и позиции (cashier,items) — справка: в сравнение не входят. -
receiptIdуникален в пределах точки: если на точке несколько касс, их номера чеков не должны совпадать — например, с префиксом кассы. После отмены (posUndo) тот жеreceiptIdможно провести заново. - Повтор
posUndoотдаёт тот же ответ сreplayed: true. -
rate_limitedиtoo_many_attempts— подождитеdetails.secondsсекунд;internal— повторите позже.
Ответ с ошибкой
Ошибка — HTTP-статус и тело:
{
"error": {
"code": "cooldown",
"message": "Слишком рано: следующий штамп можно через 12 мин",
"details": { "minutes": 12 },
"requestId": "Qk2v9XyZaB7cD1eF3gH5"
}
} Касса смотрит на error.code — коды стабильны (таблицы ниже). message — по-русски, как в кассе Unemi; details — числа к коду (минуты, лимит, баланс).
posIdentify — узнать клиента
POST https://api.unemi.kz/posIdentify
QR из приложения Unemi, шесть цифр под ним или номер телефона → сессия на один чек, клиент, балансы, награды и купоны, идущие акции.
Запрос
| Поле | Описание |
|---|---|
qr | Строка QR-кода с экрана клиента: unemi:1:st:… — или шесть цифр цифрового QR (см. «Ключ кассы») |
code | Шесть цифр под QR — когда сканера нет |
phone | Казахстанский номер клиента — только начисления (см. «Сессия и согласие клиента») |
venueId | Id точки — для ключа на всё заведение; у ключа точки необязателен |
Ровно одно из qr, code, phone.
{ "qr": "unemi:1:st:Xk2pQ9LmNb7Tz1Rw4Ycd", "venueId": "v8Kp2LmQx1" } { "code": "482913" } { "phone": "+7 701 123 45 67" } Ответ
{
"session": "Gm3kQ8rT2vXw9LpZa1Yc",
"expiresAt": "2026-10-07T11:30:00.000Z",
"identifiedBy": "qr",
"accrualOnly": false,
"customer": {
"id": "cus_4f1c9a0b2d7e8f3a6b5c1d2e",
"name": "Айгерим"
},
"level": {
"level": 3,
"name": "Друг",
"metric": "visits",
"value": 18
},
"selectedProgramId": "p8Fh2kLm",
"programs": [
{
"id": "p8Fh2kLm",
"type": "stamps",
"name": "Штамп-карта",
"locked": false,
"minLevel": 1,
"stamps": {
"count": 3,
"required": 6,
"rewardTitle": "Подарок",
"rewardPercent": 100,
"steps": [
{ "stamp": 4, "kind": "discount", "percent": 20, "title": "" }
]
}
},
{
"id": "q2Nw7xRt",
"type": "bonus",
"name": "Бонусная карта",
"locked": false,
"minLevel": 1,
"bonus": {
"balance": 1250,
"percent": 5,
"percentBp": 500,
"levelPercent": 7,
"levelBp": 700,
"welcomeBonusPending": false
}
},
{
"id": "s5Kd1vBn",
"type": "subscription",
"name": "Абонемент",
"locked": false,
"minLevel": 1,
"subscription": {
"item": "Позиция дня",
"price": 15000,
"durationDays": 30,
"lifetime": false,
"perDay": 1,
"pass": {
"expiresAt": "2026-10-20T07:00:00.000Z",
"expired": false,
"leftToday": 1,
"lifetime": false
}
}
}
],
"rewards": [
{
"id": "rW7yT2pQ",
"kind": "reward",
"title": "Подарок",
"programId": "p8Fh2kLm",
"percent": 100,
"item": null,
"expiresAt": "2026-10-30T09:00:00.000Z"
},
{
"id": "cP3mN8sD",
"kind": "coupon",
"title": "−20% на заказ",
"programId": null,
"percent": 20,
"item": null,
"expiresAt": "2026-10-08T18:00:00.000Z"
}
],
"promos": [
{
"title": "Акции по расписанию",
"description": "Бонусы ×2",
"until": "2026-10-07T11:00:00.000Z",
"effect": { "kind": "bonus_multiplier", "value": 2 }
}
]
} | Поле | Описание |
|---|---|
session, expiresAt | Сессия для posApply и до какого времени она действует — 2 часа, у ключа кассы — 12 часов. |
identifiedBy, accrualOnly | Как узнали клиента: qr (и цифровой QR), code или phone. accrualOnly: true — по номеру: только начисления. |
customer | id — постоянный id клиента для этого заведения (в другом заведении у того же человека другой); name — имя, как его видит кассир Unemi Staff. Телефона, почты и внутреннего id Unemi касса не получает. |
level | Уровень клиента, если у заведения включены уровни; иначе null. value — сколько набрано за всё время: дни с визитами (metric: "visits") или сумма покупок в тенге ("spend"); заработанный уровень не понижается. |
stamps.steps | Награды на промежуточных штампах карты по возрастанию номера: stamp — номер штампа (от 1 до required; на последнем штампе гость получает и награду шага, и главную награду rewardTitle), kind — discount (скидка percent%) или item (товар в подарок, percent — 100), title — название, пусто — назовите по скидке. Нет наград — пустой список. |
locked, minLevel | locked: true — программа «с уровня», а уровень клиента ниже minLevel: операция по ней ответит level_required (кроме выдачи по уже оплаченному абонементу). |
bonus.balance | Сколько бонусов можно списать. welcomeBonusPending: true — первый визит: приветственные бонусы начислятся этой же операцией, и их уже можно списать. |
bonus.percent, bonus.levelPercent | percent — процент программы. levelPercent — процент этого клиента по его уровню, если заведение задало проценты по уровням и он выше percent: по нему posApply и начислит; иначе null. |
bonus.percentBp, bonus.levelBp | Те же проценты точно, в базисных пунктах: 250 — 2,5%, 10 000 — 100%. Процент бывает дробным (до двух знаков после запятой, от 0 до 100); percent и levelPercent — целые, округлены половиной вверх (2,5% → 3), для касс, подключённых раньше. «Начислится» — по bp: floor((amount − spend) × bp / 10000). |
subscription.pass | Абонемент клиента; null — не оформлен. |
subscription.lifetime | Бессрочная программа: durationDays у неё 36 500. pass.lifetime — бессрочный абонемент клиента: дата окончания через сто лет, продлевать его не нужно (pass_lifetime_active). |
selectedProgramId | Программу клиент выбрал в приложении перед показом QR; null — выбирает кассир. |
rewards | Непогашенные награды штамп-карт и купоны рассылок в сроке: percent — скидка (100 — бесплатно), item — товар купона. |
promos | Акции по расписанию на точке сейчас. Эффект (bonus_multiplier, bonus_extra_percent, double_stamps) сервер применит сам при posApply; без эффекта (effect: null) — напоминание кассиру провести скидку. |
defaultProgram | Только у ключа кассы: по какой программе пройдёт чек без programId и action — { "programId": "q2Nw7xRt", "action": "bonus" }: выбранная клиентом в приложении штамп-карта или бонусная карта, иначе программа по умолчанию ключа; null — ни того, ни другого. У обычного ключа поля нет. |
posApply — провести закрытый чек
POST https://api.unemi.kz/posApply
Чек закрыт и оплачен → операция по программе и погашение наград. Операция, погашения наград, визит для уровней, подарки «Приведи друга» и подарки за новый уровень — одной транзакцией: либо всё, либо ничего.
Запрос
| Поле | Описание |
|---|---|
session | Из ответа posIdentify. |
receiptId | Id чека в кассе: 1–64 печатных знака ASCII без пробелов или целое неотрицательное число. Ключ идемпотентности — в пределах точки. |
programId, action | Операция по программе — парой (действия ниже). Без пары — только погашение наград, а у ключа кассы чек с amount — по программе по умолчанию. |
amount | Сумма чека, ₸. Для bonus обязательна (1 … 10 000 000); у остальных необязательна (целое 0 … 10 000 000) и хранится для разборов. |
spend | Сколько бонусов списано в этом чеке; только для bonus (у ключа кассы без программы — тоже, тогда программа по умолчанию должна быть бонусной картой), не больше amount и баланса. |
rewardIds | До 5 наград и купонов из posIdentify, применённых к чеку. |
cashier | Необязательно: кто провёл чек — { "id": "1234", "name": "Вдовин Б.А." }; id — код сотрудника в кассе (до 64 знаков без пробелов), имя — до 100 знаков. Хранится в чеке для разборов и антифрода. |
items | Необязательно: до 100 позиций — { "code": "7644", "name": "Позиция дня", "qty": 2, "amount": 2400 }; код товара кассы — до 40 знаков, количество больше нуля (весовой товар — дробное), сумма после скидок — целые тенге. Нужны правилу ключа кассы «штамп только за товары». |
В одном чеке — одна программа и до 5 наград и купонов.
{
"session": "Gm3kQ8rT2vXw9LpZa1Yc",
"receiptId": "A-1024",
"programId": "q2Nw7xRt",
"action": "bonus",
"amount": 4500,
"spend": 500,
"rewardIds": ["cP3mN8sD"]
} Действия по программам
action | Программа | Что делает |
|---|---|---|
stamp | Штамп-карта | Штамп на карту клиента |
bonus | Бонусная карта | Бонусы с оплаченного деньгами и списание spend |
pass_purchase | Абонемент | Оформить или продлить абонемент |
pass_issue | Абонемент | Выдать по абонементу |
Бонусы начисляются с оплаченного деньгами (amount − spend) по проценту программы — вниз до целого бонуса, floor((amount − spend) × bp / 10000), — а клиенту, чей уровень даёт больше, — по проценту его уровня до этого чека (bonus.levelBp из posIdentify); с эффектом акций по расписанию, если он идёт. Прибавки уровня и акции складываются, а не умножаются, и вместе не больше оплаченного.
Ключ кассы без программы. Чек с amount, но без пары programId и action проходит по программе по умолчанию: штамп-карта или бонусная карта, которую клиент выбрал в приложении перед показом QR, иначе программа и действие из правил ключа.
Пороги правил: оплачено деньгами (amount − spend) меньше порога — без начисления; у штампа программы по умолчанию с кодами товаров нужна хотя бы одна позиция с таким кодом (без items — штампа нет). Списание бонусов порог не останавливает, а без бонусной программы оно невозможно — action_mismatch.
Не начислено — ответ всё равно успешный: operation: null и причина в skipped; чек записан, сессия закрыта. У обычного ключа поля skipped нет, а чек без пары и без наград — invalid_request.
Ответ
{
"receiptId": "A-1024",
"operationId": "bonus:Zx81LmQa0pTt7uVv3wYb",
"operation": {
"type": "bonus",
"programId": "q2Nw7xRt",
"programName": "Бонусная карта",
"amount": 4500,
"spent": 500,
"earned": 480,
"welcome": 0,
"balance": 1230,
"promo": {
"title": "Акции по расписанию",
"kind": "bonus_multiplier",
"value": 2,
"extra": 200
},
"levelPercent": 7,
"levelBp": 700,
"levelExtra": 80
},
"redeemed": [
{ "id": "cP3mN8sD", "kind": "coupon", "title": "−20% на заказ" }
],
"referral": null,
"levelUp": null,
"replayed": false
} operation штампа{
"type": "stamp",
"programId": "p8Fh2kLm",
"programName": "Штамп-карта",
"stamps": 4,
"required": 6,
"added": 1,
"rewardIssued": false,
"rewardTitle": null,
"stepRewards": [{ "stamp": 4, "title": "Скидка 20%", "percent": 20 }],
"promo": null
} operation оформления абонемента{
"type": "pass_purchase",
"programId": "s5Kd1vBn",
"programName": "Абонемент",
"item": "Позиция дня",
"price": 15000,
"expiresAt": "2026-11-19T07:00:00.000Z",
"renewed": true,
"lifetime": false
} operation выдачи по абонементу{
"type": "pass_issue",
"programId": "s5Kd1vBn",
"programName": "Абонемент",
"item": "Позиция дня",
"leftToday": 0,
"perDay": 1,
"expiresAt": "2026-10-20T07:00:00.000Z",
"lifetime": false
} levelUp с подарками: крупная покупка подняла клиента сразу через уровень (уровни по сумме покупок){
"from": 1,
"to": 3,
"name": "Друг",
"gifts": [
{
"level": 2,
"kind": "coupon",
"rewardId": "cL4vR9kTq2",
"title": "−15% на заказ",
"percent": 15,
"item": null,
"expiresAt": "2026-11-05T18:59:59.000Z"
},
{
"level": 3,
"kind": "bonus",
"programId": "q2Nw7xRt",
"programName": "Бонусная карта",
"amount": 500
}
]
} | Поле | Описание |
|---|---|
operationId, operation | Проведённая операция; null — в чеке только погашение наград или, у ключа кассы, начислять было нечего (см. skipped). |
promo | Акции по расписанию, сработавшие в операции: extra — сколько бонусов или штампов добавила акция. |
levelPercent, levelBp, levelExtra | У бонусной операции: процент уровня клиента, если начислено по нему (levelBp — точно, в базисных пунктах; levelPercent — целым), и сколько бонусов он добавил сверх процента программы (earned — уже с ними); иначе null, null и 0. В примере: Друг — 7% вместо 5% и «бонусы ×2» с 4 000 ₸: 280 по уровню + 200 от акции = 480, а не 560. |
rewardIssued | true — штамп закрыл карту, у клиента новая награда (rewardTitle); погасить её можно следующим чеком. |
stepRewards | Награды промежуточных штампов, которые выдал этот чек: номер штампа stamp, название title (без названия — «Скидка 20%» или «Подарок»), скидка percent (100 — товар в подарок). Обычно пусто или одна. Это обычные награды: придут в rewards при узнавании, погасить можно следующим чеком. |
redeemed | Погашенные награды и купоны из rewardIds. |
referral | Первый визит приглашённого друга: { "gift": { "kind": "bonus", "amount": 300, "programName": "Бонусная карта" } }; иначе null. |
levelUp | Клиент поднялся на уровень: from, to, name и gifts — подарки за новый уровень, выданные этим чеком (пусто — подарков нет; через уровень — за каждую ступень); иначе null. Купон: rewardId — id награды (придёт и в rewards при узнавании, погасить можно следующим чеком), title, скидка percent или товар item, срок expiresAt. Бонусы: programId, programName, amount — уже на счёте клиента (если на карте этого чека — и в operation.balance). |
skipped | Только у ключа кассы, в чеке без программы: почему ничего не начислено — no_program (у ключа нет программы по умолчанию, клиент её не выбрал), below_minimum (оплачено меньше порога), no_qualifying_items (в чеке нет товаров из правила); null — начислено. |
replayed | true — повтор чека: ответ сохранённый, второй операции не было. |
posUndo — отменить чек
POST https://api.unemi.kz/posUndo
Отмена возвращает всё как было до чека: штамп, бонусы, абонемент, погашенные награды и купоны, визит уровня, подарки «Приведи друга» и подарки за новый уровень (купон-подарок, который клиент уже погасил, остаётся у него; потраченные бонусы подарка снимаются, сколько осталось на счёте). Можно в пределах 48 часов после чека: сторно и возврат бывают и в конце смены, и на следующий день.
Запрос
| Поле | Описание |
|---|---|
receiptId | Id чека, проведённого posApply на этой точке. |
venueId | Только для ключа на всё заведение. |
amount | Необязательно: сумма возврата, ₸ (целое 0 … 10 000 000). Меньше суммы чека — частичный возврат; без неё или с полной суммой — отмена чека целиком. |
{ "receiptId": "A-1024", "venueId": "v8Kp2LmQx1" } Повтор отмены отдаёт тот же ответ с replayed: true. Сессия чека снова открыта, пока жива: тот же чек можно провести заново той же сессией.
Отменить нельзя, если после чека карта клиента уже изменилась (undo_not_last), начисленные бонусы потрачены (undo_bonus_spent), награду за этот штамп уже выдали (undo_reward_redeemed) или по оформленному абонементу уже выдавали (undo_pass_used).
Частичный возврат (amount меньше суммы чека): операция остаётся, ответ успешный — partial: true, ничего не отменено.
Частичный возврат и отказы undo_too_late, undo_not_last, undo_bonus_spent, undo_reward_redeemed, undo_pass_used, operation_not_found записываются владельцу в журнал возвратов кабинета, а если он включил «Подозрительные операции» — ещё и сигналом в утренней сводке. Возврат на кассе по ответу posUndo не блокируйте: код отказа значит, что Unemi не отменил начисление, а решает владелец. Удавшаяся отмена снимает запись из журнала.
Ответ
{
"receiptId": "A-1024",
"undone": ["bonus:Zx81LmQa0pTt7uVv3wYb", "redeem:cP3mN8sD"],
"undoneAt": "2026-10-07T09:41:12.000Z",
"replayed": false
} {
"receiptId": "A-1024",
"undone": [],
"undoneAt": null,
"partial": true,
"replayed": false
} | Поле | Описание |
|---|---|
undone | Что отменено: id операции и погашений (redeem:<id награды>); пусто — частичный возврат. |
undoneAt | Время отмены; null — частичный возврат. |
partial | true — частичный возврат: ничего не отменено, запись владельцу. При отмене целиком поля нет. |
replayed | true — повтор отмены: ответ сохранённый. |
Коды ошибок
Доступ и запрос
| Код | HTTP | Когда | details |
|---|---|---|---|
unauthorized | 401 | Нет ключа, ключ не похож на ключ Unemi или не подходит | |
key_revoked | 401 | Ключ отозван в кабинете | |
plan_feature | 403 | Заведение не на Pro (или оплата просрочена больше 7 дней) | plan, feature |
method_not_allowed | 405 | Не POST | |
invalid_request | 400 | Тело не JSON-объект или поле не того вида | field |
rate_limited | 429 | Больше 120 запросов в минуту на ключ или 30 неудачных входов с одного адреса за минуту | seconds, limit |
venue_required | 400 | Ключ на всё заведение, а venueId нет | field |
venue_forbidden | 403 | Ключ одной точки, а запрос про другую | |
venue_not_found | 404 | Точки нет, она чужая или выключена | |
internal | 500 | Сбой на стороне Unemi — повторите позже |
Узнавание (posIdentify)
| Код | HTTP | Когда | details |
|---|---|---|---|
unknown_qr | 400 | Не QR Unemi и не шесть цифр | |
reward_qr | 400 | Показан QR награды — нужен QR карты; награды приходят в rewards | |
invalid_phone | 400 | Номер не казахстанский | |
code_not_found | 404 | Кода нет (опечатка или чужой QR) | |
code_used | 409 | Код уже погашен | |
code_expired | 409 | Код устарел (живёт около минуты) — клиент обновит экран | |
customer_not_found | 404 | По номеру не нашёлся клиент заведения | |
customer_unknown | 400 | В коде нет клиента | |
too_many_attempts | 429 | Пауза после промахов узнавания | seconds |
Чек (posApply)
| Код | HTTP | Когда | details |
|---|---|---|---|
session_not_found | 404 | Сессии нет, она чужая или с точки, недоступной ключу | |
session_expired | 409 | Сессии больше 2 часов (у ключа кассы — 12) | |
session_used | 409 | По сессии уже проведён другой чек | |
receipt_conflict | 409 | Этот чек уже проведён с другими данными | operationId |
consent_required | 403 | Клиент назван по номеру, а в чеке списание, абонемент или награда | |
program_not_found | 404 | Программы нет или она чужая | |
program_paused | 409 | Программа выключена | |
action_mismatch | 409 | Действие не подходит типу программы; у ключа кассы — списание в чеке без бонусной программы по умолчанию | type |
level_required | 409 | Программа с уровня, уровень клиента ниже | minLevel, level |
cooldown | 409 | Штамп этой карте на точке был недавно | minutes |
daily_limit | 409 | Дневной лимит штампов | limit |
invalid_amount | 400 | Сумма или списание не целое в границах | max |
bonus_insufficient | 409 | Списание больше баланса | balance |
pass_not_found | 409 | Выдача без абонемента | |
pass_expired | 409 | Абонемент истёк | expiredAtMillis |
pass_day_limit | 409 | Сегодня по абонементу уже выдано | limit |
pass_lifetime_active | 409 | У клиента действует бессрочный абонемент — оформлять его снова не нужно | |
reward_not_found | 404 | Награды нет или она другого клиента | |
reward_other_business | 403 | Награда другого заведения | |
reward_already_redeemed | 409 | Награда уже погашена | |
reward_expired | 409 | Срок награды вышел | |
coupon_exhausted | 409 | Купон уже использовали первые N | limit |
Отмена (posUndo)
| Код | HTTP | Когда | details |
|---|---|---|---|
receipt_not_found | 404 | Чек через API на этой точке не проводился | |
invalid_amount | 400 | Сумма возврата не целое в границах | max |
undo_too_late | 409 | Прошло больше 48 часов (minutes — длина окна отмены, 2880) | minutes |
undo_already | 409 | Операцию уже отменили на кассе или в кабинете | |
undo_not_last | 409 | После чека карта клиента изменилась | |
undo_reward_redeemed | 409 | Награду за этот штамп уже выдали | |
undo_bonus_spent | 409 | Начисленные бонусы уже потрачены | balance |
undo_pass_used | 409 | По абонементу уже выдавали | |
operation_not_found | 404 | Операции чека больше нет (награду удалили) |
Безопасность и данные
- Ключ —
unemi_<id ключа, 20 знаков>_<секрет, 48 hex>, 192 случайных бита секрета. Unemi хранит только sha256 секрета и последние четыре знака для узнавания в списке; неверный, кривой и несуществующий ключ — один ответunauthorized. - Чужое заведение недоступно: ключ привязан к заведению, сессия и чек ищутся только в нём; ключ точки видит только свою точку. Чужие сессия, программа, награда и чек отвечают «не найдено».
- Персональные данные: касса получает имя клиента (как кассир Unemi Staff), балансы, награды и уровень. Телефона, почты и внутреннего id Unemi в ответах нет; id клиента — отдельный псевдоним для каждого заведения.
- Перебор кодов и номеров: промахи узнавания (
code_not_found,customer_not_found) копятся на ключ 15 минут; после 5 — пауза 1 минута, после 10 — 5 минут, после 15 — 30 минут (too_many_attempts). Проводить и отменять чеки пауза не мешает. - Журнал запросов в кабинете — без данных клиента, хранится 30 дней.
- Песочницы нет: интеграцию проверяют на тестовом заведении на тарифе Pro.
Ключ кассы
- Ключ кассы — ключ API одной точки, отмеченный кассовой системой: r_keeper, iiko, Syrve или своя касса сети. Создаёт владелец в кабинете: «API и интеграции» → «Создать ключ» → «Касса r_keeper». Ключа кассы на всё заведение нет: касса стоит в конкретной точке.
- У ключа — правила точки: программа по умолчанию и действие (штамп — для штамп-карты, бонусы — для бонусной карты), порог суммы (0 … 10 000 000 ₸) и коды товаров кассы (до 100, каждый до 40 знаков без пробелов), — и язык текстов на экране кассы, один из шести языков Unemi. Правила и язык меняются без нового ключа; для другой кассы создают новый ключ.
- Что иначе в методах: сессия живёт 12 часов, и тот же код или номер в заказе отдаёт ту же сессию;
posIdentifyотдаётdefaultProgram; чек без программы проходит по программе по умолчанию, а если ничего не начислено — причина вskipped. - Цифровой QR: пока у заведения есть действующий ключ кассы r_keeper, в QR карты клиента — те же шесть цифр, что под ним: сканер r_keeper читает их как номер карты. В
posIdentifyих передают вqr(identifiedBy: "qr"). Общий QR из меню приложения (без карты) остаётся обычным: клиент называет шесть цифр под ним.
{
"name": "r_keeper · Абая",
"venueId": "v8Kp2LmQx1",
"pos": {
"system": "r_keeper",
"language": "ru",
"rules": {
"programId": "q2Nw7xRt",
"action": "bonus",
"minAmount": 0,
"productCodes": []
}
}
} Мост r_keeper для дилеров Скоро
Модуль HttpFarCard (ExtDllHTTP.dll) кассового сервера r_keeper сам шлёт POST с XML — запрос карты (getcardinfoex) и проводки закрытого чека (transactionsex), — а мост posRkeeper проводит их тем же ядром, что и методы выше: узнаёт клиента, проводит чек, отменяет его при откате и возврате.
| Параметр | Значение |
|---|---|
| Адрес | https://api.unemi.kz/posRkeeper — строка Address в ExtDllHttp.ini |
| Обработчики | GetCardInfoEx=getcardinfoex, TransactionsEx=transactionsex |
| Вход | Базовая авторизация: логин unemi_<id ключа>, пароль — секрет ключа; только https, иначе https_required |
| Ключ | Ключ кассы r_keeper на одну точку: адрес, логин и пароль владелец получает в кабинете при создании ключа и передаёт дилеру. Обычный ключ API или ключ другой кассы — pos_key_required |
| Привязка | Первый запрос запоминает объект r_keeper (его коды в запросах кассы); запрос с другого объекта — venue_mismatch |
| Ответы | XML протокола HttpFarCard. Отказ проводок — Result="1" с причиной в TRRESPONSE; карта не принята — Locked="1" с причиной в WhyLock |
Проводки отклоняются, только когда нельзя принять оплату бонусами (например, не хватает бонусов, клиент назван по телефону или нет бонусной программы): чек без оплаты бонусами касса закрывает всегда, а если начисление не прошло, причину владелец видит в журнале запросов.
Откат оплаты, возврат и откат возврата кассу не останавливают: возврат отменяет чек в пределах 48 часов, а что Unemi не отменил, владелец видит в журнале возвратов. Подарки и купоны через r_keeper не гасятся — их выдают в кассе Unemi. Тексты на экране кассы — на языке ключа.
Тақырып бойынша тағы
-
Кассалармен интеграциялар
Poster, iiko және басқа кассалармен дайын интеграциялар осы API негізінде жасалады. Кассаңызды белгілеңіз — қайсысын бірінші жасау керегін осылай түсінеміз.
-
Pro тарифі
Ашық API Pro тарифіне кіреді. Тарифте тағы не бар және не қазір жұмыс істейді — тарифтерді салыстыруда.
-
Интеграция бойынша сұрақтар
Бөлек сынақ ортасы (sandbox) жоқ: интеграция Pro тарифіндегі сынақ мекемесінде тексеріледі. Бізге жазыңыз — қосылуға көмектесеміз.