У софту для оркестрації платежів дев’ять завдань. Вести кожен платіж за правилами, які можна прочитати. Повторювати ті відмови, які варто повторювати. Тримати карткові токени так, щоб ви змогли піти з ними. Підписувати кожен виклик API і захищати його від дублів. Доставляти вебхуки зі справжніми повторами. Перекладати коди провайдерів в один словник статусів. Зводити гроші з платежами після розрахунку. Показувати, чому обрано саме цього провайдера. Тримати тестовий трафік подалі від бойового.

Це і є чек-лист. Далі кожен пункт перетворено на питання, яке ви поставите на демо, плюс цифри з живого коду як лінійка для порівняння.

Одне застереження щодо цифр. Вони взяті з коду, у якому я працюю щодня, та з його бета-середовища, а не з бойового парку серверів — бойового парку поки немає. Це орієнтир, як звучить слово «конкретно», а не галузевий бенчмарк.

Якщо ви ще вирішуєте, чи потрібен вам такий клас софту, спершу прочитайте що таке оркестрація платежів, а сюди поверніться на етапі вибору.

Що таке софт для оркестрації платежів

Це софт між вашим checkout і кількома провайдерами. Він вирішує, куди піде кожен платіж, і звітує по всіх однією мовою.

Два слова тут часто плутають. Оркестрація — це практика. Софт для оркестрації — те, що ви купуєте або пишете заради неї. Платформа оркестрації — той самий софт як сервіс, де зв’язки з провайдерами вже написані.

Хто користується оркестрацією платежів? Мерчанти з двома і більше еквайєрами. Підписні сервіси, що живуть на продовженнях. Платформи, які рухають гроші за чужий бізнес. Маркетплейс успадковує географію та ризик-профіль кожного продавця одразу, тому до другого провайдера доходить раніше, ніж сам очікує.

Чи потрібна вам платформа оркестрації платежів? Ні, якщо у вас один провайдер, один ринок і немає скарг. Причини переходу нудні та конкретні: другий еквайєр, ринок, де нинішній слабкий, або питання ради директорів про вартість платежу. Якщо жодної з них немає, вкладіть сили в checkout.

Четверта група рідко потрапляє в презентації вендорів: софтверні компанії, що вбудовують платежі у власний продукт. Вертикальному SaaS, який почав платити своїм користувачам, маршрут потрібен з першого дня. Разом із ним токени. І звірка. А платіжної команди в нього немає. Для них чек-лист нижче — не гід покупця, а технічне завдання.

До демо: що має бути готове з вашого боку

Кожен провальний вибір вендора, який я бачив, зірвався з однієї причини. Покупець не міг описати власний трафік — і будь-яка відповідь звучала добре.

Візьміть на перший дзвінок чотири речі:

  • Перелік провайдерів зі ставкою за договором на кожен тип карток, а не рекламну ставку.
  • Відмови за минулий місяць, згруповані за кодом причини, топ-3 за кількістю.
  • Розріз обсягу за країною та брендом картки. Локальний дебет і закордонний кредит скрізь поводяться інакше.
  • Операції, якими ви справді користуєтесь. Повернення, часткові повернення, холди, виплати, чарджбеки, рекурент.

Останній пункт вирішує більше, ніж маршрут. У контракті адаптерів, який я веду, дев’ять операцій: створити платіж, завершити 3DS, списати холд, скасувати, повернути, спитати статус, прийняти вебхук, виплатити на картку, виплатити на рахунок. Кожен конектор мусить відповісти на всі дев’ять, навіть коли провайдер за ним такого не вміє. З п’яти підключених еквайєрів виплату на картку роблять чотири, а виплату на IBAN — лише один. Ще один не вміє ні того, ні іншого і відповідає чесним «не підтримується».

Така асиметрія — норма, а не чиясь невдача. Просіть у вендора ту саму матрицю: операція за операцією, провайдер за провайдером. Одна колонка «підтримується» — тривожний знак.

Дев’ять речей, які софт мусить уміти

1. Вести маршрут за правилами, які читає людина

Правила маршруту вирішують, кому дістанеться платіж. Увесь набір ви маєте прочитати вголос за хвилину.

Рушій із цих прикладів завантажує правила в межах однієї юрособи, і правила вміють жити за розкладом: правила «тільки на вихідних» у вівторок у наборі просто немає. Правило BLOCK зупиняє платіж до вибору провайдера. Правило ROUTE називає пул провайдерів, і цей пул стає списком кандидатів. Жодне ROUTE не збіглося? Тоді кандидат — будь-який провайдерський акаунт юрособи.

Копіювати тут варто інше: місце, де ловиться конфлікт. Збігтися може тільки одне правило ROUTE, і перевірка стоїть у момент збереження, а не в момент платежу. Перетин правил — помилка конфігурації, а ловити таке треба на конфігурації.

Спитайте на демо: створіть два правила, які перетинаються, і збережіть їх. Якщо обидва збереглися, спитайте, яке переможе о третій ночі. Відповідь «перше» означає, що ви отримали проблему порядку, яку ніхто не задокументує.

2. Повторювати ті відмови, які варто повторювати

Каскад на другого провайдера після відмови звучить як безкоштовні гроші. Він не безкоштовний.

Частина відмов остаточна. Крадена картка лишається краденою і в наступного провайдера. Ви заплатите за другий запит, додасте секунди в checkout і отримаєте другий рядок у звіті. А частина емітентів читає повторні спроби за однією карткою як ознаку фроду.

Тому перелік для повтору важливіший за рушій повторів. Каскад у цьому коді вмикається, лише якщо перший результат ліг у declined. Він виключає акаунт, який щойно впав, і зупиняється на першому провайдері з будь-якою відповіддю, крім відмови. Це вузько навмисно.

Складне — у мапінгу під ним. Погляньте на чотири реальні коди з тих самих конекторів:

ПровайдерКодЩо означаєНаївне читання
UPC131Потрібна додаткова автентифікація (SCA)відмова
UPC290Банк-емітент недоступнийвідмова
PayLink406Операція виконується, спитайте пізнішевідмова
PayLink400Потрібна перевірка 3DSвідмова

Жоден із чотирьох не відмова. Два означають «клієнту є що доробити», один — «банк лежить, спробуй іншого», один — «спитай мене пізніше». Прочитаєте їх як відмову — завалите живі платежі. Відправите всі в повтор — гатитимете по емітентах спробами, які не можуть пройти.

Що спитати: покажіть перелік повторів як дані, а не як фразу. Які коди в ньому, хто його редагує і чи потрібен реліз заради правки.

3. Віддавати токени, з якими можна піти

Токен картки — це посилання замість номера картки, щоб сам номер лежав в одному місці.

Долю токенів вирішують два питання. Де лежить номер картки і що станеться з токенами, якщо ви підете.

У P26M номер картки живе рівно в одному сервісі. Усе інше — запис платежу, звіти, маршрут — носить UUID. Номер зашифровано ключем AES-256-GCM96 усередині HashiCorp Vault, і ключ сам ротується кожні 2160 годин: це 90 днів, криптоперіод, який ми для нього задали. Ключ не покидає Vault, тому дамп бази — це купа шифротексту.

Зберігання — легка половина. Вендори пропускають другу: життєвий цикл. Сховище, яке вміє тільки створити й прочитати токен, — половина сховища. Тут є ще довідка по токену, заморозка, розморозка, видалення. Кожен такий виклик звіряється з реєстром: якому мерчанту яка операція над яким токеном дозволена.

Три питання тут. Чи можна заморозити один токен, не видаляючи його? Чи можна вивантажити токени, якщо договір скінчиться? І на чиє ім’я випущені мережеві токени — Visa та Mastercard — на ваше чи вендора? Відповідь на останнє і є все питання про прив’язку до вендора, однією фразою.

4. Підписувати весь запит, а не лише тіло

Цей пункт не видно на слайді, а в проді він дорогий.

Колишня схема підпису, ще наша, покривала тіло запиту та час. Виглядала нормально. Не була: підпис для POST /payments/{A}/refund лишався чинним для POST /payments/{B}/void з тим самим тілом. Метод, шлях, query-рядок, UUID ресурсу — усе це лежало поза підписом.

Заміна підписує канонічний рядок із восьми полів: версія, HTTP-метод, шлях, канонічний query, SHA-256 тіла, час, nonce, плюс ключ ідемпотентності. Вікно за часом — 300 секунд в обидва боки. Nonce пам’ятається вдвічі довше, окремо по кожному ключу API, а повтор повертається як HTTP 409 з кодом SIGNATURE_REPLAYED.

Ключ ідемпотентності всередині підписаного рядка — та деталь, яку варто перевірити. Якщо ключ лежить поза підписом, він стає вільним параметром підписаного запиту.

Сама ідемпотентність проста і легко ламається непомітно. Тут вона за бажанням: надішлете заголовок Idempotency-Key — відповідь ляже в кеш на 24 години, не надішлете — запит відпрацює як звичайно. У ключ кешу входить UUID ключа API. Я точно знаю, що буває, коли цей поділ ламається: перейменування заголовка ледь його не зламало. Усі мерчанти злилися б в один кошик, і відповідь одного могла б повернутися іншому.

Спробуйте просто на зустрічі: надішліть один і той самий запит двічі з одним ключем ідемпотентності та покажіть обидві відповіді. Потім надішліть його з підписом, знятим з іншого ендпоінта.

5. Доставляти вебхуки як черга, а не як надія

Вебхуки — спосіб вашим системам дізнатися, що платіж змінився. На демо зазвичай показують, як один приходить. Спитайте, що буде, коли ваш ендпоінт впаде.

Раніше тут був один HTTP POST із таймаутом 10 секунд, просто всередині запиту, якого чекає платник. Два наслідки, обидва заміряні. Повільний ендпоінт додавав до 10 секунд до відповіді checkout, а підписки оброблялися поспіль: три підписки — до 30 секунд. Повторів не було зовсім: при невдачі писався рядок у лог, і сповіщення зникало.

Те, що прийшло на заміну, — форма, якої варто чекати від будь-якого серйозного продукту:

ВластивістьЗначення
Спроби1 + 4 повтори
Паузи10 с → 1 хв → 5 хв → 15 хв
Таймаут HTTP на спробу10 с
Після останнього провалузапис у dead-letter, статус exhausted
Журнал по кожній спробіномер спроби, HTTP-статус, тривалість у мс, адреса

Дві деталі варто вкрасти. Тіло фіксується в момент події й не перезбирається при повторі. Інакше вебхук після 15-хвилинної паузи описав би платіж таким, який він зараз, — і події прийшли б не в тому порядку. Підпис, навпаки, рахується заново на кожній спробі зі свіжим часом: підпис п’ятнадцятихвилинної давнини — це replay, і ваш код мусить його відкинути.

Зламайте це навмисно: спрямуйте вебхук на ендпоінт, який віддає 500, і попросіть журнал доставок. Немає журналу — немає способу відповісти на питання «пішло чи ні» під час інциденту, а його ставлять завжди.

6. Тримати один словник статусів — і слова провайдера

У кожного провайдера свій діалект, і діалекти більші, ніж здається.

Один провайдер із тієї п’ятірки документує 66 кодів результату. Конектор зводить їх до чотирьох станів. Коди 100, 101, 102 — успіх. Коди 400 і 401 — очікування, 406 — в обробці. Усе, що починається на 2, 3 або 4, — відмова, а п’ятисоті — помилка. Інший відповідає 22 різними рядками статусу, і в десятьох із них є слово «wait»: чекаємо 3DS, чекаємо готівку в терміналі, чекаємо скан QR. Зведіть ці десять до одного «в очікуванні» — і підтримка більше не скаже клієнту, що робити далі.

Пастка з третього конектора, з тих, які зустрічаєш тільки в проді. Слово hold приходить у двох його відповідях. У статусі замовлення воно означає, що гроші захолдовано. У відповіді на списання — що списання відхилено. Одне слово, зворотний зміст, одна літера різниці в коді, який його читає. Тому мапінг статусів пишеться під операцію, а не під слово.

І чесне про код, про який ця стаття. Ті самі коди PayLink 101 і 102 означають «пройшло, але на частину суми». Сьогодні мапер кладе їх у той самий кошик, де лежить звичайний успіх. Тому в записі платежу лишається запитана сума. Я про це знаю. Шукайте такий самий шов у будь-якому продукті, який дивитесь: спитайте, де в записі видно часткове списання, і подивіться, звідки прийде відповідь — з демо чи з роадмапу.

Попросіть показати запис платежу, де поруч лежать ваш нормалізований статус і сирий код провайдера. Якщо сирий код не зберігається, кожна майбутня суперечка — вгадування.

7. Звіряти гроші, а не тільки платежі

Оркестрація зводить вигляд на платежі. Вигляд на гроші вона сама не зводить, і саме в цьому розриві фінансова команда втрачає вечори.

Звірка за переказами з рахунку на рахунок працює тут за подіями банківської виписки. Поведінку варто розписати, бо кожне правило з’явилося з чийогось досвіду:

  • Зіставлення йде за order reference усередині призначення платежу, плюс сума, плюс валюта. Живі платежі в пріоритеті перед завершеними.
  • Якщо reference порожній, матчер відкочується на суму та валюту у вікні ±30 хвилин навколо часу зарахування.
  • Якщо такий відкат знайшов більше одного живого кандидата, він зупиняється і лишає подію незіставленою. Два клієнти, що платять по 500 UAH із різницею у хвилину, — не рідкість, а вгадування тут означає закрити чужий рахунок.
  • Повторну доставку тієї самої банківської транзакції ловить обмеження унікальності за джерелом і зовнішнім id, а сама подія позначається як duplicate до того, як щось торкнеться платежу.
  • Зарахування, що прийшло після того, як платіж збіг, відкриває його знову — але тільки всередині grace-вікна у 30 хвилин. Поза вікном подія лишається в черзі звірки для людини.
  • Усе решта лягає в один із п’яти статусів, включно з manual для тих, що оператор звів руками.

Нічого хитрого тут немає. Це бухгалтерія, записана один раз замість щомісячної суперечки. У софті вона живе не з краси, а з обсягу: правило, яке людина вірно застосовує на тридцяти подіях на день, перестає застосовуватися вірно на трьохстах.

Друга половина рідко доїжджає до демо, і живе в ній якраз ваш фінвідділ. П’ять провайдерів — це п’ять файлів розрахунків, п’ять розкладів, п’ять назв для повернення і п’ять способів утримати комісію до зарахування. Спитайте, що шар робить із цими файлами, а не тільки з платежами. Відповідь «ми віддаємо API, імпорт ви напишете самі» — чесна відповідь, але тепер ви знаєте, що проєкт ваш.

Вимагайте екран: незіставлене зарахування і місце, де людина його розбирає. У будь-якої справжньої звірки є ручний шлях. Продукт без нього просто ще не зустрічався з банківською випискою.

8. Показувати свою роботу

Коли платіж пішов не так, у вас одне питання: чому він пішов туди.

Відповідь потребує запису на кожен виклик провайдера. Такий запис тримає запит і відповідь, HTTP-код, час виконання в мілісекундах. І — те, що найчастіше пропускають, — id правила маршруту, яке обрало акаунт, плюс повний набір правил, що спрацювали. Тому «чому цей платіж пішов туди» — це вибірка, а не розслідування.

З боку API кожен запит отримує UUID, який повертається в заголовку відповіді, а весь обмін іде в окремий структурований аудит-канал. Канал з’явився тому, що вимога PCI DSS 10.2.1 просить журнал доступу до компонентів системи, і він же виручає при звичайному налагодженні. Чутливе вирізається до запису: номери карток, звісно, але ще й capability-токени всередині URL, бо лог із витеклим токеном перетворює архів логів на в’язку запасних ключів.

Засічіть час. Дайте мені id платежу і покажіть на одному екрані всі його виклики та правило, яке обрало провайдера. Порахуйте кліки. У ніч інциденту у вас буде три хвилини.

9. Розділяти пісочницю та прод

Звучить як галочка, але галочкою не є.

Кандидати з чужого середовища викидаються для будь-якого типу операції, а не тільки для карткових платежів. Якщо після фільтра не лишилося нікого, платіж падає з «немає провайдера», а не бере тихо тестовий акаунт. Тиха підміна гірша за відмову: відмову видно сьогодні, а підміну знаходять наприкінці місяця.

Ще одна перевірка: спробуйте відвести бойовий платіж на тестовий акаунт провайдера і покажіть помилку. Вийшло — отже бар’єр це ярлик, а не правило.

Параметри та значення: що просити в цифрах

Вендори відповідають на прикметники прикметниками. Просіть цифри і порівнюйте ось із цими — не тому, що ці правильні для вас, а тому, що вендор, який не може назвати свої, про них не думав.

ПараметрОпорне значенняЧому це важливо
Вікно здоров’я провайдера1 година, перерахунок кожні 5 хвКоротше — реакція на шум, довше — пропустите падіння зараз
Формула здоров’я70% успішність, 30% час відповідіМенше 1 с — повний бал, 10 с — нуль
Поріг здоров’я40 зі 100Нижче провайдер випадає з маршруту
Бал без свіжого трафіку50, нейтральноТихий провайдер не значить зламаний
Усі провайдери хворіФільтр знімається, платіж усе одно йдеЧистота замість виручки — поганий розмін
Таймаут на виклик провайдера30 сОдному потрібні два виклики на платіж, рахуйте вдвічі
Повтори вебхука5 спроб приблизно за 21 хвДив. таблицю пауз вище
Кеш ідемпотентності24 год, окремо по ключу APIДовше — рахунок за пам’ять, коротше — губиться страховка
Вікно свіжості підпису±300 сЗапас на розбіжність годинників проти вікна replay
Ліміт запитів60 за хвилину на мерчантаПитайте і число, і поведінку на сплеску
Життя сесії checkout30 хвНадто коротка рубає живих клієнтів посеред оплати
Полів облікових даних на провайдеравід 3 до 10Праця підключення у провайдерів різна

Нижній рядок дивує людей. Підключення одного з тих п’яти еквайєрів — три поля. Іншого — десять, і обов’язкові з них лише три: тобто сім способів налаштувати його майже правильно. Коли вендор каже «у нас 200 провайдерів», корисне питання далі — скільки полів потрібно їхньому найсвіжішому конектору і хто їх заповнює.

Типові помилки і як зловити їх рано

Купівля роутера, коли потрібен сейф. Якщо справжня біда в тому, що карткові дані розкидані по трьох системах, правила маршруту не допоможуть. Спершу дані, маршрут після — він простіший.

Віра в таблицю можливостей. «Підтримується» в маркетинговій таблиці і «підтримується» в гілці коду, що працює о третій ночі, — різні слова. Одна знайома мені таблиця можливостей ставить wallet-метод усім п’ятьом еквайєрам, а криптограму гаманця прямо на нашому checkout приймають двоє: решта троє підтримують гаманець на власній платіжній сторінці. Спитайте, яке джерело читає код маршруту.

Маршрут за пласкою ставкою. Реальна вартість залежить від бренду, підтипу картки, суми, методу. Провайдер, дешевший на локальному дебеті, часто дорожчий на закордонному кредиті. Сортування за одним відсотком із договору впевнено обиратиме не того цілий день і малюватиме вам охайний звіт.

Забути, що одна інтеграція — одна залежність. Ви прибрали п’ять інтеграцій і додали одну штуку, крізь яку йде кожен платіж. Зазвичай це вірний розмін. Але все ж розмін: спитайте про процес релізів, про історію аптайму і про те, чи дотягнетесь ви до провайдера напряму, якщо шар лежить.

Лишити це без власника. Правила кодують рішення, а рішення все одно хтось ухвалює. Платформа не замінює людину, яка його ухвалює. Команди, що купили платформу і не призначили відповідального, отримують дорожчу версію того, що було.

Вважати, що комплаєнс переходить у спадок. Сертифікат вендора покриває вендора. Ваша зона залежить від того, де у вашій схемі тече картковий номер. Вимога PCI DSS 12.8 чекає від вас переліку сторонніх постачальників послуг і свідчень їхнього статусу. Тому просіть їхню атестацію та матрицю відповідальності письмово — на етапі вибору, а не на етапі аудиту.

Сценарій демо в шість кроків

Дві години з живою системою скажуть більше, ніж місяць презентацій. Ідіть по порядку і пишіть нотатки просто в кімнаті.

  1. Підключіть тестового провайдера самі. Не спільний демо-акаунт, а свіжий, і креденшели вводите ви. Засічіть час. Це найближче, що є до прев’ю вашої майбутньої інтеграції.
  2. Проведіть один картковий платіж. Потім відкрийте запис і знайдіть: сирий код провайдера, нормалізований статус, правило маршруту та час відповіді.
  3. Зламайте навмисно. Спрямуйте вебхук на URL, що віддає 500. Подивіться на повтори. Попросіть журнал доставок і запис dead-letter.
  4. Повторіть запит. Надішліть один і той самий виклик двічі з одним ключем ідемпотентності. Потім ще раз — із підписом від іншого ендпоінта. Другий мусить впасти.
  5. Змусьте маршрут обрати неправильно і полагодьте без релізу. Додайте правило, що жене все на дорогого провайдера, дочекайтесь ефекту і зніміть його. Заміряйте, скільки часу правка йде до бойового трафіку.
  6. Поставте питання про звірку. Покажіть незіставлене вхідне зарахування та екран, де людина його розбирає.

Оцініть шість кроків чесно того ж дня, поки наступний дзвінок не змішав відповіді. Усе, чого ви не змогли зробити самі та в кімнаті, — це те, чого ви потім чекатимете.

Як зрозуміти, що запрацювало

Купівля — не фініш. Чотири перевірки в першому кварталі скажуть, чи окупає шар своє місце.

Склад відмов змінив форму. Не підсумковий відсоток, а склад. Якщо ті самі коди причин ідуть у колишніх частках, маршрут нічого не робить. Справжнє обмеження тоді вище за потоком.

Інцидент провайдера минув нудно. Коли один еквайєр деградує вперше, з виручкою не має статися нічого, крім рядка на дашборді. Якщо довелося збирати нараду, автоматики ще немає.

Фінанси перестали ходити до розробки по цифри. Схвалення за країнами, вартість платежу, повернення за провайдерами — це звіти, а не тікети.

Хтось змінив правило маршруту без релізу. Якщо через три місяці відповідь звучить як «їх ніхто не чіпав», то або дефолти ідеальні, або в шару немає власника. Друге буває частіше.

Є ще одна перевірка, найнезручніша. Спробуйте піти. Не насправді — на папері. Випишіть, що ви заберете: токени, мандати, договори з провайдерами, історію операцій. Короткий перелік означає, що ви купили не софт, а оренду залежності. Як ця скриня влаштована всередині — ті самі деталі, з яких беруться відповіді вище, — розбираємо в матеріалі що таке шар оркестрації платежів, а різницю між шлюзом і шаром — у статті оркестрація платежів проти платіжного шлюзу.

Чого цей софт для вас не зробить

Варто сказати прямо, бо категорію продають так, ніби вона лагодить усе.

Він не полагодить поганий відсоток схвалень сам по собі. Роутер не лікує причину, він лише переносить спробу. Маршрут відводить платежі туди, де їх скоріше схвалять. Якщо всі ваші провайдери відмовляють тому самому трафіку з тієї самої причини, маршрут просто розмаже відмови. Лікування живе в коді причини.

Ваша PCI-зона не зсунеться від того, що з’явився шар. Її вирішує те, як карткові дані течуть крізь ваш checkout. Шар, який пропускає крізь себе сирі номери карток, лишить вас рівно там само, де ви були.

Слабкий еквайєр лишиться слабким. Якщо у провайдера погане покриття на ринку, роутер перед ним покриття не додасть. Він тільки спростить відправку цього трафіку в інше місце.

І ніщо з цього переліку не обере за вас. Дев’ять пунктів вище — це специфікація, а не рейтинг. Продукт може провалити звірку і все одно підійти компанії, у якої один файл розрахунків на тиждень.

Перш ніж складати шорт-лист, поставте цифру на те, чого варта зміна: нинішні комісії, обсяг, який ви переведете, відмови, які міг би повернути повтор. ROI-калькулятор на цьому сайті проходить цю арифметику хвилин за п’ять, і на виході ви отримаєте число, з яким іти на перший дзвінок замість прикметника.