Skip to content

© 2026 ООО «Аксиома» ИНН:7842223709 · mock-services · Apache-2.0 SPDX-License-Identifier: Apache-2.0

tbank-mock — мок-стенд Т-Банк: эквайринг, Мультирасчёты и E2C ​

Локальный тестовый банк с HTTP-контрактами /v2/*, E2C-выплатами, проверкой счёта, рекуррентными платежами, СБП/QR, партнёрской регистрацией, Token-подписью, платёжной формой, подписанными нотификациями и админ-консолью. Профиль plain (по умолчанию) моделирует обычный эквайринг; multisplit добавляет обязательные поля и балансовые правила Мультирасчётов. Исследовательская база — конспекты провайдеров в приватном репозитории mock-services-docs; публичный источник — официальная документация Т-Банка.

Node.js >= 18; внешние npm-зависимости не нужны. Сервер использует общий модуль packages/core для HTTP, персистентности, sandbox и защитных helpers.

Зачем ​

Реальный тестовый контур банка недоступен без договора + IP-whitelist и требует запросов с боевого терминала (см. RES-007 §1). Мок даёт управляемые сценарии: успех/frictionless, 3DS-challenge, недостаточно средств, отказы, частичные возвраты, дубли и ретраи нотификаций, авто-подтверждение холда.

Запуск ​

bash
docker compose up -d tbank-mock          # порт 3100
# или голым node
MOCK_TERMINAL_KEY=TBANKMOCKTEST MOCK_TERMINAL_PASSWORD=mockpass123 node services/tbank-mock/server.js

Самотест (48 сценариев: контракты эквайринга/Мультирасчётов/E2C, TerminalKey и CSRF, песочницы, подписи и webhook-ретраи; все процессы слушают ephemeral-порты):

bash
npm run test:tbank

Подключение своего приложения к моку ​

Приложение ходит в мок как в банк: укажите в конфигурации базовый URL мока и креды стенда (внутри docker-сети сервис доступен как http://tbank-mock:3100):

env
TBANK_API_URL=http://tbank-mock:3100/v2   # или http://localhost:3100/v2 с хоста
TBANK_TERMINAL_KEY=TBANKMOCKTEST          # те же ключи видит мок
TBANK_TERMINAL_PASSWORD=mockpass123
TBANK_NOTIFICATION_URL=https://<ваш домен>/api/v1/payments/tbank/webhook

Клиент не меняется: запросы подписываются Token (sha256) как в бою, нотификации приходят снаружи и проверяются по-настоящему. Пошаговая цепочка curl — в гайде «за 10 минут».

API мока ​

МаршрутПоведение
POST /v2/Initсоздаёт платёж; профиль plain допускает обычный эквайринг без сделки, multisplit валидирует DealId/CreateDealWithType и PaymentRecipientId; повторный OrderId отклоняется, если явно не разрешён
POST /v2/Confirm, Cancel, GetState, CheckOrderподтверждение, отмена/возврат, поиск по PaymentId или OrderId, история попыток по заказу
POST /v2/Chargeback, Dispute; GET /v2/Dispute/{id}dispute/chargeback transitions (DISPUTED → REPRESENTMENT → ARBITRATION → WON/LOST) с подписанными нотификациями
POST /v2/createSpDeal, closeSpDealсоздание/закрытие сделки Мультирасчётов (также поддерживаются имена CreateSpDeal/CloseSpDeal)
POST /e2c/v2/Init, Payment, GetState, CancelPayment, GetSbpMemberspayout по карте, СБП или партнёру; баланс сделки, FinalPayout, отмена партнёрской выплаты и список участников СБП. Все запросы подписываются и проверяют допустимый TerminalKey
POST /v2/GetQr; POST /payment/{id}/sbp-payQR СБП и тестовая оплата через СБП
POST /v2/Charge, AddCustomer, GetCustomer, RemoveCustomer, AddCard, GetCardList, RemoveCardрекуррентные платежи и управление тестовыми картами покупателя
POST /v2/SendClosingReceiptтестовый закрывающий чек
POST /av/v1/payment, /av/v1/verificationaccount verification: «прогон рубля» и проверка счёта
POST /oauth/token, /sm-register/register*тестовая OAuth-регистрация партнёра/магазина для E2C partner payouts
GET /payment/{id}; POST /payment/{id}/pay, /otp, /done, /rejectHTML-форма и тестовые сценарии карт; challenge использует OTP 1qwezxc
GET /mock/time; POST/PUT /mock/time; GET /mock/scenarios; POST/DELETE /mock/scenariosвиртуальные часы, сценарные правила и история срабатываний; для разового запроса — X-Mock-Scenario
GET /adminконсоль платежей, споров, сделок, уведомлений, поступлений и верификаций; действия форм защищены подписанным CSRF-токеном и same-origin проверкой
GET /admin/journal, GET /openapi.json, GET /healthжурнал API с редактированием секретов/PII, OpenAPI 3.1 и health-check

Правила, история срабатываний и журнал /admin/journal принадлежат текущей песочнице (#52): другие песочницы их не видят и не очищают, POST /mock/reset действует только на целевую песочницу. Лимиты: до 200 правил на песочницу и до 8 KiB на правило (превышение — HTTP 400 с code rule_cap_exceeded/rule_too_large).

acqapi: OAuth и регистрация точки ​

POST /oauth/token принимает только фактический Basic-клиент: по умолчанию partner:partner, либо MOCK_ACQAPI_CLIENT_ID + MOCK_ACQAPI_CLIENT_SECRET. Поддерживаются grant_type=password (документированный контур) и client_credentials; ответ выдаёт случайный opaque Bearer со scope=partner и TTL 3600 секунд (переопределяется MOCK_ACQAPI_TOKEN_TTL_MS). Токен проверяется на POST/GET/PATCH /sm-register/register*; произвольная строка Bearer, истёкший токен и запрос без Authorization возвращают 401.

Регистрация требует полную JSON-схему из документации Т-Банка: shopArticleId (латиница/цифры/._-, до 32 символов), billingDescriptor, fullName, name, inn, kpp, ogrn, непустые addresses[] (type, zip, country ISO-3, city, street), ceo.phone/ceo.citizenship, founders.individuals[], email, siteUrl, bankAccount (account, korAccount, bankName, bik, details) и boolean nonResident. kbk и oktmo при передаче обязательны парой; mcc допускается как 4-значный override. shopArticleId без генерации маппится в shopCode, который используется как PartnerId в e2c-выплате. Валидация выполняется до записи state.

Терминал проверяется вместе с подписью во всех payout-операциях, включая Payment, GetState, GetSbpMembers и CancelPayment; неверный или отсутствующий TerminalKey возвращает provider-shaped ошибку до поиска/изменения выплаты. MOCK_ADMIN_TOKEN ограничивает консоль, а native POST-формы передают CSRF-токен и сохраняют query-token админки и owner-token owned-песочницы при отправке/redirect.

Нотификации: подписанный POST (Token покрывает SpAccumulationId) на NotificationURL из Init; ответ должен быть ровно OK, иначе ретраи (MOCK_RETRY_MS × MOCK_MAX_ATTEMPTS, по умолчанию 60 с × 24 — как у банка «раз в час в течение суток», но сжато для тестов). Нотифицируемые статусы: AUTHORIZED, CONFIRMED, REVERSED, PARTIAL_REVERSED, REFUNDED, PARTIAL_REFUNDED, REJECTED.

Надёжность очереди (после аудита 2026-10-08): одна нотификация = максимум один POST «в полёте» (ретраи не накладываются), доставленные записи помечаются done и не переотправляются, а недоставленные переживают рестарт с MOCK_STATE_FILE и продолжают ретраиться.

Песочницы и hosted tenancy (RFC-001, A-21) ​

Каждый запрос разрешает свою песочницу один раз и дальше видит только её состояние, креды и персистентность: параллельные A/B-запросы не смешиваются между await, а запрос без селектора всегда попадает в default, а не остаётся в предыдущей песочнице. Селектор: X-Mock-Sandbox: <id> → ?sandbox=<id> → поддомен <id>.<MOCK_SANDBOX_HOST_SUFFIX> (если суффикс задан). PaymentURL платежа в именованной песочнице уже содержит ?sandbox=<id>.

РежимВключаетсяПоведение
namespacesдефолт self-hosted; MOCK_TENANCY=namespacesX-Mock-Sandbox создаёт изолированное пространство имён для параллельных CI-воркеров; креды и управляющие токены — общие
ownedMOCK_HOSTED=1 по умолчанию; MOCK_TENANCY=owned (legacy 1/on/true/yes)у каждой песочницы свои креды и owner-token (показывается один раз); знание id без owner-token доступа не даёт (401), неизвестный id — 404, истёкший — 410
offMOCK_TENANCY=off (legacy 0/false/no)одна общая песочница default; селектор игнорируется

API (в owned — с owner-token; в namespaces те же маршруты управляют пространствами имён без owner-token):

ЗапросЧто делает
POST /sandboxesсоздать песочницу: id, url, creds (свой TerminalKey/TerminalPassword) и ownerToken — показывается один раз
GET /sandboxes (алиас GET /mock/sandboxes)список: владельцу — своя песочница, оператору (MOCK_OPERATOR_TOKEN) — все
DELETE /sandboxes?sandbox=<id>удалить песочницу вместе с состоянием (владелец или оператор)
GET /sandboxes/meсвоя песочница: состояние, креды, TTL, расход квоты; POST /sandboxes/me/reset, POST /sandboxes/me/reset-creds, DELETE /sandboxes/me

Owner-token принимается в Authorization: Bearer, X-Sandbox-Token или ?sandbox_token=. Персистентность: реестр песочниц пишется атомарно и поштучно — по файлу <MOCK_STATE_FILE>.sandboxes.records/<id>.json на песочницу (хэши owner-токенов + снимки состояния; мутация переписывает только свою песочницу, PD-02), а default всегда восстанавливается только из MOCK_STATE_FILE — состояние именованной песочницы не может быть выдано за default (F-14). Просроченные песочницы удаляет sweep-воркер; квота документов (MOCK_SANDBOX_MAX_DOCUMENTS) проверяется до создания платежа/сделки/выплаты и отвечает ошибкой 7 с подсказкой.

Тестовые карты (как у банка, oplata_multisplit.pdf §7) ​

PANСценарий
2201382000000013успех, frictionless
2201382000000047успех, challenge (OTP 1qwezxc, 3 попытки)
2201382000000039 / 5586200071492158 / 2200770239097761успех (attempts / 3DS1 / без 3DS)
2201382000000831 / 4249170392197566недостаточно средств
5586200071499591недостаточно средств при сумме > 1000 ₽, иначе успех
2201382000000021 / 2201382000000005 / 5586200071492075отказы

Конфиг (env) ​

ПеременнаяПо умолчаниюЧто делает
MOCK_PORT / MOCK_HOST3100 / 0.0.0.0прослушивание
MOCK_PROFILEplainplain — обычный эквайринг; multisplit — требования Мультирасчётов и валидация сделок
MOCK_TERMINAL_KEY / MOCK_TERMINAL_PASSWORDTBANK_TERMINAL_* из env ядра, иначе TBANKMOCKTEST/mockpass123ключи терминала мока
MOCK_PUBLIC_BASE_URLhttp://localhost:${MOCK_TBANK_HOST_PORT:-3100}база для PaymentURL (виден покупателю!)
MOCK_ACQAPI_CLIENT_ID / MOCK_ACQAPI_CLIENT_SECRETpartner / partnerфактические Basic-креды acqapi; секрет не печатается и не хранится в state
MOCK_ACQAPI_TOKEN_TTL_MS3600000 (1 ч)TTL Bearer-токена acqapi; виртуальные часы применяются для проверки истечения
MOCK_DEFAULT_NOTIFICATION_URL—куда слать нотификации, если Init без NotificationURL
MOCK_RETRY_MS / MOCK_MAX_ATTEMPTS60000 / 24политика ретраев нотификаций
MOCK_STRICT_TOKENtrueотклонять запросы без валидного Token
MOCK_ALLOW_DUPLICATE_ORDER_IDfalseразрешить повторный Init с тем же OrderId (по умолчанию — ошибка 7, как в банке)
MOCK_BLOCK_PRIVATE_WEBHOOKSfalse (в MOCK_HOSTED=1 — true)не отправлять нотификации на приватные адреса и имена, которые в них резолвятся (1/true; 0/false выключает явно)
MOCK_OPERATOR_TOKEN—токен управляющей поверхности: /mock/* и GET /v2/Dispute/{id} (fallback — MOCK_ADMIN_TOKEN)
MOCK_ADMIN_TOKEN—токен админки /admin*; query-токен из страницы сохраняется в action URL, POST дополнительно требует CSRF-токен и same-origin
MOCK_HOSTEDfalsehosted-режим: управляющая поверхность fail-closed без токена, SSRF-политика по умолчанию
MOCK_TENANCYowned при MOCK_HOSTED=1, иначе namespacesowned/namespaces/off; legacy 1/on/true/yes → owned, 0/false/no → off; неизвестное непустое значение пишет WARN и безопасно возвращается к default
MOCK_SANDBOX_TOKEN—owner-token default-песочницы. При MOCK_HOSTED=1 без него default не обслуживается (MS-12: бизнес/form → 404, стартовый лог default=closed); в self-hosted default открыта с предупреждением при старте
MOCK_SANDBOX_TTL_MS24 ч в hosted, иначе 0 (бессрочно)TTL именованной песочницы; истёкшие удаляет sweep-воркер
MOCK_SANDBOX_MAX100 в hosted, иначе 256максимум именованных песочниц
MOCK_SANDBOX_MAX_DOCUMENTS5000 в hosted, иначе 0 (без лимита)квота документов песочницы (F-15)
MOCK_SANDBOX_HOST_SUFFIX—суффикс поддоменов песочниц, напр. mock-services.dev: <id>.mock-services.dev
MOCK_SANDBOX_CREATE_LIMIT20 в hosted, иначе 0лимит создания песочниц на IP в час
MOCK_SANDBOX_FILE<MOCK_STATE_FILE>.sandboxes.jsonбаза реестра песочниц: поштучные файлы в каталоге <база без .json>.records/ (owner-токены — только хэши); legacy-файл <база> переносится при старте и переименовывается в .migrated
MOCK_SANDBOX_SWEEP_MS60000интервал воркера TTL/retention
MOCK_SANDBOX_RETENTION_MS0 (выкл.)retention диагностических записей (доставленные нотификации, завершённые верификации)
MOCK_AUTO_CONFIRM_MS0 (выкл.)авто-подтверждение холда через N мс (банк делает это через 4/7 дней)
MOCK_VIRTUAL_CLOCK—ISO-старт виртуальных часов стенда (TTL AccessToken, срок холда 7 дней, авто-отмена сделки 60 дней, ретраи нотификаций)
MOCK_STATE_FILE—файл персистентности (JSON); без него состояние в памяти

Границы симуляции ​

  • Это локальный mock server, а не тестовый/боевой контур банка: платежи, выплаты, СБП и account verification имеют только синтетическое состояние; реальные карты, ключи и персональные данные использовать нельзя.
  • Поддерживаются только маршруты и конечные автоматы, перечисленные выше. Не реализованные методы возвращают provider-shaped ошибку «501»; наличие тестового ответа не означает сертификацию или полную эквивалентность API банка.
  • Список SBP-участников и карточные сценарии статические. Состояние хранится в памяти, если не задан MOCK_STATE_FILE; никакие операции не проводят реальные денежные средства.
  • Перед изменением production-интеграции сверяйте поля и статусы с актуальной документацией Т-Банка и согласованным профилем (plain/multisplit).

Байтовые квоты состояния (PD-02) ​

EnvДефолтНазначение
MOCK_SANDBOX_MAX_STATE_BYTESпусто: 8388608 (8 МиБ) при maxDocuments > 0, иначе без лимитабайты JSON одной песочницы; 0 выключает
MOCK_SANDBOX_GLOBAL_MAX_STATE_BYTES67108864 (64 МиБ)сумма байт JSON всех песочниц рантайма, включая default; 0 выключает

Значения задаются в целых байтах. Пусто сохраняет дефолты. Квота per-sandbox не ограничивает память контейнера; общий бюджет меньше mem_limit: 128m, но не равен RSS. Превышение глобального бюджета на записи или байтовых квот при импорте /mock/state → HTTP 400, errorCode: 400, kind: 'bytes', code: sandbox_state_budget_exceeded / sandbox_state_quota_exceeded, с откатом отклонённого состояния. Правила/история/журнал остаются volatile. Подробности и границы — документация ядра.