Перейти к основному содержимому

Платёжный домен платформы

Версия: 1.0 Дата: 26.04.2026 Статус: Готов к обсуждению

Назначение документа

Документ определяет каноничную модель платёжного домена (payment domain) платформы Vitiana — сущности, статусную машину, абстракцию слоя провайдеров платёжных услуг (payment service providers, PSP), стыковку с моделями отвечающего за платежи продавца (merchant-of-record, MoR), требования усиленной аутентификации клиента (Strong Customer Authentication, SCA), процедуры возвратов (refunds) и возвратных платежей (chargebacks), область применимости стандарта безопасности данных платёжной индустрии (Payment Card Industry Data Security Standard, PCI DSS), фазы развёртывания и события платёжного контура.

Документ читается после Архитектурный якорь и бизнес-модель и Соответствие требованиям регуляторов. Эти два документа фиксируют что платформа делает с моделью отвечающего за платежи продавца и какие нормативы применимы. Этот документ описывает как платформа реализует платёжный контур.

Платёжный домен — критически важный контур: без него невозможно подтверждение бронирования (booking commit), невозможно обязательство платформы перед поставщиком (supplier settlement), невозможна динамическая тарификация платформенных услуг для партнёров. Правило 00000 (платформа главенствует над поставщиками) применяется здесь напрямую: платёжная архитектура не подгоняется под условия конкретного провайдера платёжных услуг и не зависит от модели бронирования конкретного поставщика. Платформа задаёт каноничный платёжный контракт; конкретные провайдеры подключаются как адаптеры.

Главное решение

Платёжный домен — это самостоятельная каноничная модель на уровне платформы Vitiana, не интеграция с конкретным провайдером платёжных услуг. Слой провайдеров (Stripe, Adyen, локальные провайдеры) подключается через абстракцию платёжного адаптера (payment adapter), и любой провайдер может быть отключён, заменён, добавлен без изменения каноничной модели.

Это означает:

  • Каноничные сущности (PaymentIntent, PaymentTransaction, Settlement, Refund, Chargeback, PayoutBatch, PaymentMethod) проектируются от целей платформы, не от схемы Stripe или Adyen.
  • Адаптер провайдера переводит произвольные представления провайдера в каноничную модель Vitiana.
  • Поддерживаются три модели отвечающего за платежи продавца одновременно (Платформа MoR, Партнёр MoR, Гибрид) — каждая модель использует свой набор адаптеров и свою логику взаиморасчёта.
  • Изоляция области применимости PCI DSS обеспечивается через провайдеров платёжных услуг с PCI Level 1 сертификацией — платформа не хранит данные платёжных карт (Primary Account Number, PAN) на собственных серверах.

Каноничная модель платёжного домена

Главные сущности

PaymentIntent — намерение платежа

Сущность, представляющая обязательство клиента совершить платёж на конкретную сумму в конкретной валюте по конкретному бронированию или платформенной услуге. Создаётся при подтверждении бронирования (booking commit) или при выставлении счёта партнёру за платформенные услуги.

Поля:

  • intent_id — каноничный идентификатор намерения (генерируется платформой).
  • tenant_id — какой тенант инициирует платёж.
  • mor_model — модель отвечающего за платежи продавца для этого намерения (platform_mor / partner_mor / hybrid).
  • purpose — цель платежа (booking_payment / platform_fee / subscription / enterprise_invoice).
  • linked_entity_id — ссылка на связанную сущность (booking_id для оплаты бронирования, invoice_id для оплаты платформенных услуг).
  • amount — сумма в наименьшей единице валюты (копейки, центы).
  • currency — код валюты по ISO 4217.
  • client_context — контекст клиента, осуществляющего платёж (без чувствительных платёжных данных).
  • selected_psp — выбранный провайдер платёжных услуг для этого намерения (заполняется при создании после применения политики выбора провайдера).
  • state — состояние намерения (см. статусную машину ниже).
  • idempotency_key — ключ идемпотентности для предотвращения двойных платежей.
  • expires_at — момент истечения намерения, после которого попытка оплаты не принимается.
  • created_at, updated_at — временные метки.

PaymentIntentглавная единица идемпотентности платёжного домена. Один и тот же idempotency_key от партнёра гарантирует, что повторный запрос вернёт исходное намерение, не создаст дубликат.

PaymentTransaction — попытка платежа

Сущность, представляющая конкретную попытку списания суммы по PaymentIntent через выбранный провайдер платёжных услуг. На одно намерение может быть несколько транзакций (попыток), но только одна успешная.

Поля:

  • transaction_id — каноничный идентификатор транзакции.
  • intent_id — ссылка на родительское намерение.
  • psp_provider — какой провайдер платёжных услуг обработал транзакцию.
  • psp_transaction_id — внешний идентификатор транзакции у провайдера (для трассировки).
  • payment_method_token — токенизированная ссылка на платёжный метод (без хранения PAN).
  • state — состояние транзакции (см. статусную машину).
  • amount_authorized — авторизованная сумма (может отличаться от amount_captured при частичной фиксации).
  • amount_captured — фактически списанная сумма.
  • sca_status — статус усиленной аутентификации клиента (not_required / requested / passed / failed / frictionless).
  • failure_code — код ошибки в случае провала (каноничный, мапится из кодов провайдера).
  • attempt_number — номер попытки в рамках намерения.
  • created_at, updated_at, captured_at, failed_at — временные метки.

Refund — возврат

Сущность, представляющая возврат части или всей суммы ранее успешной транзакции. Может быть инициирован клиентом (отмена бронирования с правом возврата по Директиве о пакетных турах), партнёром, или платформой (массовый возврат при отмене поставщиком).

Поля:

  • refund_id — каноничный идентификатор возврата.
  • transaction_id — ссылка на исходную транзакцию.
  • amount — сумма возврата (≤ amount_captured транзакции).
  • currency — наследуется от транзакции.
  • reason — каноничная причина (customer_cancellation / supplier_cancellation / platform_dispute_resolution / chargeback_settlement / partial_unavailability).
  • state — состояние возврата.
  • psp_refund_id — внешний идентификатор возврата у провайдера.
  • requested_by — кто инициировал возврат (tenant_id или platform_admin).
  • created_at, processed_at — временные метки.

Chargeback — возвратный платёж

Сущность, представляющая возвратный платёж, инициированный банком клиента (когда клиент оспаривает платёж). Это операционный риск для отвечающего за платежи продавца. Процедура обработки требует доказательной базы (evidence pack).

Поля:

  • chargeback_id — каноничный идентификатор.
  • transaction_id — ссылка на оспариваемую транзакцию.
  • amount — сумма оспаривания.
  • psp_chargeback_id — внешний идентификатор у провайдера.
  • reason_code — код причины от банка-эмитента (каноничный, мапится из network reason codes Visa/Mastercard).
  • dispute_state — состояние спора (opened / evidence_required / evidence_submitted / won / lost / accepted).
  • evidence_pack_id — ссылка на пакет доказательств (если собран).
  • deadline_at — крайний срок предоставления доказательств.
  • created_at, resolved_at — временные метки.

Settlement — взаиморасчёт с поставщиком

Сущность, представляющая обязательство платформы перед поставщиком по конкретному бронированию (модель «Платформа сама отвечающий за платежи продавец»). Связывает успешную транзакцию клиента с расчётом, который платформа должна провести с поставщиком.

Поля:

  • settlement_id — каноничный идентификатор.
  • transaction_id — ссылка на исходную транзакцию клиента.
  • booking_id — ссылка на бронирование.
  • supplier_id — каноничный идентификатор поставщика.
  • gross_amount — общая сумма транзакции клиента.
  • platform_fee — комиссия платформы (зависит от тарифа партнёра и условий поставщика).
  • supplier_payable — сумма к перечислению поставщику (gross_amount - platform_fee).
  • currency — валюта взаиморасчёта (может отличаться от валюты транзакции при FX-конверсии).
  • state — состояние (pending / held / cleared / paid_out / disputed).
  • clearing_period_id — ссылка на расчётный период (см. partner-finance-and-clearing.md).
  • created_at, cleared_at, paid_out_at — временные метки.

PayoutBatch — пакет выплат

Сущность, представляющая периодическую массовую выплату поставщикам или партнёрам (для модели «Партнёр сам отвечающий за платежи продавец» с обратным потоком — платформа выплачивает партнёру долю от своих собранных платежей).

Поля:

  • payout_id — каноничный идентификатор.
  • recipient_type — тип получателя (supplier / partner / agency).
  • recipient_id — каноничный идентификатор получателя.
  • period_start, period_end — расчётный период.
  • total_amount — общая сумма выплаты.
  • currency — валюта выплаты.
  • included_settlement_ids — список взаиморасчётов в этой выплате.
  • state — состояние (pending / processing / paid / failed).
  • psp_payout_id — внешний идентификатор у провайдера, исполняющего выплату.

PaymentMethod — платёжный метод (токенизированный)

Сущность, представляющая сохранённый платёжный метод клиента (карта, банковский перевод, кошелёк) для повторного использования. Не содержит данных карты — только токен от провайдера платёжных услуг плюс минимально необходимые отображаемые поля (последние 4 цифры, тип карты, срок действия).

Поля:

  • payment_method_id — каноничный идентификатор.
  • client_id — каноничный идентификатор клиента (привязка к сущности клиента, не к учётной записи в платёжной системе провайдера).
  • psp_provider — какой провайдер выпустил токен (платёжный метод действителен только в этом провайдере).
  • psp_method_token — внешний токен.
  • method_type — тип (card / bank_transfer / wallet / direct_debit / local_payment_method).
  • display_brand — отображаемый бренд (visa / mastercard / mir / local_brand) для интерфейса.
  • display_last4 — последние 4 цифры (только для отображения).
  • display_expiry_month, display_expiry_year — срок действия (только для отображения).
  • created_at, last_used_at, revoked_at — временные метки.

Связь с другими каноничными сущностями

  • PaymentIntent.linked_entity_id указывает на Booking (см. Каноничная доменная ось) или Invoice (выставленный счёт за платформенные услуги).
  • PaymentTransaction участвует в потоке подтверждения бронирования (booking commit) — успешная транзакция разрешает переход бронирования в confirmed.
  • Settlement связан с PartnerSettlementBatch из Партнёрские взаиморасчёты — взаиморасчёты группируются в расчётные периоды.
  • Tenant определяет применимую модель отвечающего за платежи продавца через tenant_configuration (см. Тенантная настройка).

Статусная машина платежа

Состояния PaymentIntent

created

selecting_psp — выбор провайдера платёжных услуг по политике

awaiting_method — ожидание ввода платёжного метода клиентом

processing — попытка списания через провайдера

├─→ requires_action — требуется усиленная аутентификация (3D Secure)
│ ↓
│ processing — повторная попытка после прохождения SCA

├─→ succeeded — платёж проведён успешно

├─→ failed — попытка провалена, возможна повторная попытка
│ ↓
│ processing — повторная попытка с тем же или другим методом

└─→ expired — намерение просрочено (по `expires_at`)

succeeded

├─→ partially_refunded — был частичный возврат

refunded — был полный возврат

disputed — открыт возвратный платёж (chargeback)

Состояния PaymentTransaction

initiated

authorized — авторизация прошла, средства зарезервированы

├─→ captured — фиксация (списание)

├─→ voided — авторизация снята до фиксации (отмена бронирования)

└─→ expired — авторизация истекла (типично 7 дней)

captured

├─→ refund_pending — инициирован возврат
│ ↓
│ refunded — возврат проведён

└─→ chargeback_opened — открыт возвратный платёж

Состояния Refund

requested → approved → processing → completed

failed (провайдер отказал в возврате)

Состояния Chargeback

opened → evidence_required → evidence_submitted

├─→ won — платформа выиграла спор
├─→ lost — платформа проиграла
└─→ accepted — платформа приняла возвратный платёж без оспаривания

Стыковка с состояниями бронирования

Платёж синхронизирован с бронированием по правилу:

Состояние бронированияДопустимое состояние PaymentIntent
draft, submittedcreated, selecting_psp, awaiting_method
pending_revalidationawaiting_method (платёж ещё не запрошен у клиента)
pending_supplier_confirmationsucceeded (платёж проведён, но поставщик ещё не подтвердил)
confirmedsucceeded
partially_confirmedsucceeded (полный платёж) или partially_refunded (после частичной отмены)
failedfailed, voided, refunded
cancel_requested, cancelledvoided (если до фиксации) или refund_pending / refunded (после фиксации)
completedsucceeded или partially_refunded

Состояния бронирования зафиксированы в API Contracts и в reference/booking-state-machine.md (фаза 5). Полная state machine с переходами и идемпотентным замыканием — там.

Архитектура отвечающего за платежи продавца — три модели

Подробно три модели описаны в Соответствие требованиям регуляторов § 2.1 и в Архитектурный якорь и бизнес-модель. Здесь — операционная сторона каждой модели в платёжном контуре.

Модель А. Платформа сама отвечающий за платежи продавец (Platform-as-MoR)

Поток платежа:

  1. Клиент инициирует бронирование на потребительской поверхности (B2C Storefront Surface) или через интерфейс агентства (Agency Working Surface).
  2. Платформа создаёт PaymentIntent со своим расчётным счётом провайдера платёжных услуг как получателем.
  3. Клиент проводит платёж — провайдер зачисляет средства на счёт платформы.
  4. Создаётся Settlement с обязательством платформы перед поставщиком.
  5. Платформа проводит подтверждение бронирования у поставщика.
  6. По расчётному периоду (clearing period) платформа группирует взаиморасчёты в PayoutBatch и переводит поставщику долю.

Когда применяется:

  • Собственный канал vitrip.store.
  • Тарифы агентств с базовой платёжной интеграцией (Starter).
  • Партнёры тарифного уровня Free (для тестирования в среде тестирования с симулированными платежами).

Операционная нагрузка: платформа держит chargeback-резерв, обрабатывает споры, проводит KYC своих тенантов-продавцов.

Модель Б. Партнёр сам отвечающий за платежи продавец (Partner-as-MoR)

Поток платежа:

  1. Конечный клиент партнёра инициирует бронирование на интерфейсе партнёра (вне платформы Vitiana).
  2. Партнёр самостоятельно проводит платёж через свой провайдер платёжных услуг — средства зачисляются на счёт партнёра.
  3. Партнёр вызывает программный интерфейс Vitiana для подтверждения бронирования, не передавая платёжных данных — только подтверждение факта оплаты.
  4. Платформа создаёт PaymentIntent в специальном состоянии external_paid (платёж проведён вне платформы).
  5. Платформа проводит подтверждение бронирования у поставщика как обычно.
  6. По расчётному периоду партнёру выставляется счёт за платформенные услуги (платный программный интерфейс) и за стоимость инвентаря у поставщика, передаваемого без наценки (passthrough).
  7. Партнёр оплачивает счёт платформы через PaymentIntent с purpose: platform_fee.

Когда применяется:

  • Корпоративный (Enterprise) тариф.
  • Большинство партнёров тарифного уровня Professional.

Операционная нагрузка: платформа не держит chargeback-резерва по бронированиям конечных клиентов партнёра. Платформа только выставляет счета и принимает платежи от партнёра.

Модель В. Гибрид с разделением по продукту

Тенант сам отвечающий за платежи продавец для одних продуктов (например, отдельные бронирования отелей), а для других (например, пакетных туров с ответственностью по Директиве о пакетных турах) — платформа. Конкретное разделение фиксируется в tenant_configuration для каждого тенанта.

Слой провайдеров платёжных услуг

Принцип абстракции

Провайдеры платёжных услуг (Stripe, Adyen, локальные провайдеры) подключаются через абстракцию платёжного адаптера. Каждый адаптер реализует каноничный интерфейс платформы:

interface PaymentProviderAdapter {
createIntent(canonical_intent_request) -> psp_intent_response
confirmIntent(psp_intent_id, payment_method_data) -> psp_transaction_response
capture(psp_transaction_id, amount) -> psp_capture_response
void(psp_transaction_id) -> psp_void_response
refund(psp_transaction_id, amount, reason) -> psp_refund_response
retrievePaymentMethod(psp_method_token) -> psp_method_data
handleWebhook(webhook_payload, signature) -> normalized_event
payout(recipient_account, amount, currency) -> psp_payout_response
collectChargebackEvidence(psp_chargeback_id, evidence) -> psp_evidence_response
}

Каждый адаптер переводит каноничные запросы платформы в специфический протокол провайдера и нормализует ответы провайдера обратно в каноничные структуры.

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

Выбор провайдера для конкретного PaymentIntent определяется политикой провайдера платежей (payment routing policy):

  1. Валюта платежа — провайдер должен поддерживать валюту намерения.
  2. Юрисдикция тенанта-продавца и клиента-покупателя — провайдер должен иметь лицензию в применимых юрисдикциях.
  3. Тип платёжного метода — некоторые методы (местные платёжные методы — local payment methods) поддерживаются только определёнными провайдерами.
  4. Тарифный уровень тенанта — корпоративные тенанты могут иметь привязку к конкретному провайдеру по контракту.
  5. Операционное состояние провайдера — здоровье (operational health) провайдера в реальном времени, fallback к альтернативе при деградации.

Политика — отдельная конфигурируемая сущность, не зашита в код. Это позволяет менять стратегию маршрутизации без релизов.

Поддержка нескольких провайдеров одновременно

Платформа никогда не привязывается к одному провайдеру. На каждый момент времени:

  • Один или несколько главных провайдеров (primary providers) для основных потоков.
  • Один или несколько резервных провайдеров (fallback providers) на случай деградации главного.
  • Региональные провайдеры для местных платёжных методов в географиях первой волны.

Матрица провайдеров по фазам и регионам

Развилка: конкретный выбор провайдеров для каждого региона первой волны — открыт. Архитектура не зависит от этого выбора (любой провайдер подключается через адаптер). Ниже — критерии выбора и ориентировочный план подключения.

РегионФаза подключенияКритерии главного провайдераКандидаты на исследование
Чехия (CZ), Польша (PL), широкая Европа (EU)Фаза 2 (после Bootstrap)EU-лицензия, поддержка PSD2 SCA, поддержка SEPA, разумные комиссии для агрегаторовStripe, Adyen, Mollie
Украина (UA)Фаза 2Локальная лицензия, поддержка местных платёжных методов (UAH-карты, локальные кошельки), интеграция с украинским налоговым режимомLiqPay, Fondy, WayForPay; Stripe (через UA-MCC при локальной структуре)
Казахстан (KZ)Фаза 2Локальная лицензия, поддержка KZT, интеграция с казахстанским налоговым режимом, поддержка карт «Каспи», «Халык»Локальные провайдеры (выбор открыт)
Великобритания, Турция, Закавказье, Центральная АзияФаза 4По мере выхода в географиюОткрыто

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

Запрещённые паттерны

  • ❌ Захватная интеграция (captive integration) с одним провайдером (поля каноничной модели, повторяющие схему Stripe).
  • ❌ Жёсткая зашитая стратегия маршрутизации провайдеров (выбор должен быть конфигурируемой политикой).
  • ❌ Хранение данных платёжных карт (PAN) на серверах платформы (PCI scope нельзя минимизировать).
  • ❌ Прямая работа с банками-эквайерами без провайдера платёжных услуг (на старте). Возможно в фазе 4 при достижении масштаба, оправдывающего собственный мерчант-аккаунт.

Усиленная аутентификация клиента (Strong Customer Authentication, SCA) под PSD2

Применимость

PSD2 (Платёжная директива 2, Payment Services Directive 2) Европейского Союза требует усиленной аутентификации клиента для электронных платежей в Европейской экономической зоне (European Economic Area, EEA) с 14 сентября 2019 года. Это означает, что для платежей с клиентами из Европейского Союза по картам, выпущенным в EU, требуется проверка по двум факторам из трёх категорий: знание (пароль, PIN), владение (телефон с приложением, ключ безопасности), биометрия (отпечаток, лицо).

Технически это реализуется через 3D Secure 2 (3DS2) — протокол, передающий аутентификацию клиента к банку-эмитенту его карты.

Поток с SCA

PaymentIntent.processing

PSP запрашивает 3DS у банка-эмитента

├─→ frictionless flow — банк аутентифицирует клиента без интерактива
│ ↓
│ PaymentIntent.succeeded

├─→ challenge flow — банк требует интерактивную аутентификацию
│ ↓
│ PaymentIntent.requires_action
│ ↓
│ Клиент проходит аутентификацию (push в приложение банка, SMS-код, и т.д.)
│ ↓
│ PaymentIntent.processing → succeeded или failed

└─→ exemption applied — применено разрешение на пропуск SCA

PaymentIntent.succeeded (без интерактива)

Разрешения на пропуск SCA (SCA exemptions)

PSD2 предусматривает разрешения на пропуск:

  • Малая сумма — до 30 евро (или эквивалента) при отсутствии 5 транзакций подряд от того же клиента без SCA.
  • Низкий риск (transaction risk analysis) — для провайдеров с низким уровнем мошенничества.
  • Платежи по подписке — после первой аутентифицированной транзакции с тем же платёжным методом.
  • Корпоративные платежи (commercial card payments) — между бизнес-аккаунтами.

Каноничное поле PaymentTransaction.sca_status = frictionless фиксирует применение разрешения.

Применимость в первой волне

РегионSCA применимаКомментарий
Чехия (CZ), Польша (PL), широкая ЕвропаДа, обязательноПо PSD2/PSD3
Украина (UA)Не PSD2-юрисдикция; собственные требования НБУЛокальные платёжные карты — отдельный режим аутентификации
Казахстан (KZ)Не PSD2-юрисдикция; собственные требования НБКАналогично
Великобритания (UK)Да, обязательноUK FCA повторил требования PSD2 после Brexit

Возвраты (refunds)

Полный возврат

Применяется при:

  • Отмене бронирования с правом возврата (по политике поставщика или Директиве о пакетных турах).
  • Отмене со стороны поставщика (поставщик не может выполнить бронирование).
  • Решении платформы по спору в пользу клиента.

Поток:

1. Тенант (или платформа) инициирует возврат через программный интерфейс или панель управления.
2. Создаётся Refund в состоянии requested.
3. Применяется политика возврата (refund policy) — каноничные правила платформы (см. ниже).
4. Если политика разрешает — Refund переходит в approved.
5. Адаптер провайдера запрашивает возврат у провайдера платёжных услуг.
6. Refund в processing.
7. Провайдер подтверждает возврат — Refund в completed.
8. Транзакция переходит в refunded; намерение в refunded.
9. Если есть Settlement — он корректируется (взаиморасчёт с поставщиком уменьшается на сумму возврата).

Частичный возврат

Применяется при:

  • Частичной отмене (только часть номеров отменена, остальные подтверждены).
  • Корректировке цены post-fact (например, при пересчёте — repricing — после частичной недоступности).
  • Возврате части услуг пакетного тура (one component out of multi).

Может быть несколько Refund на одну PaymentTransaction. Сумма всех успешных возвратов не должна превышать amount_captured.

Каноничные правила политики возврата

Каждый Refund.reason имеет каноничную политику. Исходные данные политики:

  • time_until_arrival — за сколько до даты заезда отменяется.
  • supplier_refund_policy — политика поставщика (полная отмена 30 дней до / штрафная отмена 14 дней / неотменяемое за 7 дней).
  • tenant_mor_model — модель отвечающего за платежи продавца тенанта.
  • applied_compliance_rules — например, Директива о пакетных турах требует возврата при отмене со стороны организатора независимо от политики поставщика.

Полные правила политики — в reference/post-booking-lifecycle.md. Этот документ только определяет сущность возврата и состояния.

Возвратные платежи (chargebacks)

Жизненный цикл

1. Клиент оспаривает платёж в своём банке.
2. Банк-эмитент инициирует возвратный платёж через VISA/Mastercard сеть.
3. Провайдер платёжных услуг получает уведомление и пересылает в платформу через webhook.
4. Создаётся Chargeback в состоянии opened.
5. Сумма списывается со счёта отвечающего за платежи продавца (если платформа MoR — со счёта платформы).
6. Платформа уведомляет тенанта (или партнёра) о возвратном платеже.
7. Решение: оспорить или принять.
├─→ Оспорить: собирается evidence_pack — пакет доказательств.
│ ↓
│ Chargeback в evidence_required → evidence_submitted.
│ ↓
│ Сеть VISA/Mastercard рассматривает спор (10-45 дней).
│ ↓
│ ├─→ won: средства возвращаются.
│ ├─→ lost: средства списаны окончательно.

└─→ Принять: Chargeback в accepted, средства списаны.

Пакет доказательств (evidence pack)

Каноничная структура пакета доказательств для оспаривания:

  • Подтверждение бронирования с реквизитами клиента.
  • Запись транзакции с временной меткой и IP-адресом клиента.
  • Прохождение усиленной аутентификации клиента (если применима).
  • Доказательство выполнения услуги поставщиком (для уже исполненных бронирований).
  • Переписка с клиентом, если была.
  • Применимая политика возврата с подписью клиента (явное согласие).

Пакет доказательств — критическая операционная потребность платформы. Сборка осуществляется через канонические события (booking.confirmed, client.authentication.passed, supplier.fulfillment.confirmed) из контура наблюдаемости (см. Операционная ось).

Меры предотвращения возвратных платежей

  • Обязательная усиленная аутентификация клиента (3D Secure 2) для всех PSD2-платежей — снимает значительную часть рисков.
  • Ясные описания продукта на чеках и в подтверждениях бронирования (название гостиницы, даты заезда/выезда, комната).
  • Узнаваемое имя продавца (statement_descriptor) в выписке клиента — клиент должен видеть «Vitiana» или название канала, а не имя поставщика.
  • Активная коммуникация при подозрении на проблему (proactive customer service).

Идемпотентность и replay-safe

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

Каждый запрос на создание PaymentIntent от партнёра должен содержать ключ идемпотентности (idempotency key):

  • Партнёр генерирует уникальный ключ для каждого нового намерения.
  • Платформа проверяет: если намерение с этим ключом и от этого тенанта уже существует — возвращается то же самое намерение (не создаётся новое).
  • Срок хранения ключей идемпотентности — 24 часа (после этого ключ может быть переиспользован).

Это критично для replay-safety: если партнёр получил тайм-аут при отправке запроса и повторил его, платформа не создаст два намерения и не спишет с клиента дважды.

Идемпотентность операций провайдера

Все вызовы адаптеров провайдеров платёжных услуг (создание транзакции, фиксация, возврат, выплата) — идемпотентны через ключ, передаваемый адаптером провайдеру (Stripe Idempotency-Key, Adyen reference).

Replay-safe событий

События платёжного контура (payment.captured, refund.completed, chargeback.opened) — replay-safe. При повторной обработке события потребителем (consumer) не должна происходить двойная обработка.

Это обеспечивается через:

  • Уникальный идентификатор события (event_id).
  • Каноничное состояние «is replayed» в адаптере потребителя.
  • Журнал обработанных событий с возможностью обнаружения дубликатов.

Подробности — в Событийная шина и асинхронная дисциплина.

Изоляция области применимости PCI DSS

Цель — минимизация области (PCI scope minimization)

Стандарт безопасности данных платёжной индустрии (PCI DSS) применяется к любой системе, которая хранит, передаёт или обрабатывает данные платёжных карт (cardholder data, CHD). Соответствие на уровне Level 1 (для агрегаторов с большим объёмом транзакций) — это значительные операционные расходы (ежегодный аудит сертифицированным аудитором, QSA).

Стратегия Vitiana — минимизация области:

  • Платформа не принимает данные карт напрямую. Клиент вводит данные карты в защищённой форме, размещённой провайдером платёжных услуг (через iframe, hosted fields, или редирект на страницу провайдера).
  • Платформа получает от провайдера только токен (psp_method_token), не данные карты.
  • Все операции с данными карты — на стороне провайдера, который имеет PCI Level 1 сертификацию.

Это переводит платформу в PCI SAQ-A (Self-Assessment Questionnaire A) — самый минимальный уровень соответствия, требующий только подтверждения, что платформа использует PCI-сертифицированных провайдеров и не хранит данные карт.

Что разрешено хранить

  • Токен метода платежа (psp_method_token) — это не данные карты, а внешняя ссылка.
  • Отображаемые поля (display_brand, display_last4, display_expiry_month/year) — допустимо для отображения клиенту в личном кабинете и для подбора метода при повторной транзакции.
  • Идентификатор транзакции у провайдера (psp_transaction_id) — для трассировки и сверки.

Что запрещено хранить

  • Полный номер карты (Primary Account Number, PAN).
  • CVV/CVC.
  • Полная дорожка (full track data).
  • ПИН-блок.

Любая попытка хранения этих данных — критическая регуляторная ошибка, ведущая к потере PCI-соответствия.

Учёт потребления для тарификации платёжных операций

Платёжный домен — один из источников метрик для динамической тарификации платформенных услуг (см. Архитектурный якорь и бизнес-модель → «Динамическая тарификация платформенных услуг»). Метрика «операции взаиморасчёта и клиринга» (settlement and clearing operations) считается на основе:

  • Числа созданных PaymentIntent за период.
  • Числа успешных PaymentTransaction.
  • Числа Refund (возвраты дороже первичной транзакции по операционной нагрузке).
  • Числа Chargeback (возвратные платежи дороже всего).
  • Объёма обработанных средств в валюте.

Учёт ведётся в реальном времени через канал событий и агрегируется в систему учёта потребления (см. Учёт потребления и квоты).

События платёжного контура

Платёжный домен публикует следующие каноничные события в Событийную шину:

СобытиеКогда публикуетсяГлавные потребители
payment.intent.createdПосле создания PaymentIntentКонтур наблюдаемости, контур учёта потребления
payment.intent.updatedПри смене состояния намеренияКонтур бронирования, контур уведомлений
payment.transaction.authorizedПосле успешной авторизацииКонтур бронирования, контур наблюдаемости
payment.transaction.capturedПосле фиксации платежаКонтур бронирования (разрешает confirmation), контур взаиморасчётов, контур уведомлений
payment.transaction.failedПри провале попыткиКонтур бронирования, контур наблюдаемости
refund.requestedПри создании возвратаКонтур пост-бронирования, контур взаиморасчётов
refund.completedПри завершении возвратаКонтур учёта, контур уведомлений клиенту
chargeback.openedПри открытии возвратного платежаКонтур поддержки клиентов, контур наблюдаемости (alerting)
chargeback.resolvedПри завершении спораКонтур учёта, контур взаиморасчётов
settlement.clearedПри завершении взаиморасчёта с поставщикомКонтур партнёрских финансов
payout.completedПри завершении выплатыКонтур уведомлений тенанту

Полная таксономия событий — в Первоначальная таксономия событий.

Multi-currency и политика валютных операций

Базовый набор валют

Платформа поддерживает с фазы Bootstrap:

  • украинская гривна (UAH);
  • евро (EUR);
  • чешская крона (CZK);
  • польский злотый (PLN);
  • казахстанский тенге (KZT);
  • доллар США (USD).

Валюта намерения и валюта взаиморасчёта могут различаться

PaymentIntent.currency — валюта, в которой клиент платит.

Settlement.currency — валюта, в которой платформа рассчитывается с поставщиком (может быть другой, потому что поставщик принимает платежи в другой валюте).

При различии — применяется политика валютных операций (FX policy):

  • Курс конвертации фиксируется в момент создания Settlement (не в момент клиентского платежа).
  • Источник курса — выбранный валютный провайдер (FX provider) с opciją использования курса своего платёжного провайдера, если он предоставляет.
  • Маржа платформы на FX-конверсии (FX margin) — отдельная коммерческая позиция, документируется в Коммерческая модель.

Запрещённые паттерны

  • ❌ Захватная интеграция с одной валютой (например, всё в евро с конверсией на лету) — это исключает поддержку Украины и Казахстана как первой волны.
  • ❌ Скрытая FX-маржа — комиссия должна быть явно зафиксирована в платёжном расчёте клиента.

Фазы развёртывания платёжного домена

Платёжный домен разворачивается фазированно по правилу Эластичное масштабирование и упаковка по фазам.

Фаза Bootstrap (0–6 месяцев)

Что разворачивается:

  • Каноничная модель платёжного домена в схеме хранения (см. Хранение) — все сущности и базовые связи.
  • Адаптер первого провайдера платёжных услуг (один регион — Чехия или Польша как первая EU-юрисдикция, кандидат — Stripe или Adyen в среде тестирования).
  • Прототип потока платежа в среде тестирования (sandbox) с симулированными платежами.
  • События платёжного контура публикуются в локальный канал событий.

Триггер выхода:

  • Готовность к боевому запуску (production launch) первого тенанта (vitrip.store).
  • Все события платёжного контура реализованы и наблюдаемы.

Фаза 2 — Production launch (6–12 месяцев)

Что разворачивается:

  • Боевой режим первого провайдера платёжных услуг для Чехии и Польши.
  • Первая локальная адаптация — провайдер для Украины (LiqPay/Fondy/WayForPay — выбор открыт).
  • Полная процедура усиленной аутентификации клиента под PSD2.
  • Процедура возвратов с интеграцией политики возврата из пост-бронирования.
  • Базовая процедура обработки возвратных платежей (без автоматической сборки доказательной базы).

Триггер выхода:

  • Объём бронирований с применённым 3D Secure превышает порог стабильной операции.
  • Появляются первые партнёры с моделью «партнёр сам отвечающий за платежи продавец» — нужен слой выставления счетов за платформенные услуги.

Фаза 3 — Multi-region и многопровайдерность (12–24 месяца)

Что разворачивается:

  • Адаптеры провайдеров для Казахстана.
  • Многопровайдерная маршрутизация с автоматическим резервированием при деградации.
  • Автоматическая сборка пакета доказательств для возвратных платежей через каноничные события.
  • Развитая FX-политика с поддержкой нескольких валютных провайдеров.
  • Поддержка местных платёжных методов в каждом регионе первой волны.

Фаза 4 — Многорегиональная зрелость и собственный мерчант-аккаунт (24+ месяцев)

Что разворачивается:

  • Собственный мерчант-аккаунт (direct merchant relationship) с эквайером для крупнейших регионов — экономия на комиссиях провайдера платёжных услуг при достижении порога объёма.
  • Многорегиональное активно-активное развёртывание для критических потоков платежей.
  • Аналитика мошенничества (fraud analytics) на основе ML-моделей (см. Ось данных и интеллекта).
  • Автоматический анализ риска транзакции (transaction risk analysis) для применения разрешений на пропуск усиленной аутентификации.

Архитектурные решения с тезисным обоснованием

Решение 1. Каноничная модель платёжного домена, не интеграция с провайдером

Цель: обеспечить независимость платформы от конкретного провайдера платёжных услуг и поддержку нескольких провайдеров одновременно.

Тезисы поддержки:

  1. Захватная интеграция с одним провайдером — экзистенциальный риск: смена условий, рост комиссий, региональные ограничения провайдера могут заблокировать всю платформу.
  2. Канонична модель — единственный способ поддержать одновременно три модели отвечающего за платежи продавца с разными провайдерами для разных тенантов.
  3. Современные лучшие практики платформ верхнего уровня (Stripe Connect, Adyen MarketPay) построены именно на абстракции платёжного слоя — это база, не выбор.

Альтернатива и почему отклонена:

  • Прямая интеграция со Stripe как primary — отклонено, потому что Stripe не покрывает Украину и Казахстан. Платформа не может работать в первой волне без поддержки этих регионов.

Принимаемые компромиссы:

  • Сложность слоя адаптеров — выше, чем при прямой интеграции. Это окупается на втором, третьем, и далее провайдере.

Решение 2. PCI scope minimization через токенизацию

Цель: избежать высоких операционных расходов сертификации PCI DSS Level 1 (~$50–200 тысяч в год при полном объёме область применимости).

Тезисы поддержки:

  1. Платформа не имеет конкурентного преимущества в обработке данных карт — это подсолнух обработки на стороне провайдера платёжных услуг.
  2. Минимизация области применимости PCI снижает регуляторную нагрузку с Level 1 до SAQ-A — экономия порядка пары порядков по операционным расходам соответствия.
  3. Современные провайдеры предоставляют hosted fields и iframe-формы, не требующие переноса PAN на серверы платформы.

Альтернативы:

  • Принять Level 1 соответствия и обрабатывать карты на серверах платформы. Отклонено: высокие операционные расходы соответствия не оправданы.

Решение 3. Идемпотентность через ключ от партнёра

Цель: исключить двойные платежи при тайм-аутах и повторных вызовах партнёра.

Тезисы поддержки:

  1. Платежи — финансово-критическая область, ошибки дорогие.
  2. Партнёрский программный интерфейс работает в среде сетевой нестабильности (потенциально несколько географий) — повторные вызовы неизбежны.
  3. Идемпотентность через ключ — стандарт индустрии (Stripe, Square, PayPal — все так делают).

Решение 4. Поддержка трёх моделей отвечающего за платежи продавца одновременно

Цель: покрыть все сегменты бизнес-модели (собственный канал, агентства, партнёры) одной платформой.

Тезисы поддержки:

  1. Бизнес-модель Vitiana явно фиксирует гибридную модель отвечающего за платежи продавца для каждого тенанта (см. Архитектурный якорь и бизнес-модель).
  2. Невозможно ограничиться одной моделью — корпоративные партнёры всегда сами отвечающий за платежи продавец, потребительские клиенты — нет.
  3. Технически три модели отличаются только потоком (платформа vs тенант принимает деньги), но используют одну каноничную модель сущностей.

Открытые развилки

Развилка 1. Конкретные провайдеры платёжных услуг для каждого региона

См. секцию «Матрица провайдеров по фазам и регионам». Кандидаты исследуются и выбираются при подключении каждого региона. Этот документ описывает архитектуру выбора, не конкретный выбор.

Эскалируется: к владельцу платформы в момент финализации бизнес-партнёрств с провайдерами платёжных услуг.

Развилка 2. Стратегия валютных операций — собственный валютный провайдер vs курсы провайдера платёжных услуг

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

Эскалируется: при создании секции FX-policy в Партнёрские взаиморасчёты или при достижении порогового объёма международных платежей.

Развилка 3. Собственный мерчант-аккаунт vs модель агрегатора провайдера

В фазе 4 при достижении объёма платформа может перейти на прямой мерчант-аккаунт с банком-эквайером (экономия на комиссиях провайдера, ~0.3–0.7% от оборота), но это требует собственной PCI Level 1 сертификации.

Эскалируется: при достижении бизнес-триггера объёма (порог фиксируется в Эластичное масштабирование).

Развилка 4. Поддержка криптовалютных платежей

Не входит в фазы 1–3. В фазе 4 может быть рассмотрено как опция для определённых тенантов с тенантной включённостью (per-tenant opt-in) и отдельным провайдером криптовалютных платежей.

Эскалируется: при появлении партнёрских запросов на криптоплатежи.

Развилка 5. Подписные платежи (subscription / recurring)

Платформенная подписка корпоративного тенанта (Enterprise tier) — это потенциально подписной платёж. Архитектурно поддерживается через PaymentIntent.purpose: subscription плюс сохранённый PaymentMethod. Конкретные правила (когда списывать, как обрабатывать неудачи) — открытая развилка.

Эскалируется: при создании Платформа как продукт v2 с финализацией тарифной структуры.

Связанная документация

Корневые архитектурные документы

Связанные доменные документы

Архитектурные правила

Уточнение под Фазы 5–6 (28.04.2026) — связи с booking states, saga, isolation, SLA

Документ опубликован 26.04.2026 (Фаза 4). После Фаз 5–6 интеграция со специализированными доменами требует фиксации.

Связь со статусной машиной бронирования

reference/booking-state-machine.md (Фаза 5) — каноничные 14 состояний Booking. Payment lifecycle координирован:

  • submittedPaymentIntent.authorized (hold);
  • pending_supplier_confirmationPaymentIntent.authorized (hold continues);
  • supplier_confirmedPaymentIntent.captured (PSP capture);
  • platform_confirmed → settlement event posted;
  • unknown_external_statefreeze payment progress, manual review;
  • failedPaymentIntent.canceled, hold released;
  • cancelledRefund initiated.

Связь с saga Tour Builder

reference/tour-builder-operational-model.md (Фаза 5) — multi-component tour bookings:

  • single PaymentIntent для всего тура (предпочтительно) или multi-PaymentIntent (один на компонент);
  • saga compensation при partial failure → individual refund operations per компонент;
  • per-component settlement через separate flows;
  • DriftEvent может triggered repricing → новый PaymentIntent.

Связь с уровнями тенантной изоляции

reference/multi-tenant-isolation-strength.md (Фаза 5):

  • payment data — Tier 1 critical во всех isolation levels;
  • Enterprise с dedicated_infrastructure могут иметь отдельные PSP credentials;
  • tenant-specific PSP routing (например, EU tenant → Stripe EU, KZ tenant → local PSP);
  • audit log per tenant.

Связь с SLA payment success rate

operations/sla-and-on-call-model.md (Фаза 6) — SLI 7 (payment success rate):

  • target менее 1% rejected payments при штатной нагрузке;
  • breach triggers SEV2 incident;
  • service credits applied per breach.

Связь с DR — Tier 1

operations/disaster-recovery-and-capacity.md (Фаза 6) — payment data:

  • Tier 1: RTO 60м, RPO 5м;
  • 7 лет retention (financial records);
  • continuous WAL streaming + snapshot каждый час;
  • ежемесячные restore drills mandatory.

Связь с runbooks

operations/runbooks-incident-playbooks.md (Фаза 6) — payment-related incidents:

  • payment provider degradation;
  • chargeback storm (массовый chargeback);
  • unknown_external_state propagation в payment-side;
  • PSP credential rotation issues.

Связь с partner clearing

reference/partner-finance-and-clearing.md — clearing layer поверх payment-domain. Payment-domain — transaction lifecycle; partner-finance — balance aggregation. См. partner-finance-and-clearing уточнение для деталей.

Связь с economic model

reference/economic-model.md (Фаза 4) — payment генерирует revenue events для unit-economics: payment_processing cost category, PSP fees как cost driver.

Связь с compliance — PCI DSS / PSD2

reference/compliance-and-legal.md (Фаза 4):

  • PCI DSS — через PSP-only handling (zero-touch к card data, SAQ A);
  • PSD2 SCA — через PSP 3D Secure 2.0;
  • AML / KYC для high-volume transactions (фаза 4+);
  • Sanctions screening — automated via PSP или отдельный provider.

Каноничный итог уточнения

Уточнение выполнено через no-destruction.