A/B тести платіжних сценаріїв
1) Навіщо тестувати платіжні сценарії
Збільшити схвалення (AR) і знизити відмови (DR).
Зменшити вартість: take-rate (interchange/scheme/markup/fixed) и cost-per-approval.
Знизити ризик: менше чарджбеков/фрода при тих же схваленнях.
Стійкість: підібрати провайдера/3DS-стратегію/роутинг під конкретні GEO/BIN/методи.
2) Дизайн експерименту
2. 1. Юніт рандомізації
User-level (рекомендується): всі спроби одного користувача потрапляють в одну гілку → немає «перемішування» 3DS/токенів.
BIN-level: коли тест - про роутинг за емітентом; ризик крос-призначеного для користувача змішання.
Order/Attempt-level: допустимо для дрібних UI-експериментів (наприклад, копія помилки), небажано для роутингу/3DS.
2. 2. Стратифікація (до рандомізації)
Стратифікуйте за: GEO гравця, issuer country/BIN6, метод оплати, канал (web/app), сума-сегмент, ризик-скор. Це зменшить дисперсію і ризик SRM.
2. 3. Що тестуємо
Роутинг/каскад: PSP_A vs PSP_B, sticky BIN, ліміт-aware.
3DS-політика: frictionless→challenge, примусовий 3DS для BIN/гео.
UX флоу: послідовність кроків, тексти помилок/повторів.
Параметри ретрая: вікна та коди soft-decline.
Ціноутворення: провайдер з IC++ vs blended і вплив на all-in вартість.
3) Метрики: цільові, вторинні, guardrails
3. 1. Основні
AR (Approval Rate) = approved/attempted.
Cost-per-Approval = (auth+decline fees)/approved.
Take-rate% (all-in) = fees/volume (у звітній валюті).
3DS pass-rate; liability shift %.
Latency p95/p99 платіжного флоу.
3. 2. Ризик-метрики
Chargeback ratio (CBR), refund rate, fraud alerts/1000 trx.
FX slippage (bps) = effective vs reference FX.
3. 3. Guardrails (стоп-умови)
Падіння AR> Y bps або зростання CBR/Refunds вище порогу.
SRM (Sample Ratio Mismatch) - дисбаланс трафіку проти очікуваного.
Spikes: латентність, soft-decline surge, 3DS anomaly.
4) Статистика і потужність
4. 1. Розмір вибірки (наближення для часток)
n_per_group ≈ 2 (Z_{1-α/2} + Z_{1-β})^2 p(1-p) / δ^2
де'p'- базовий AR,'δ'- очікуваний uplift в AR, α - рівень значущості, β - помилка II роду.
4. 2. Послідовний аналіз (ранні зупинки)
Alpha-spending (O’Brien–Fleming/Pocock): фіксуємо графік перевірок і витрачаємо α по етапах.
SPRT/Bayes - для оперативних рішень, але фіксуйте протокол.
4. 3. Варіанс-редакшн
CUPED: Y = Y − θ (X − μ_X), де X - передекспериментальний коваріат (AR/DR/ризик-скор), θ - коваріантний коефіцієнт.
Стратифіковані оцінки, кластер-робастні помилки (user/BIN-кластери).
Bootstrap для take-rate/вартісних метрик (важкі хвости).
4. 4. Мультиваріантні тести та bandits
MAB (UCB/Thompson): коли важливо «вчитися» на льоту і не втрачати оборот.
Для комплаєнс-критичних метрик (CBR, liability) - віддайте перевагу класичному A/B з guardrails.
5) Архітектура платформи експериментів
1. Assignment-сервіс: детермінований хеш'( user_id, experiment_id, salt)'→ bucket.
2. Feature-прапори/Rules-engine: активація маршруту/3DS/ретрая по гілці.
3. Події: спроби/результати (authorize/capture/refund/cb) → шина (Kafka/PubSub).
4. Ідемпотентність: загальний'idempotency _ key'на каскад.
5. DWH/Вітрини: нормалізовані статуси, fees, FX, ризик-прапори.
6. Моніторинг: online-SLI (AR/3DS/latency), алерти, SRM-чек.
7. Протоколи: pre-register гіпотезу, фінальні критерії, дата-фриз.
6) Модель даних (мінімум)
sql ref. experiments (
exp_id PK, name, hypothesis, owner, start_at, end_at,
unit -- USER BIN ORDER,
target_metric, guardrails JSONB, design JSONB, alpha NUMERIC, power NUMERIC, meta JSONB
);
ref. experiment_arms (
exp_id FK, arm_id, name, traffic_share NUMERIC, params JSONB, enabled BOOLEAN
);
assignments. buckets (
exp_id, user_id, assigned_arm, assigned_at, salt, hash_key, PRIMARY KEY (exp_id, user_id)
);
events. payments (
attempt_id PK, user_id, exp_id, arm_id,
provider, method, bin, iso2, risk_score,
status, decline_code, three_ds_used BOOLEAN, liability_shift BOOLEAN,
amount_minor BIGINT, currency, latency_ms INT,
authorized_at, captured_at, settled_at, meta JSONB
);
finance. fees (
attempt_id FK, interchange_amt NUMERIC, scheme_amt NUMERIC, markup_amt NUMERIC,
auth_amt NUMERIC, refund_amt NUMERIC, cb_amt NUMERIC, gateway_amt NUMERIC,
fx_slippage_amt NUMERIC, reporting_currency TEXT
);
risk. outcomes (
attempt_id FK, is_refund BOOLEAN, is_chargeback BOOLEAN, fraud_alert BOOLEAN
);
7) SQL-шаблони
7. 1. SRM-чек (частка трафіку по руках)
sql
SELECT arm_id,
COUNT() AS n,
ROUND(100. 0 COUNT() / SUM(COUNT()) OVER (), 2) AS share_pct
FROM assignments. buckets
WHERE exp_id =:exp
GROUP BY 1;
7. 2. Основні метрики по руках
sql
WITH base AS (
SELECT e. arm_id,
COUNT() AS attempts,
COUNT() FILTER (WHERE status='APPROVED') AS approvals,
AVG(latency_ms) AS latency_avg_ms,
AVG((three_ds_used)::int) AS three_ds_share
FROM events. payments e
WHERE e. exp_id=:exp AND e. authorized_at BETWEEN:from AND:to
GROUP BY 1
),
cost AS (
SELECT e. arm_id,
SUM(f. interchange_amt + f. scheme_amt + f. markup_amt +
f. auth_amt + f. refund_amt + f. cb_amt + f. gateway_amt + f. fx_slippage_amt) AS fees_rep,
SUM(e. amount_minor)/100. 0 AS volume_rep
FROM events. payments e
JOIN finance. fees f USING (attempt_id)
WHERE e. exp_id=:exp AND e. settled_at BETWEEN:from AND:to
GROUP BY 1
)
SELECT b. arm_id,
approvals::numeric/NULLIF(attempts,0) AS ar,
fees_rep/NULLIF(volume_rep,0) AS take_rate,
(SELECT COUNT() FROM risk. outcomes r
JOIN events. payments e2 USING (attempt_id)
WHERE e2. exp_id=:exp AND e2. arm_id=b. arm_id AND r. is_chargeback)=0
AS cb_zero_flag,
latency_avg_ms, three_ds_share
FROM base b LEFT JOIN cost c ON c. arm_id=b. arm_id;
7. 3. CUPED для AR (приклад)
sql
WITH pre AS (
SELECT user_id, AVG((status='APPROVED')::int) AS ar_pre
FROM events. payments
WHERE authorized_at <:pre_from_end
GROUP BY 1
),
cur AS (
SELECT e. user_id, e. arm_id, (e. status='APPROVED')::int AS ar_flag
FROM events. payments e
WHERE e. exp_id=:exp AND e. authorized_at BETWEEN:from AND:to
)
SELECT arm_id,
AVG(ar_flag - theta (ar_pre - mu_pre)) AS ar_cuped
FROM cur
LEFT JOIN pre USING (user_id),
LATERAL (SELECT AVG(ar_pre) AS mu_pre FROM pre) mu,
LATERAL (SELECT COVAR_SAMP(ar_flag, ar_pre)/VAR_SAMP(ar_pre) AS theta FROM cur LEFT JOIN pre USING(user_id)) t
GROUP BY arm_id;
7. 4. Перевірка guardrails (приклад)
sql
SELECT arm_id,
100. 0 SUM(is_chargeback::int)::numeric / NULLIF(COUNT(),0) AS cbr_pct,
100. 0 SUM(is_refund::int)::numeric / NULLIF(COUNT(),0) AS refund_pct
FROM risk. outcomes r
JOIN events. payments e USING (attempt_id)
WHERE e. exp_id=:exp AND e. settled_at BETWEEN:from AND:to
GROUP BY 1
HAVING 100. 0 SUM(is_chargeback::int)::numeric / NULLIF(COUNT(),0) >:cbr_threshold
OR 100. 0 SUM(is_refund::int)::numeric / NULLIF(COUNT(),0) >:refund_threshold;
8) Процес проведення тесту (енд-ту-енд)
1. Pre-registration: гіпотеза, метрики, дизайн, розміри, стоп-правила.
2. SRM/AA-тест на «порожньому» ефекті (пару днів).
3. Запуск: assignment freeze, логіка в rules-engine/фічефлагах.
4. Моніторинг онлайн: AR/3DS/latency/health + guardrails.
5. Проміжні перевірки по alpha-spending (якщо планувалися).
6. Фініш і дата-фриз: тільки після обліку funding/резервів/пізніх CB/refunds.
7. Аналітика: CUPED/стратифікація, чутливість, гетерогенність по GEO/BIN/методу/каналу.
8. Рішення: roll-out, roll-back, або follow-up тест; оновлення правил/роутингу.
9. Документація та ретроспектива: уроки, оновлення порогів/ваг.
9) Анти-патерни і пастки
Peeking/пере-огляд без протоколу → помилкові перемоги.
Order-level рандомізація в тестах роутингу → витоку між руками.
Гра з множинністю (багато метрик/зрізів) без корекції α.
Неповна вартість (забули FX/резерв/refund fees) → невірний take-rate.
Відсутність SRM-чека → зміщені висновки.
Неідемпотентні ретраї → подвійні авторизації/спотворення AR.
10) Безпека, комплаєнс та етика
Same-method/return-to-source не повинні ламатися тестом.
Санкції/ліцензії/GEO-політики - поза експериментами.
RG/відповідальна гра: не погіршувати захисні механізми заради AR.
PCI/GDPR: токени замість PAN, мінімізація персональних даних, DPA/SOC2.
11) KPI дашборду експерименту
AR/DR, uplift і довірчі інтервали по руках і ключовим стратифікаціям (GEO/BIN/метод).
Cost-per-Approval, take-rate %, FX slippage (bps).
3DS pass/liability shift, soft-decline share.
Latency p95/p99, помилки/таймаути.
CB/Refunds (lag-aware), SRM, охоплення трафіку, тривалість.
12) Best practices (коротко)
1. Рандомізуйте на рівні користувача і стратифікуйте.
2. Використовуйте guardrails і SRM-чек; Фіксуйте протокол.
3. Рахуйте повну вартість (fees + FX + reserve) і cost-per-approval.
4. Застосовуйте CUPED, кластер-робастні помилки і bootstrap для вартісних метрик.
5. Для критичних ризиків - класичний A/B; bandits - для переважно цінових/AR завдань.
6. Враховуйте funding/резерви/пізні CB перед фінальним виведенням.
7. Документуйте і версіонуйте правила; робіть post-mortem.
13) Чек-лист запуску
- Гіпотеза, метрики, ефект, дизайн, розмір вибірки, термін.
- Юніт рандомізації і страти, assignment-сервіс, фічефлаги.
- Guardrails/пороги, SRM/AA-precheck, алерти.
- Логи/події, ідемпотентність, нормалізація статусів.
- Вітрини fees/FX/reserve; звітна валюта.
- План зупинок (alpha-spending) і дата-фриз.
- Плейбуки roll-out/roll-back; документація результатів.
Резюме
A/B тести платіжних сценаріїв - це інженерно-статистична дисципліна: правильна рандомізація і стратифікація, повні метрики вартості і ризику, guardrails і SRM, акуратна аналітика (CUPED/кластер-робастність/послідовний аналіз) і «боєздатна» інфраструктура (ідемпотентність, телеметрія, reconciliation). Дотримуючись цієї методики, ви підвищуєте AR, знижуєте all-in take-rate і при цьому не платите за «помилкові перемоги» зростанням чарджбеків і регуляторних ризиків.