# Основные принципы

# Схема взаимодействия

Diagram

# Запросы

# Точки входа

Точки входа для тестового (sandbox) и боевого (production) окружения одинаковы. Mandarin определяет окружение по аутентификационным данным (а именно, по значению секретного ключа Secret).

Важно использовать TLS не ниже 1.2 (запросы с TLS 1.0 или 1.1 будут отклоняться).

Точка входа для создания транзакций

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

POST https://secure.mandarinpay.com/api/transactions

Точка входа для токенизации карт

Используется только для токенизации карт.

POST https://secure.mandarinpay.com/api/card-bindings

Точка входа для упрощенной идентификации

Процесс идентификации значительно отличается от остальных и описан на отдельной странице. При этом используется стандартный для Mandarin способ аутентификации.

POST https://secure.mandarinpay.com/api/personidentification

# Аутентификация запросов

Аутентификация запросов происходит за счет авторизационной строки, которая передается в параметре заголовка X-Auth.

Значение X-Auth формируется по следующему шаблону:
merchantId-SHA256(merchantId-requestId-secret)-requestId, где:

  • merchantId – MID, указанный в личном кабинете.

  • requestId – уникальный номер запроса. Для обеспечения уникальности рекомендуем использовать текущий таймстамп в миллисекундах, либо набор байт, сгенерированный криптографически-надёжным генератором случайных чисел.

  • secret – Secret, указанный в личном кабинете.

API-запросы без заголовка или с некорректным заголовком, в том числе c некорректным X-Auth, будут отклонены без создания транзакций.

Примеры расчета X-Auth

<?php
function gen_auth($merchantId, $secret)
{
        $reqid = time() ."_". microtime(true) ."_". rand();
        $hash = hash("sha256", $merchantId ."-". $reqid ."-". $secret);
        return $merchantId ."-".$hash ."-". $reqid;
}
?>
public static string GenerateXAuth(string secret)
{
  var requestId = Guid.NewGuid().ToString("N");
    string hash;
    using (var sha256 = System.Security.Cryptography.SHA256.Create())
        hash = BitConverter.ToString(sha256.ComputeHash(Encoding.UTF8.GetBytes($"{merchantId}-{requestId}-{secret}"))).ToLower().Replace("-", "");
    return $"{merchantId}-{hash}-{requestId}";
}

DEPRECATED

Альтернативный способ аутентификации - Basic auth (opens new window). Не рекомендуем использовать его, особенно для запросов по выплатам на карту. В качестве логина используется значение merchantId, в качестве пароля - значение Secret.

# Параметры запросов

Content-Type для запросов принимает значение application/json.

Параметры запросов для приема платежей, токенизации и выплат на банковские карты описаны в отдельном разделе.

# Синхронные ответы

# HTTP-коды

Mandarin использует стандартные HTTP-коды статуса для индикации успешности или неуспешности API-запросов.

Код Описание
2хх Запрос обработан.
4хх Параметры, переданные клиентом, некорректны (отсутствие нужного формата, неверно сформированный заголовок и т.д.).
5хх Внутренняя ошибка на стороне Mandarin (довольно редкий случай).

# Параметры ответов

Параметр Обязателен Описание
id Да Идентификатор созданной операции или токен карты
userWeblink Нет Ссылка для перенаправления пользователя при работе с платежной страницей
jsOperationId Нет Идентификатор операции для использования с Mandarin Custom Pay
error Нет Текстовое описание ошибки

Каждый вызов API имеет ассоциируемый с ним идентификатор, который называется ID транзакции и передается в синхронном ответе как значение параметра id. Для запроса токенизации он является токеном карты, а для запроса платежа/выплаты его называют ID транзакции. Он также присутствует в составе callback-уведомления в качестве значения поля transaction (для платежей/выплат) или card_binding (для токенизаций).

ID транзакции (его также называют ID платежа) также доступен в таблице транзакций по ссылке в личном кабинете (opens new window) и в интерфейсе HeartBeat.

Transaction ID

СОВЕТ

При обращении в Cлужбу поддержки (opens new window) по вопросам с конкретной транзакцией, сообщите ее ID транзакции! Это существенно ускорит получение ответа.

После получения синхронного ответа могут быть три варианта действий:

  1. Для использования платежной страницы
    Перенаправить пользователя по ссылке, полученной в качестве userWebLink (подробнее)
  2. Для использования встраиваемой формы Mandarin Custom Pay
    Использовать значение из jsOperationId в качестве operationId (подробнее)
  3. Дальнейшие действия не требуются
    В этом случае в синхронном ответе будет получен только id.

Ответ в случае успешного создания транзакции (200 ОК)

{
	"id": "43913ddc000c4d3990fddbd3980c1725",
	"userWebLink": "https://secure.mandarinpay.com/Pay?transaction=0eb51e74-e704-4c36-b5cb-8f0227621518",
	"jsOperationId": "9874694yr87y73e7ey39ed80"
}

Ответ в случае успешной токенизации (200 ОК)

{
	"id": "0eb51e74-e704-4c36-b5cb-8f0227621518",
	"userWebLink": "https://secure.mandarinpay.com/CardBindings/New?id=0eb51e74-e704-4c36-b5cb-8f0227621518",
	"jsOperationId": "binding-4994591t5-194t694159t-43t5345"
}

Ответ в случае, если транзакция не создана (400 Bad request)

{
	"error": "Invalid request"
}

# Асинхронные уведомления о статусе (callbacks)

# Аутентификация уведомлений

Для подтверждения того, что уведомление пришло именно от системы Mandarin, а также того факта, что данные, переданные в уведомлении, не были искажены, необходимо проверять значение параметра sign.

Поле sign представляет из себя хэш SHA256 от значений всех параметров уведомления, отсортированных по алфавиту и значения secret, разделённых символом -.

ОБРАТИТЕ ВНИМАНИЕ

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

Для проверки корректности расчета значения sign можете воспользоваться специальной утилитой (opens new window).

Sign Calculator UI

  • Вставьте тело callback в поле (1);
  • Вставьте secret в поле (2);
  • Значение sign будет рассчитано автоматически в поле (3).

# Параметры уведомлений

Content-Type для асинхронных уведомлений принимает значение application/x-www-urlencoded.

Уведомления высылаются в виде POST-запроса на адрес, который был передан в соответствующем запросе в опциональном параметре urls.callback. Если параметр не был передан, то для отправки POST-запроса используется адрес, который был указан в личном кабинете на закладке Интеграция.

ВАЖНО!

Количество параметров в callback-уведомлении может меняться. Могут добавляться новые параметры. Кроме того, в каждом уведомлении присутствует "соль" (параметр и значение со случайными данными).
Поэтому важно не хардкодить набор параметров!

Перечень и описание параметров, передаваемых в составе callback-уведомления

Параметр object_type хранит в себе тип: transaction (Платеж / Выплата) или card_binding(Токенизация карты). В зависимости от его значения, меняется набор других параметров!

Параметры в POST-запросе передаются в формате x-www-form-urlencoded.

Параметр Обязателен Описание
16797d04-d688-4a55-8190-861224243701 Да Соль (UUID для названия и для значения параметра генерируются случайным образом).
3dsecure Нет Индикатор подтверждения платежа с помощью ввода кода 3-D Secure.
action Нет Действие (платеж pay или выплата payout), актуально только для транзакций.
callbackUrl Нет Адрес для отправки callback.
card_binding Нет Токен карты в системе, актуален только для токенизаций.
card_expiration_month Нет Месяц срока действия карты.
card_expiration_year Нет Год срока действия карты.
card_holder Нет Владелец карты (в формате URL-encoded).
card_info_bank Нет Название банка-эмитента карты (в формате URL-encoded).
card_info_country Нет Страна банка-эмитента карты (в формате ISO 3166-1 alpha-3 (opens new window)). Например, RUS.
card_info_type Нет Название международной платежной системы карты. Например, mastercard.
card_number Нет Номер карты (маскированный).
cb_customer_creditcard_number Нет Номер карты (маскированный), поле будет убрано в следующих версиях.
cb_processed_at Нет Дата и время обработки операции.
customer_fullName Нет ФИО пользователя.
customer_email Нет Адрес email пользователя.
customer_phone Нет Телефон пользователя.
customName0 Нет Имя первого параметра (в формате URL-encoded), переданного в массиве customValues в составе запроса на оплату или токенизацию. Может существовать до 8 параметров: customName0, customName1, ... , customName7.
customValue0 Нет Значение первого параметра (в формате URL-encoded), переданного в массиве customValues в составе запроса на оплату или токенизацию. Может существовать до 8 параметров: customValue0, customValue1, ... , customValue7.
email Нет Email пользователя.
error_code Нет Код ошибки. Отсутствие кода не гарантирует успешность операции!
error_description Нет Описание ошибки.
gw_channel Нет Название канала для перевода средств.
gw_id Нет ID канала для перевода средств.
initial_hold_amount Нет Сумма авторизации, обязательна только для токенизаций.
merchantId Да ID мерчанта.
metadata_* Нет Параметры, переданные в объекте metadata в составе запроса на оплату или токенизацию. Имеют префикс metadata_.
object_type Да Тип объекта (платеж/выплата transaction или токенизация card_binding).
orderActualTill Нет Срок резервирования товара/услуги. После указанной даты оплата будет невозможна.
orderId Да Уникальный номер заказа в вашей системе.
payment_system Нет Константа mandarinpayv1, поле будет убрано в следующих версиях.
price Нет Сумма платежа, обязательна только для транзакций.
returnUrl Нет Адрес магазина для переадресации по окончанию операции.
status Да Статус операции: success, failed, payout-only. Только статус success однозначно указывает на успешность операции!
transaction Нет ID транзакции в системе. Актуален только для транзакций.
transaction_rrn Нет RRN транзакции.
sign Да Подпись для аутентификации (всегда последним).

# Параметры в объекте metadata

Запрос на токенизацию или оплату может включать в себя объект metadata, который содержит список ваших параметров с любыми названиями и любыми значениями, которые будут отправлены в callback-уведомлении. При этом на платежной странице они не будут показаны пользователю.

Например, для запроса на токенизацию:

POST https://secure.mandarinpay.com/api/card-bindings
{
	"customerInfo": {
		"email": "user@example.com",
		"phone": "+79001234567"
	},
	"metadata": {
		"first_param": "p1",
		"second_param": "p2"
	}
}

Подробнее про использование объекта metadata в запросах можно прочитать в главе Сохранение дополнительной информации.

Callback-уведомление, наряду с остальными параметрами, будет включать в себя параметры из запроса, но с префиксом metadata_:

metadata_first_param=p1&metadata_second_param=p2

# Примеры уведомлений

Пример callback-уведомления об оплате

merchantId=1&orderId=03917&email=sadukin%40mail.ru&orderActualTill=2021-02-12%2010%3A54%3A23Z&price=11040&action=pay&customName0=%D0%9D%D0%BE%D0%BC%D0%B5%D1%80%20%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80%D0%B0&customValue0=AK-247%2F0001-2021%2F1&customName1=%D0%9A%D0%BE%D0%BC%D0%B8%D1%81%D1%81%D0%B8%D1%8F&customValue1=289.15&customer_fullName=%20%20&customer_phone=%2B79189271304&customer_email=sadykin%40mail.ru&transaction=60a186c112e24b90ad839bb7bc65a9ff&object_type=transaction&status=success&payment_system=mandarinpayv1&cb_processed_at=2021-02-11T10%3A56%3A03.5789615Z&card_number=403841XXXXXX6022&cb_customer_creditcard_number=403841XXXXXX6022&card_holder=RUSLAN%20SADYKOV&card_expiration_year=23&card_expiration_month=05&gw_channel=open_way4&3dsecure=true&gw_id=39104278&metadata_first_param=p1&metadata_second_param=p2&transaction_rrn=718791158493&d000d97e-a0db-4e56-9460-6934e4bec050=4d3bb82f-fd4f-43c6-b809-2aec91e0de8a&sign=b53587e838d028cdc702cd5f59c22b8f132325f541181beb56514dd63f0dace9

Пример callback-уведомления о токенизации полных карточных данных

merchantId=1&card_binding=abbd431d-fb01-4bf9-9eb9-773b794c2df9&card_holder=RUSLAN%20MALYGIN&card_number=427638XXXXXX3811&card_expiration_year=2023&card_expiration_month=11&object_type=card_binding&status=success&initial_hold_amount=1&3dsecure=true&gw_id=39104403&card_info_country=RUS&card_info_type=mastercard&card_info_bank=SBERBANK%20OF%20RUSSIA&metadata_first_param=p1&metadata_second_param=p2&orderId=1147710&f9d6c9d1-f4d4-4a3e-8ccf-9421eb483792=0ac5dff9-7aea-4d2f-90ac-c16d730cf2a1&sign=dcc6c824310da7796888497d0537ddf9e320accdb9a00656723dd1f948fbd324

Пример callback-уведомления о токенизации со статусом payout-only

merchantId=1&card_binding=abbd431d-fb01-4bf9-9eb9-773b794c2df9&card_holder=RUSLAN%20MALYGIN&card_number=427638XXXXXX3811&card_expiration_year=2023&card_expiration_month=11&object_type=card_binding&status=payout-only&initial_hold_amount=1&metadata_first_param=p1&metadata_second_param=p2&orderId=1147710&f9d6c9d1-f4d4-4a3e-8ccf-9421eb483792=0ac5dff9-7aea-4d2f-90ac-c16d730cf2a1&sign=bb6d322474e64381f46e3c71c042d3749924a001d4a6ce5b33778ac2e5467072

Пример callback-уведомления о выплате с использованием токена карты

merchantId=1&orderId=8399235e616537a&email=sadukin%40mail.ru&orderActualTill=2021-02-22%2010%3A59%3A48Z&price=5000&action=payout&customer_fullName=%20%20&customer_phone=%2B79316537426&customer_email=sadukin%40mail.ru&transaction=85b79213245143c8a6032ef589a7069d&object_type=transaction&status=success&payment_system=mandarinpayv1&cb_processed_at=2021-02-20T10%3A59%3A52.9419268Z&card_number=220220XXXXXX4398&cb_customer_creditcard_number=220220XXXXXX4398&gw_channel=open_way4&transaction_rrn=199141256754&gw_id=39348488&c9742db9-6c45-4890-9c07-131997788bb7=6cbe0860-a643-43cd-8410-bc8ed6a64811&sign=9c97a77fbd4dbfc63d5862e5947ea11acd3697896df1eb71b4459c14988d5816

Пример callback-уведомления о выплате с использованием номера карты

merchantId=1&orderId=9537D957-AC43-4853-AB47-4E39BCFFF3FC&email=sadukin%40mail.ru&orderActualTill=2021-02-22%2010%3A48%3A17Z&price=2000.0&callbackUrl=http%3A%2F%2Fmail.example.com%3A4000%2Fapi%2Fmandarin%2Fpayout%2Fcallback&action=payout&customName0=manager_id&customValue0=E099D738-CED4-48F2-A21C-36C0EA25A549&customName1=dealer_id&customValue1=BD251868-EACA-483D-91F3-954543576F93&customName2=customer_id&customValue2=A54856FA-3A81-4742-AA73-743389D536A9&customer_fullName=%20%20&customer_phone=%2B79273884129&customer_email=sadukin%40mail.ru&transaction=52f1874b9bd846e7ab14c9f96fb9bc17&object_type=transaction&status=success&payment_system=mandarinpayv1&cb_processed_at=2021-02-20T10%3A48%3A22.7232790Z&card_number=546906XXXXXX1568&cb_customer_creditcard_number=546906XXXXXX1568&gw_channel=open_way4&transaction_rrn=105199356489&gw_id=39104021&709b674c-1f5e-424d-841e-1244d7b71041=9ee4b553-f961-4da9-b9dc-0924c0260d33&sign=a63189b75147a8bd2326baaacdd482d902206b5b6fe6de5f0df464e698b47912

Примеры проверки sign

<?php
function check_sign($secret, $req)
{
        $sign = $req['sign'];
        unset($req['sign']);
        $to_hash = '';
        if (!is_null($req) && is_array($req)) {
                ksort($req);
                $to_hash = implode('-', $req);
        }

        $to_hash = $to_hash .'-'. $secret;
        $calculated_sign = hash('sha256', $to_hash);
        return $calculated_sign == $sign;
}

check_sign("123", $_POST);
?>
public static string Calculate(string secret, IDictionary<string, string> values)
{
    using (var sha256 = System.Security.Cryptography.SHA256.Create())
        return BitConverter.ToString(sha256.ComputeHash(Encoding.UTF8.GetBytes(string.Join("-", values.OrderBy(x => x.Key, StringComparer.Ordinal).Select(x => x.Value)) + "-" + secret))).ToLower().Replace("-", "");
}

public static bool CheckSign(string secret, HttpRequest request)
{
    var sign = request.Form["sign"];
    if(string.IsNullOrWhiteSpace(sign))
      return false;
    return sign ==
        Calculate(secret, request.Form.Keys.Where(k => k != "sign").ToDictionary(k => k, k => request.Form[k]));
}

# Повторная отправка уведомлений

В качестве ответа, обозначающего, что callback успешно обработан на вашей стороне, необходимо вернуть в Mandarin ответ с HTTP-кодом 200 и телом OK.

ВАЖНО!

Любой другой ответ будет означать, что callback не обработан. В этом случае Mandarin повторяет отправку callback-запроса в течение 3 суток, или до получения ответа об успешной обработке (в зависимости от того, что наступит раньше).

# Лимиты для запросов к API

Ограничения и лимиты для запросов к API:

  • На реккурентные платежи: не более 100 запросов в секунду, и не более 1000 запросов в минуту.

  • На возвраты: максимальная сумма возврата, и максимальное количество возвратов (устанавливается по заявке клиента).

  • На платежи: лимит на покупку (устанавливается по заявке клиента).