RUS
  • ENG
  • RUS

Рекомендации по разработке интеграции UDS и кассово-учетных систем

Последние изменения: 06.03.2024

Ниже описаны рекомендации по разработке модуля (плагина) для интеграции с UDS и учетных систем на основе API.


Если при разработке у Вас возникли вопросы по этому документу, Вы можете обратиться на наш почтовый ящик support@uds.app - и мы вас проконсультируем.

Документация по Partner API

Часто задаваемые вопросы по API

Логическая схема запросов

Примеры запросов


Предполагаемый бизнес процесс работы кассы при реализованной интеграции с UDS:

1. Клиент скачивает приложение UDS.

2. Показывает свой код на оплату из приложения UDS App кассиру.

3. Кассир вводит данный код в кассу и отображается информация о клиенте (Имя, Фамилия, сколько бонусных баллов накопил).

4. Кассир вводит сколько бонусов списать, 1 бонусный балл = 1 рубль.

5. Итоговая сумма счета понижается на количество списываемых бонусных баллов. Например, счет 1000, списываем 100 бонусных баллов, итого клиент должен оплатить 900 рублей.

6. После оплаты в UDS отправляется информация о данной оплате.

7. Если по каким-то причинам чек был проведен без использования UDS, то реализовать печать ваучера для накопления бонусов после покупки.

8. Реализовать возможность отмены оплаты, т.е. при отмене в учетной системе также должна происходить отмена транзакции в UDS

mceclip3.png

Основы работы с API

  • Формат взаимодействия

API UDS построено на REST-принципах. С помощью этого API вы можете отправлять запросы для проведения оплат по начислению / списанию бонусных баллов, получать информацию о клиентах, совершать возвраты, заполнять прайс и многое другое. API в качестве основного протокола использует HTTP. Методы должны быть стандартными для HTTP: GET, POST, DELETE или PUT.

API endpoint: https://api.uds.app/partner/v2/


Partner API основан на открытых стандартах, поэтому можно использовать любой язык веб-разработки для доступа к API. API возвращает ответ в формате JSON, независимо от типа запроса.

  • Заголовки запроса (Headers)

Существует несколько заголовков, которые должны быть размещены в каждом запросе для удовлетворения требований транспортной инфраструктуры.

Название

Формат (тип данных)

Описание

Accept

MIME Type

application/json

Accept-Charset

String

utf-8

Content-Type

MIME Type

application/json (для метода POST)

X-Origin-Request-Id

UUID

идентификатор запроса, используемого приложением; может быть опущен, но его использование рекомендуется

X-Request-Id

UUID

идентификатор запроса

X-Timestamp

ISO 8601 Date

дата и время создания запроса

  • Аутентификация

Для вызова методов Partner API интегрируемые приложения должны аутентифицировать запросы, используя Basic Auth. Для этого требуется установить значение токена в http-заголовок Authorization. Значение токена - идентификатор вашей компании (company id) и секретный ключ (API Key), закодированные с помощью base64. Создать или получить имеющийся API Key можно на странице Интеграция.


Пример запроса с аутентификацией:

curl -X GET -s https://api.uds.app/partner/v2/settings  -H "Authorization: Basic MTIzNDp0b2tlbg=="

Где MTIzNDp0b2tlbg== -- это закодированная в Base64 строка 1234:token.


Секретный ключ отвечает за безопасность ваших данных. Храните его в защищенном месте и не публикуйте на сторонних ресурсах.


Внимание! Если при отправке запросов возвращается 401 ошибка unauthorized или 403 ошибка forbidden, то API key или id компании введены неверно.


API key (токен) и id компании, которые используются при интеграции с кассой, не должны жестко прописываться в коде. При настройке интеграционного модуля должна быть возможность прописать API key и id в какой-нибудь конфигурационный файл (config), т.к. они для каждой компании свои.

  • Числа и округление

Все числа API должны быть округлены с точностью до двух десятичных знаков до ближайшего числа. Все ответы от сервера также должны следовать этому правилу; поэтому каждое поле, рассчитанное на стороне сервера, будет иметь не более двух десятичных цифр, а число будет округлено до ближайшего числа.

Важно! Сумму списываемых бонусов можно округлять только в меньшую сторону.

  • Выполнение запросов

Клиенты должны устанавливать заголовки X-Origin-Request-Id со значением UUID и X-Timestamp со значением временной отметки по ISO-8601 для всех запросов. В ответ сервер генерирует и устанавливает новый UUID в X-Request-Id и временную отметку в заголовке X-Timestamp. Если запрос содержит заголовок X-Origin-Request-Id, сервер устанавливает его в ответ.


Пример:

X-Origin-request-Id: 8c828ee7-e7b2-4631-a3e4-b18987962556 X-Timestamp: 2016-07-08T13:17:39,245+00:00
  • Коды ответов и ошибки

Partner API использует стандартные коды состояния HTTP для индикации успешности запроса. Некоторые ответы также могут содержать поле errorCode, которое содержит подробное объяснение возникшей ошибки. Ожидается, что все запросы, приведшие к состоянию ответа 4xx (ошибка на стороне клиента), не будут повторяться до тех пор, пока не будет найден источник ошибки.


Коды ответов:

Код ответа

Описание

200

Ok. Вызов API был успешным

400

Произошла ошибка проверки достоверности или бизнес-логики

401

Доступ запрещен, данный токен аутентификации не установлен или не имеет соответствующего разрешения

404

Запрошенный объект, API-метод или путь не существует

  • Объект ошибки

Когда вызов API-метода приводит к ошибке, ответ будет содержать объект ошибки JSON. Для большинства ответов об ошибках этот объект выглядит следующим образом:

{     "errorCode": "<Short code for given error>", // string     "message": "<Human readable error description>" // string }


Совет: Язык описания ошибки зависит от HTTP-заголовка Accept-Language.


Для ошибок проверки достоверности формы существует специальный код ошибки - badRequest. Если объект ошибки имеет этот код ошибки, ответ также будет содержать свойство errors по следующей схеме:

{     "errorCode": "badRequest", // string     "message": "<Error description>", // string     "errors": [ // array         {             "errorCode": "nullalbe", // string             "message": "Property [points] cannot be null", // string             "field": "points", // string, optional             "value": null // string, optional },     ] }


Распространенные коды ошибок:

Код ошибки

Описание

forbidden

Доступ запрещен, данный токен аутентификации не установлен или не имеет соответствующего разрешения

notFound

Объект не найден

badRequest

Произошли ошибки проверки достоверности формы. Например, это может быть несоответствие типов или ошибки нарушения ограничений

  • Коды ошибок конкретного метода

Каждый вызов API-метода может вызвать ошибки, характерные для этого метода. Для получения подробной информации об этих ошибках, пожалуйста, ознакомьтесь с описанием метода в каждом пути API.

Типовой сценарий интеграции

  • Ввод кода или номера телефона клиента

1. После формирования итогового счета к оплате должна быть возможность ввода кода клиента из мобильного приложения UDS или номера телефона клиента в международном формате +79992221133. Если есть возможность, также реализовать ввод кода клиента с помощью сканера QR кодов.

mceclip5.png


2. После ввода кода или номера телефона клиента в UDS отправляется GET запрос

https://api.uds.app/partner/v2/customers/find?code=456123&exchangeCode=true&total=1000&skipLoyaltyTotal=100&unredeemableTotal=200

(см. запрос https://docs.uds.app/#tag/Customers/paths/~1customers~1find/get)

Пример запроса:

curl -H 'Accept: application/json' \ -H "X-Origin-Request-Id: $(uuidgen)" \ -H "X-Timestamp: $(date --iso-8601=seconds --utc)" \ -u "<companyId>:<api_key>"  -X GET –s https://api.uds.app/partner/v2/customers/find?code=456123&exchangeCode=true&total=1000&skipLoyaltyTotal=100&unredeemableTotal=200


Где code - код на клиента из мобильного приложения UDS,

total - изначальная сумма счета за вычетом сторонних скидок (без учета скидок UDS и списанных бонусных баллов);

exchangeCode - запрос на получение кода клиента длительностью 24 часа (вместо кода из приложения, у которого время действия 45 минут);

skipLoyaltyTotal – сумма, на которую не должна применяться скидка (данный параметр влияет в этом запросе, если в компании установлена настройка "Предоставление скидки", а не начисление бонусных баллов).

unredeemableTotal - сумма чека, на которую запрещено списывать бонусы. В этом случае максимальное количество баллов будет рассчитано с учетом этого параметра

Примечание:

  • Про параметр skipLoyaltyTotal:

Если в чеке есть товар с ограничением применения прямой скидки или начислением бонусов, то количество бонусов будет начислено без учетов таких товаров. Например, если в Вашей компании бонусы начисляются 10% от суммы чека и в чеке 2 позиции: товар А за 50р с ограничение на начисление бонусов (передается параметр skipLoyaltyTotal=50) и товар Б за 50р без ограничений, то количество начисляемых бонусов будет рассчитываться только от стоимости товар Б, то есть можно получить 5 бонусов. Если параметр skipLoyaltyTotal не передается,то количество бонусов будет рассчитываться на всю сумму чека и можно будет получить 10 бонусов.

  • Про параметр unredeemableTotal:

Если в чеке есть товар с ограничением списания бонусов, то количество списываемых бонусов будет рассчитываться без учета таких товаров. Например, если в Вашей компании можно списывать бонусами 20% от суммы чека и в чеке 2 позиции: товар А за 50р и ограничением на списание бонусов (передается параметр unredeemableTotal=50) и товар Б за 50р и без ограничений, то количество списываемых баллов будет только рассчитываться от стоимости товар Б, то есть максимум можно списать 10 бонусов. Если параметр unredeemableTotal не передается, то количество бонусов будет рассчитываться на всю сумму чека и бонусами можно будет оплатить 20.

skipLoyaltyTotal ограничивает начисление баллов или применение прямой скидки на акционные товары (но можно на них списывать), unredeemableTotal ограничивает списание бонусов на акционные товары( но дает на них начислять бонусы или применять прямую скидку).
Если передать оба параметра, то ограничение будет и на списание, и на начисление бонусов

  • Ответ, основные поля

uid - идентификатор пользователя (по uid также можно производить поиск и оплату),
displayName - имя и фамилия,
discountRate - размер скидки,
points - количество баллов,
maxPoints - количество допустимых к списанию баллов, применимых к этой оплате (рассчитывается исходя из поля total в GET запросе),
code - код на оплату для проведения операции.


  • Применение скидки к заказу

Важно! Применение скидки допустимо только при вводе кода из приложения, при вводе номера телефона скидка не должна применяться.

3. Применяется скидка к заказу в размере discountRate. Если discountRate = 0, то это значит, что клиенту после оплаты будут начислены бонусы и скидка не нужна.

Если discountRate >0, то к заказу должна применяться скидка, процент которой приходит в этом параметре. В этом случае сумма счета сначала уменьшается на процент скидки, а после клиенту предлагается списать/ накопить бонусы.

  • Списание бонусных баллов

Важно! Списание бонусов всегда доступно при вводе кода из приложения. По номеру телефона бонусы можно списывать при условии, что в компании активна соответствующая настройка. По uid нельзя списывать бонусные баллы, только копить.

4. Вводится количество бонусных баллов для списания. Если значение параметра maxPoints = 0, то ввод количества списываемых баллов должен быть недоступен.

mceclip6.png

  • Итоговое формирование чека после списания баллов

5. Итоговая сумма счета уменьшается на примененную скидку (если в компании включена скидка, а не начисление бонусных баллов) и количество списываемых бонусных баллов.

  • Отправка POST запроса о проведении операции по UDS

6. После нажатия кнопки Оплатить (закрытия заказа), транзакция должна отправиться и в UDS – POST запрос (запрос Create operation https://docs.uds.app/#tag/Operations/paths/~1operations/post).


Пример запроса:

curl -H "accept: application/json" \ -H "Content-Type: application/json" \ -H "X-Origin-Request-Id: $(uuidgen)" \ -H "X-Timestamp: $(date --iso-8601=seconds --utc)" \ -u "<companyId>:<api_key>" -d '{ \     "code":"string", \     "nonce":"uuid", \     "cashier": { \         "externalId":"string", \         "name":"string" \     }, \     "receipt": { \         "total":100.0, \         "cash":50.0, \         "points":50.0, \         "number":"string" \         "skipLoyaltyTotal":10.0 \         "unreedemableTotal":20.0 \     }, \     "tags":[1,2] \ }' -X POST "https://api.uds.app/partner/v2/operations"


В запросе Create operation передаются следующие параметры:

code (код для проведения транзакции, из ответа к запросу Find customer) или phone (номер телефона в международном формате через +7)

total (изначальная сумма счета); Если в заказе присутствуют сторонние скидки, тогда сумма total должна указываться после применения этих скидок.

skipLoyaltyTotal – сумма, на которую не должна применяться скидка или начисляться кешбэк. Если в заказе присутствуют товары, которые не должны участвовать в системе UDS (т.е. на эти товары не распространяются скидки), то нужно передать в этом поле их сумму.

unredeemableTotal - сумма чека, на которую запрещено списывать бонусы. В этом случае максимальное количество баллов будет рассчитано с учетом этого параметра

points (количество списываемых баллов у клиента), если оплата проводится по номеру телефона, то баллы списывать нельзя, т.е. points указывать 0;

cash (сумма, оплаченная деньгами: карта, наличными или комбинированная оплата);

externalId и name - идентификатор и имя кассира, производивший оплату. Externalid может состоять только из цифр и латинских букв. В кассовой системе этим идентификатором может являться id или номер сотрудника;

number (номер чека в кассовой системе);

nonce - строка вида uuid, уникальная для каждого чека. Рекомендуется указывать этот параметер для исключения повторных операций в случае дублирования запроса. Если запрос с операция в первый раз прошел в UDS успешно, то для второго запроса вернется успешный ответ, но операция в UDS будет только одна. Если этот параметр не используется, то возможно дублирование операции при повторном запросе или возникновение ошибок

tags (список id тегов, которые нужно установить клиенту);

Важно! При возвращении ошибки с UDS не проводить оплату в учетной системе до внесения корректировки / устранения ошибки и отправления повторного запроса, т.е. проводить оплату в учетной системе только после получения ответа success. Возможные ошибки описаны ниже.

  • Описание ошибок

7. Если при оплате / закрытии заказа вернулась ошибка от UDS, то в интерфейсе учетной системы следует писать соответствующее описание:

Статус

Код ошибки

Описание

400

badRequest

Form validation errors occurred. Обратитесь, пожалуйста, к разработчикам учетной системы

400

invalidChecksum

Удалите, пожалуйста, в заказе посторонние скидки, проверьте правила округления

400

insufficientFunds

Попытка списания бонусных баллов больше, чем есть у клиента на балансе. Внесите, пожалуйста, корректировку

400

discountLimitExceed

Попытка списания бонусных баллов больше, чем допустимо по маркетингу. Внесите, пожалуйста, корректировку

401

unauthorized

Компания не активна или сгенерирован новый API Key Продлите, пожалуйста, подписку UDS.

404

notFound

Неверно введен код клиента или время жизни кода истекло. Введите, пожалуйста, новый код

  • Реализовать возможность возврата

8. Реализовать возможность отмены оплаты, то есть при отмене в учетной системе также должна происходить отмена транзакции в UDS.

Запрос POST /operations/{id}/refund , где:
id - это id транзакции UDS, значение которой возвращается ответом после успешной проведенной транзакции.
partialAmount - сумма, на которую производится отмена. Для реализации частичной отмены оплаты, необходимо в данном запросе передавать параметр partialAmount, иначе отмена будет полной.

mceclip7.png

Пример запроса:

curl -H "accept: application/json" \ -H "Content-Type: application/json" \ -H "X-Origin-Request-Id: $(uuidgen)" \ -H "X-Timestamp: $(date --iso-8601=seconds --utc)" \ -u "<companyId>:<api_key>" \  -d '{"partialAmount":100.0}' \ -X POST "https://api.uds.app/partner/v2/operations/<id>/refund"


Для частичного возврата (например, клиент возвращает один товар из покупки) укажите стоимость возвращаемого товара в поле partialAmount. Если товар оплачивался баллами, возврат осуществляется с учетом списанных баллов – например, клиент купил товар на 100 р. и оплатил баллами UDS 30 р., наличными - 70 р., то в поле partialAmount нужно передавать 100

  • Реализовать печать ваучера

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

Метод позволяет напечатать на чеке код ваучера (qr код) и клиент, отсканировав его в приложении UDS App, сможет получить баллы за покупку. Например, клиент забыл телефон, не было времени, сотрудник не рассказал про возможность накопить и т.п., то клиент сможет накопить баллы позже по чеку с таким ваучером. Срок жизни ваучера- 3 часа.

Важно! Обязательным условием использования данного функционала является настройка модуля программы лояльности в настройках административной панели UDS Business (https://admin.uds.app/). Вам необходимо указать Начислять бонусные баллы в блоке настройки Способ предоставления скидки и поставить базовый статус больше 0

mceclip0.png
  • Endpoint

https://api.uds.app/partner/v2/operations​/voucher

Метод - POST

Создание ваучера на проведение операции в UDS. В случае успеха вы получите информацию для печати кода и ссылки на графическое отображение QR кода ваучера на чеке.

Пример запроса, который нужно отправить при создании ваучера:

            curl -H "accept: application/json" \             -H "Content-Type: application/json" \             -H "X-Origin-Request-Id: $(uuidgen)" \             -H "X-Timestamp: $(date --iso-8601=seconds --utc)" \             -u "<companyId>:<api_key>"             -d '{ \               "nonce":"string-UUID", \               "cashier":{ \                 "externalId":"string", \                 "name":"string" \               }, \               "receipt":{ \                 "total":100.0, \                 "number":"string", \                 "skipLoyaltyTotal": 50.0 \               } \             }' -X POST "https://api.uds.app/partner/v2/operations/voucher"


В запросе Voucher передаются следующие параметры:
total (изначальная сумма счета); Если в заказе присутствуют сторонние скидки, тогда сумма total должна указываться после применения этих скидок.
skipLoyaltyTotal – сумма, на которую не должен начисляться кешбэк. Если в заказе присутствуют товары, которые не должны участвовать в системе UDS (т.е. на эти товары не распространяются скидки), то нужно передать в этом поле их сумму.
externalId и name - идентификатор и имя кассира, производивший оплату. Externalid может состоять только из цифр и латинских букв. В кассовой системе этим идентификатором может являться id или номер сотрудника;
number (номер чека в кассовой системе);


Ответ на запрос создания ваучера

code - Числовой код ваучера

qrCodeText - Текст для генерации QR - кода ваучера для дальнейшей печати.

qrCode128 - Ссылка для генерирования картинки QR кода (size 128), которую можно распечатать.

qrCode256 - Ссылка для генерирования картинки QR кода (size 256), которую можно распечатать.

expiresIn - Время, когда ваучер сгорит по UTC.

points - Количество баллов для начисления. Рассчитывается из настроек базового уровня бонусной программы. Если клиент с повышенным статусом отсканирует чек, то бонусы будут начислены согласно статусу клиента.

Возвращаемые ошибки

Status

Error Code

Description

400

invalidChecksum

Способ предоставления скидки не кешбэк (CHARGE_SCORES)

400

invalidChecksum

Поля total, skipLoyaltyTotal не коррелируют с маркетинговыми настройками компании

400

invalidChecksum

Размер начисляемых бонусных баллов равен 0

400

invalidChecksum

Поле total меньше или равно skipLoyaltyTotal

Протестируйте интеграцию согласно чек-листу

Помогла ли вам статья?