FAQ — пополнения клиентам Т-Банка
Как сформировать цифровую подпись
Извлеките и канонизируйте
data— из исходного JSON-документа извлеките значение поляdataкак отдельный JSON-объект и приведите его к каноническому виду по стандарту RFC 8785.- Поля объекта отсортированы лексикографически — по имени ключа в
UTF-8. - Нет пробелов, переносов и отступов — строка должна быть максимально компактной.
- В одном объекте не должно быть повторяющихся ключей.
- Кодировка —
UTF-8. - Числовые поля должны быть конечными и представимыми в формате
IEEE 754.
- Поля объекта отсортированы лексикографически — по имени ключа в
Вычислите хеш от канонизированной строки
dataс использованием алгоритма ГОСТ Р 34.11-2012.Для полученного хеша вычислите значение подписи с использованием алгоритма ГОСТ Р 34.10-2012.
Добавьте в исходный JSON блок
crypto:- sign – электронная подпись, представленная в виде строки в формате
Base64; - serial – серийный номер публичного сертификата, которым может быть проверена данная подпись;
- algorithm – использованный при создании подписи криптоалгоритм.
- sign – электронная подпись, представленная в виде строки в формате
Измененять структуру поля data и кодировку документа нельзя.
Поддерживаемые алгоритмы шифрования — передается в запросе в crypto.algorithm:
| Значение | Описание |
|---|---|
| Crypto-pro 2012-256 | ГОСТ Р 34.11/34.10-2012 с длиной ключа 256 бит |
| Crypto-pro 2012-512 | ГОСТ Р 34.11/34.10-2012 с длиной ключа 512 бит |
Пример реализации на Java
public class SignExample {
private static class SortingNodeFactory extends JsonNodeFactory {
@Override
public ObjectNode objectNode() {
return new ObjectNode(this, new TreeMap<>());
}
}
private static final SimpleModule BIG_NUMBER_SERIALIZER = new SimpleModule()
.addSerializer(BigInteger.class, new ToStringSerializer())
.addSerializer(BigDecimal.class, new ToStringSerializer());
private static final ObjectMapper MAPPER = JsonMapper.builder()
.nodeFactory(new SortingNodeFactory())
.enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY)
.addModule(new JavaTimeModule())
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.addModule(BIG_NUMBER_SERIALIZER)
.build();
@SneakyThrows
public static void main(String[] args) {
// инициализируем криптопро
final KeyStore keyStore = initCryptoPro();
// создаем POJO запроса
final PartnersRequest request = generatePartnersRequest();
// серилизуем в JSON блок data
final String dataJson = MAPPER.writeValueAsString(request.getData());
// получем подпись блока data (если алгоритм, например crypto-pro 2012-256)
final byte[] sign = makeSign_2012_256_handsome(keyStore, dataJson);
// получаем base64 строку
final String base64Sign = Base64.getEncoder().encodeToString(sign);
// заполняем поле подписи
request.getCrypto().setSign(base64Sign);
// получаем готовый JSON
final String json = MAPPER.writeValueAsString(request);
System.out.println(json);
}
@SneakyThrows
private static byte[] makeSign_2012_256_handsome(final KeyStore keyStore, final String strForSign) {
PrivateKey privateKey = (PrivateKey) keyStore.getKey(KEY_ALIAS, KEY_PASSWORD);
final MessageDigest digest = MessageDigest.getInstance(JCP.GOST_DIGEST_2012_256_NAME, JCP.PROVIDER_NAME);
final byte[] data = strForSign.getBytes(StandardCharsets.UTF_8);
byte[] signedData = digest.digest(data);
final Signature signature = Signature.getInstance(JCP.RAW_GOST_SIGN_2012_256_NAME);
signature.initSign(privateKey);
signature.update(signedData);
return signature.sign();
}
}
Обязательность полей
В методах Пополнения клиентам Т-Банка
обязательными помечены только те поля, которые являются обязательными независимо от значения data.sourceCode.
Полный состав полей в запросе и ответе зависит от значения data.sourceCode и
согласовывается индивидуально на этапе подключения к API.
Обязательные поля в запросе для data.amount > 15 000
Передавать следующие поля при data.amount <= 15 000 необязательно, но
допустимо — логика не нарушится:
- data.senderInfo.lastName
- data.senderInfo.firstName
- data.senderInfo.address
Обязательные поля в зависимости от data.sourceCode
Список полей не зависит от значения data.amount — эти поля
должны передаваться во всех запросах.
Обязательные поля в запросе
data.senderInfo.extraInfo
Обязательные поля в ответе
- mainData.additionalInfoPartners.identificationCheck
- mainData.additionalInfoPartners.nameS
- mainData.additionalInfoPartners.lastCardNumber
- mainData.additionalInfoPartners.fullName
- mainData.additionalInfoPartners.recHash
Возможные коды ответов
Успешные коды ответов
result | comment | Описание | ||
|---|---|---|---|---|
| 200 | 0 | Нет | – | Запрос успешно обработан |
Бизнес-ошибки
result | comment | ||
|---|---|---|---|
| 200 | 141 | Нет | Неверный номер договора получателя. |
| 200 | 142 | Нет | Неверный номер карты получателя. |
| 200 | 143 | Нет | Неверный номер телефона получателя. |
| 200 | 144 | Нет | Невозможно однозначно определить получателя платежа, найдено более одного контакта с данным номером телефона. |
| 200 | 146 | Нет | Неверный номер телефона или переданный номер телефона не принадлежит оператору. |
| 200 | 149 | Нет | Неверный номер счета получателя. |
| 200 | 151 | Нет | Сумма перевода меньше минимальной. |
| 200 | 152 | Нет | Сумма перевода больше максимальной. |
| 200 | 153 | Нет | Сумма пополнения после конвертации равна 0. |
| 200 | 159 | Нет | Невозможно идентифицировать клиента по переданным реквизитам пополнения. |
| 200 | 160 | Нет | Отсутствуют идентификационные данные при сумме пополнения больше 15 000 рублей. |
| 200 | 161 | Нет | Данная операция невозможна. |
| 200 | 162 | Нет | ФИО плательщика и клиента не совпадают. |
| 200 | 163 | Нет | Идентификатор получателя не соответствует юридическому лицу. |
| 200 | 164 | Нет | Недостаточный уровень идентификации. |
| 200 | 165 | Нет | Пополнение по этим реквизитам невозможно. |
| 200 | 171 | Нет | Ошибка при проверке подписи. |
| 200 | 181 | Нет | Отсутствует успешный авторизационный запрос с переданным идентификатором. |
| 200 | 191 | Да | На балансе контрагента недостаточно средств для проведения данной операции. Попробуйте позже. |
| 200 | 301 | Нет | По техническим причинам пополнение невозможно. |
Технические ошибки
result | errMessage | ||||
|---|---|---|---|---|---|
| 200 | 400 | Техническая ошибка | Да | – | По техническим причинам пополнение невозможно. Рекомендуется повторить запрос. |
| 400 | – | Техническая ошибка | Нет | Bad Request | Запрос составлен некорректно — ошибка валидации, JSON, структура. |
| 401 | – | Техническая ошибка | Нет | Unauthorized | Не передан или невалиден токен доступа. |
| 403 | – | Техническая ошибка | Нет | Forbidden | Доступ к ресурсу запрещен — недостаточно прав. |
| 422 | – | Техническая ошибка | Нет | Unprocessable Entity | Запрос синтаксически верен, но не может быть обработан — логическая ошибка. |
| 429 | – | Техническая ошибка | Да | Too Many Requests | Превышен лимит запросов. Рекомендуется повторить запрос. |
| 500 | – | Техническая ошибка | Да | Internal Server Error | Внутренняя ошибка сервера. Рекомендуется повторить запрос позже. |
Правила повторной отправки запроса
Если вы получили ответ, который требует повторной отправки запроса, значения полей
data.sourceCode и data.sourceId должны совпадать со значениями оригинального
запроса — иначе повторный запрос будет расценен как новый.