Appearance
© 2026 ООО «Аксиома» ИНН:7842223709 · mock-services · Apache-2.0 SPDX-License-Identifier: Apache-2.0
Интеграция: интернет-эквайринг Альфа-Банка через mock (10 минут)
Мок воспроизводит REST-интерфейс шлюза Альфа-Банка (/payment/rest/*.do, платформа RBS) по публичной документации: регистрация заказа с form-параметрами, платёжная страница formUrl с тестовыми картами и ACS, статусы getOrderStatus(Extended).do, двухстадийная схема (registerPreAuth → deposit), reverse, полный/частичный refund и callback-уведомления HTTP GET с симметричным checksum HMAC-SHA256. Источники: официальные разделы — REST-интерфейс, тестовые карты.
Это не Т-Банк и не drop-in. Маршруты —
POST /payment/rest/*.doсapplication/x-www-form-urlencoded(у Т-Банка JSONPOST /v2/*), креды —userName/passwordв каждом запросе (у Т-БанкаTerminalKey+ подписьToken), ответ регистрации —{orderId, formUrl}сerrorCode/errorMessage(у Т-Банка{Success, Status, PaymentId}), callback — GET с query (у Т-Банка подписанный POST), статусы — числовыеorderStatus 0…6(у Т-Банка строковыеNEW/AUTHORIZED/…). Перенос кода между банками неизбежен; мок подсказывает расхождения вhint.
Вне области стенда: асимметричный режим checksum (официальный PDF противоречив: описание говорит SHA-256, примеры SHA512withRSA / OPENSSL_ALGO_SHA512 — SHA-512; режим подтверждается банком, поэтому не домысливается), привязки карт (bindingId), моделирование orderBundle.
1. Поднять стенд
bash
docker compose up -d alfa-mock # http://localhost:3104
# или без docker: npm run start:alfaСтартовый лог печатает синтетические дефолты стенда (значения, заданные через env, скрыты — <задан через env, скрыт>):
creds: userName=ALFAMOCKTEST password=mockpass123 callback_secret=mocksecret123 (дефолты СИНТЕТИЧЕСКИЕ, по образцу TBANKMOCKTEST; ...)Это синтетические креды мока, а не реквизиты банка. Реальные тестовые userName/password Альфа-Банк выдаёт индивидуально при подключении — поэтому в дефолты конфига они не зашиты (и не должны). Свои значения — MOCK_ALFA_USERNAME, MOCK_ALFA_PASSWORD, MOCK_ALFA_CALLBACK_SECRET.
2. Зарегистрировать заказ
register.do — одностадийная оплата; registerPreAuth.do — холд (двухстадийная схема, включается банком; на стенде — MOCK_TWO_STAGE, по умолчанию включена). Параметры — form-urlencoded: обязательны userName, password, уникальный orderNumber, amount в копейках, returnUrl.
bash
curl -sS -X POST http://localhost:3104/payment/rest/register.do \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'userName=ALFAMOCKTEST' \
--data-urlencode 'password=mockpass123' \
--data-urlencode 'orderNumber=demo-0001' \
--data-urlencode 'amount=10000' \
--data-urlencode 'returnUrl=https://shop.test/alfa/return' \
--data-urlencode 'failUrl=https://shop.test/alfa/fail' \
--data-urlencode 'sessionTimeoutSecs=1200' \
--data-urlencode 'jsonParams={"callback_url":"https://shop.test/alfa/callback"}'json
{
"errorCode": 0,
"errorMessage": "",
"orderId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"formUrl": "http://localhost:3104/payment/3fa85f64-5717-4562-b3fc-2c963f66afa6",
"hint": "errorCode=0 — результат обработки API-вызова, не эквивалент финального статуса оплаты…"
}Перенаправьте покупателя на formUrl. Ключевые ловушки, которые мок воспроизводит как банк:
orderNumberуникален в пределах магазина: повтор —errorCode 1, а не идемпотентный replay прежним заказом;amount— копейки (100.00 ₽ =10000); дроби и «1000.9» —errorCode 5;errorCode=0— результат API-вызова, не факт оплаты: финальный статус только черезgetOrderStatusExtended.doили callback;sessionTimeoutSecs(дефолт стенда1200= 20 минут): по истечении заказ отклоняется —orderStatus=6и callbackdeclinedByTimeout.jsonParams.callback_url— mock-расширение (в бою приёмник уведомлений задаётся в настройках мерчанта банком); альтернатива на стенде —MOCK_DEFAULT_CALLBACK_URL.
3. Оплатить на форме (тестовые карты)
На formUrl — пресеты тестовых карт (официальный список тестовых карт): успех 4111111111111111 (3DS1), 639002000000000003 (МИР 3DS1), 3DS2-frictionless 2201382000000062, 3DS2-challenge 2200000000000053 и другие; отказы -2011 (3DS PaRes=U: 5555555555555557, 4444333322221111, 5555555544444442), 116 (недостаточно средств: 5432543254325430, CVV 521), без-3DS карта 5555555555555599 (успех только при MOCK_SSL_PERMITTED=true). Пароль тестового ACS — 12345678; владелец карты — минимум два слова латиницей. Неверный срок/CVV или кнопка Fail на ACS — шлюзовой код 71015 («введённая информация неверна»). Данные карт не хранятся: в заказе остаётся только маска first6**last4.
4. Сверить статус (серверная сверка)
bash
curl -sS -X POST http://localhost:3104/payment/rest/getOrderStatusExtended.do \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'userName=ALFAMOCKTEST' \
--data-urlencode 'password=mockpass123' \
--data-urlencode 'orderId=3fa85f64-5717-4562-b3fc-2c963f66afa6'orderStatus (общая нумерация платформы RBS): 0 — зарегистрирован, не оплачен; 1 — холд; 2 — оплата проведена; 3 — reverse; 4 — возврат; 5 — ACS; 6 — отказ. Расширенный ответ различает суммы authorizedAmount / depositedAmount / refundedAmount и код шлюза actionCode с описанием. Вместо orderId можно передать orderNumber.
5. Двухстадийная схема, reverse и refund
registerPreAuth.do→ оплата на форме → холд (orderStatus=1, callbackapproved);deposit.doсamountне больше авторизованной суммы (частичное подтверждение допустимо, остаток холда освобождается) →orderStatus=2, callbackdeposited.depositбольше холда —errorCode 5, повторныйdeposit—errorCode 4;reverse.do— отмена холда (1) или оплаты до окончательного расчёта (2) →orderStatus=3, callbackreversed;refund.do— полный/частичный возврат списанного (2/4), сумма ≤depositedAmount − refundedAmount→orderStatus=4, callbackrefunded. Возврат больше списанного —errorCode 5; частичные возвраты отключаются флагомMOCK_PARTIAL_REFUND=false(«разрешённый контур»).
6. Callback: HTTP GET + checksum HMAC-SHA256
Уведомление приходит GET-запросом с query-параметрами: mdOrder (= orderId), orderNumber, operation (approved, deposited, reversed, refunded, declinedByTimeout, declinedCardpresent), status (1 — операция успешна, 0 — завершилась ошибкой), amount (копейки), callbackCreationDate и checksum.
ACK — ровно HTTP 200. Любой другой код (включая 204 и 3xx) банк считает неуспехом и повторяет доставку; число попыток и интервал в официальном PDF не указаны — на стенде это MOCK_CALLBACK_RETRY_MS × MOCK_CALLBACK_MAX_ATTEMPTS (mock-конфигурация, не параметры банка).
Проверка checksum (симметричный режим): удалить checksum и sign_alias, отсортировать оставшиеся имена параметров в алфавитном порядке, построить строку name;value;name;value;…;, вычислить HMAC-SHA256 с общим секретным ключом и сравнить hex в верхнем регистре:
js
const crypto = require('crypto');
function verifyAlfaCallback(query, secret) {
const params = Object.fromEntries(new URLSearchParams(query));
const received = params.checksum;
delete params.checksum;
delete params.sign_alias;
const canonical = Object.keys(params).sort().map((k) => `${k};${params[k]};`).join('');
const expected = crypto.createHmac('sha256', secret).update(canonical).digest('hex').toUpperCase();
return received !== undefined && received.toUpperCase() === expected;
}Две оговорки, которые обязан закрывать ваш код (и которые мок умеет эмулировать):
- Callback может прийти без checksum (
MOCK_CALLBACK_CHECKSUM=false): неподписанное уведомление можно подделать — не меняйте по нему состояние заказа, сверяйтесь черезgetOrderStatusExtended.do; declinedCardpresentв опубликованном PDF перечислена без детальной семантики — мок отправляет её при отказе карточной авторизации соstatus=0; источник истины — расширенный статус (orderStatus=6,actionCode).
Асимметричный режим (проверка подписи публичным ключом сертификата, признак — sign_alias) стендом не реализуется: официальный PDF противоречив (SHA-256 в описании против SHA-512 в примерах кода), а угадывать алгоритм подписи нельзя.
7. Что мок проверяет за вас
- неверные
userName/password—errorCode 2с подсказкой, где взять креды стенда (реальные банковские креды в дефолты не зашиты); - повтор
orderNumber—errorCode 1(уникальность в пределах магазина); - некорректные
amount/returnUrl/currency/jsonParams—errorCode 5сfieldиhint; - операции не в том статусе (
depositбез холда,refundдо списания, повторныйreverse) —errorCode 4с объяснением по текущемуorderStatus; - неизвестный заказ —
errorCode 3; - сетевые сбои до бизнес-логики:
X-Mock-Scenario: http-500|http-504(честные HTTP-коды) иlatency:2s; - системный сбой шлюза:
X-Mock-Scenario: fail—errorCode 6c HTTP 200; hang— ответ не приходит вовсе (проверка ваших клиентских таймаутов);- ретраи и дубли callback: приёмник, отвечающий не-200, получает повторы (
webhook-drop/webhook-duplicate— сценарии подачи/подавления).
Журнал запросов с curl-сниппетами — GET /admin/journal (креды в нём редактируются, PAN не попадает вовсе); сценарные правила — /mock/scenarios; ускорение времени (таймауты сессий, ретраи) — POST /mock/time {"advance":"+25m"}.
8. Песочницы и арендаторы
POST /sandboxes (режим MOCK_TENANCY=owned) выдаёт изолированную песочницу с своими кредами: userName, password и callbackSecret (секрет checksum) плюс ownerToken (показывается один раз). Дальше — заголовок X-Sandbox-Token: <ownerToken> или ?sandbox=. Сброс — POST /sandboxes/me/reset, перевыпуск кредов — POST /sandboxes/me/reset-creds (ownerToken сохраняется).
9. Чеклист готовности к бою
- [ ] координаты сверены с банком: production-адрес не всегда
https://payment.alfabank.ru/payment/rest— для части merchant-логинов и схем (без префикса, r-, i-) URL и инструкции различаются; - [ ] тестовые
userName/passwordполучены от банка индивидуально (синтетика стенда — только для локальной разработки); - [ ]
orderNumberуникален в пределах магазина,amount— в копейках; - [ ] после возврата браузера статус сверяется серверно (
getOrderStatusExtended.do),errorCode=0не трактуется как оплата; - [ ] приёмник callback отвечает ровно HTTP 200, идемпотентен (дубли возможны) и проверяет checksum;
- [ ] неподписанные callback (без
checksum) не меняют состояние заказа — только сверка через REST; - [ ] режим checksum (симметричный/асимметричный) подтверждён банком; при асимметричном — уточнён алгоритм (SHA-256 или SHA-512) и
sign_alias; - [ ] двухстадийная схема и частичные возвраты согласованы с банком (на стенде —
MOCK_TWO_STAGE,MOCK_PARTIAL_REFUND); - [ ] HTTPS-приёмника: доверенный сертификат, RSA ≥ 2048, хеш ≥ SHA-256;
- [ ] обработаны отказы:
-2011(PaRes=U),116(недостаточно средств),71015(неверные данные/ACS Fail),declinedByTimeout(истёкsessionTimeoutSecs); - [ ] нагрузки на тестовый контур не создаётся (нагрузочное тестирование договором запрещено).
10. Ссылки
- Контракт сервиса, env и
/mock/*:services/alfa-mock/README.md - OpenAPI 3.1:
docs/openapi/alfa-mock.openapi.json - Манифест протокола для
npm run check:drift:protocols/alfa-eacq.json - Общая инфраструктура адаптеров (часы, песочницы, вебхуки, SSRF):
packages/core/README.md