GH GambleHub

Звірка платежів і звітів PSP

TL; DR

Звірка - це щоденне автоматизоване зшивання вашого леджера і подій (auth/capture/refund/payout) зі звітами PSP/еквайєрів/банків. Ключ до успіху: єдина модель даних, детерміновані ключі зіставлення, сувора ідемпотентність, толеранси за сумами/FX/часу, черга DLQ для спірних кейсів і плейбуки автокорекцій. KPI: Recon Mismatch Rate↓, Aging of Unreconciled↓, Auto-match%↑.

1) Навіщо і що звіряємо

Цілі: підтвердження виручки і комісій, виявлення дублів/втрат, коректний settlement по днях і валютах, контроль refund-to-source, відповідність аудиту/регулятору.

Об'єкти звірки:
  • Deposits: `auth → capture → settle`
  • Refunds: full/partial, статуси та суми
  • Payouts/Withdrawals: вихідні платежі за методами
  • Fees & Adjustments: комісії PSP, схеми інтерчейнджа, корекції
  • Chargebacks/Disputes: поза вашою ініціативою
  • FX/Конвертації: курси, спреди, момент фіксації

2) Джерела даних

Internal Events (ваші): шина подій/Kafka,'payments _ flat','refunds','payouts', ваш Ledger.

PSP Reports (SFTP/API/webhook dump):
  • Transactions (операційні виписки)
  • Settlements/Batches (розбивки зарахувань T + N)
  • Fees/Statements (комісії, коригування)
  • Chargebacks/Disputes
  • Payouts/OCT/RTP/SEPA реєстри
  • Bank Statements: MT940/CSV/ISO20022 CAMT, підтяжка зарахувань.
💡 Сховище: landing → raw → normalized → matched. Всі вхідні файли - з контрольними сумами і версіонуванням.

3) Ключі зіставлення (matching keys)

Пріоритетне дерево ключів (за спаданням точності):

1. provider_txid ↔ provider_txid (унікальний ID PSP)

2. idempotency_key/ merchant_reference (якщо стабільні у PSP)

3. (amount, currency, timestamp_bucket, last4/bin, auth_code)

4. Fuzzy-шар: ± толеранси за сумою/часом, BIN/issuer country, status family

Рекомендації:
  • Зберігайте у себе обидва: `payment_id` и `provider_txid`.
  • Для partial/refund - додавайте'sequence _ index'або'refund _ line _ id'.
  • Для payouts — `payout_batch_id + line_id`.
  • Для FX -'exec _ id'( конвертація) і джерело курсу.

4) Модель даних (нормалізований шар)

json
{
"source": "INTERNAL    PSP_TX    PSP_SETTLEMENT    BANK",
"provider": "Acquirer_A",
"payment_id": "pay_123",
"provider_txid": "psp_tx_789",
"kind": "AUTH    CAPTURE    REFUND    PAYOUT    FEE    SETTLEMENT    CHARGEBACK",
"sequence": 0,
"amount": 100. 00,
"currency": "EUR",
"fee_amount": 1. 20,
"fx_rate": 1. 0000,
"fx_src": "PSP    ECB    BANK",
"status": "APPROVED    CAPTURED    SUCCESS    FAILED    SETTLED",
"event_ts": "2025-11-03T12:00:00Z",
"settlement_date": "2025-11-05",
"account": "PSP_MERCHANT_CARD_A",
"matching_keys": {
"provider_txid": "psp_tx_789",
"merchant_ref": "mr_456",
"idem_key": "idem_abc"
},
"hash_row": "sha256(...)"
}

5) Процес звірки (ETL/оркестрація)

1. Ingest: забираємо звіти PSP (SFTP/API), валідуємо схему/підписи, зберігаємо в'raw'.
2. Normalize: маппім поля в уніфікований формат (currency ISO, decimals, таймзона UTC).
3. Match: алгоритм зіставлення по дереву ключів з толерансами.
4. Post-match: формуємо diff (розбіжності) і journal entries для леджера/корекцій.
5. Settle: зшиваємо'PSP _ SETTLEMENT ↔ BANK'( зарахування на рахунок), розкидаємо по днях/батчах.
6. Report: дашборд, алерти; спірні в DLQ на ручний розбір/автопереігрування.

Ідемпотентність: на кожен файл/сторінку -'ingest _ id'. Повторне завантаження не змінює результат.

6) Толеранси (tolerances) і правила

Час: '± 15 хв'для транзакцій,'± 1 дн'для settlement.
Сума: `≤ 0. 01'базової валюти або'≤ 10 bps'для FX/fee-різниць.
FX: допускаємо розбіжність з банком, якщо джерело курсу різне; фіксуємо'fx _ src'.
Partial/Multiple: сума по лініях partial/refund повинна дорівнювати внутрішньому залишку.

7) Обробка розбіжностей (diff taxonomy)

Тип diffОписДія
MISSING_INTERNALУ PSP є, у нас немаєСтворити orphan case, перевірити webhooks/ретраї
MISSING_PSPУ нас є, у PSP немаєПеревірити статус/повтор, контакт PSP
AMOUNT_MISMATCHСуми розрізняються> толерансАвтокорекція/журнал, ескалація при необхідності
FEE_MISMATCHКомісії відрізняютьсяПрийняти PSP як «істину» (policy) або зажадати credit note
STATUS_DRIFTCAPTURE у нас, AUTH у PSPПеревірити вебхукі capture/settlement
DUPLICATEДублі рядківДедуп по'provider _ txid/idempotency _ key '
FX_DRIFTКурси розходятьсяВстановити офіційне джерело, налаштувати P&L
REFUND_OVERRefund > capturedТерміновий блок, ручний розбір, журнал зворотної корекції

8) Ledger & Accounting (проводки)

Capture: `DR Accounts Receivable / CR Revenue` и `DR Cash (upon settle) / CR Accounts Receivable`

Fee: `DR Fees / CR Cash or Payable`

Refund: зворотні проводки пропорційно partial

Chargeback: окремі рахунки та резерв під спори

FX reval: щоденна переоцінка залишку AR/кешу за курсом'fx _ src _ policy '

9) KPI і цілі

Auto-match% = автоматично зіставлені рядки/всі рядки (мета ≥ 95%)

Recon Mismatch Rate = diff-рядки/всі рядки (≤ 1-2%)

Aging of Unreconciled: p50/p95 днів перебування в DLQ (p95 ≤ 3 дн)

Settlement Timeliness: частка батчів, зшитих з банком D-день (≥ 99%)

Fee Accuracy: розбіжності комісій з провайдерів (≤ 0. 1% обороту)

Duplicate/Orphan Incidents: прагне до 0

10) SQL-зрізи

10. 1 Базове зіставлення за provider_txid

sql
WITH i AS (
SELECT provider, provider_txid, kind, amount, currency, event_ts
FROM internal_norm
),
p AS (
SELECT provider, provider_txid, kind, amount, currency, event_ts
FROM psp_norm
)
SELECT
COALESCE(i. provider_txid, p. provider_txid) AS txid,
COALESCE(i. provider, p. provider) AS provider,
i.kind AS kind_internal, p. kind AS kind_psp,
i.amount AS amount_internal, p. amount AS amount_psp,
i.currency, p. currency,
CASE
WHEN i.provider_txid IS NULL THEN 'MISSING_INTERNAL'
WHEN p. provider_txid IS NULL THEN 'MISSING_PSP'
WHEN ABS(i. amount - p. amount) > 0. 01 THEN 'AMOUNT_MISMATCH'
ELSE 'MATCHED'
END AS recon_status
FROM i
FULL OUTER JOIN p USING (provider, provider_txid);

10. 2 Settlement ↔ Bank

sql
SELECT s. settlement_date, s. batch_id, s. currency,
s. amount_settled, b. amount_bank,
(b. amount_bank - s. amount_settled) AS diff
FROM psp_settlements s
LEFT JOIN bank_statements b
ON b. value_date = s. settlement_date
AND b. currency = s. currency
AND ABS(b. amount_bank - s. amount_settled) <= 0. 5;

10. 3 Aging DLQ

sql
SELECT diff_type,
COUNT() AS cnt,
PERCENTILE_CONT(0. 5) WITHIN GROUP (ORDER BY AGE(NOW(), created_at)) AS p50_age,
PERCENTILE_CONT(0. 95) WITHIN GROUP (ORDER BY AGE(NOW(), created_at)) AS p95_age
FROM recon_dlq
GROUP BY diff_type
ORDER BY cnt DESC;

11) Особливості по рейках/кейсах

Карти: відмінності між'auth'і'capture', пізні'settlement'коригування, інтерчейндж/схемні fee - окремими лініями.
A2A/Open Banking/RTP: миттєві підтвердження, але можливі'reversal'; звіряйте'payout'і повернення.
Гаманці: часто ідеальні'provider _ txid', швидкі'refund'; слідкуйте за fee-лініями.
Ваучери: немає симетричного refund - відображайте коректно в політиці і звітах.
Крипто: он-чейн hash ↔ provider_txid; конфірми N; облік комісій мережі та можливих ребейтів; курс - на момент конвертації.

12) Операційні плейбуки

Сплеск MISSING_INTERNAL: перевірити втрату вебхуків/ретраїв, переграти ingestion, включити полінг API.
AMOUNT_MISMATCH у одного PSP: порівняти заокруглення/ПДВ/fee-модель, запитати коригувальний statement.
Settlement не зшивається з банком: перевірити value date, комісії банку, затримки T + N; тимчасово ставити в «Suspense Account».
Масові REFUND_OVER: негайний стоп авто-рефандів, аудит ідемпотентності, ручна корекція.
FX_DRIFT: зафіксувати policy джерела курсу (ECB/PSP/BANK), перерахувати P & L-різниці.

13) Контроль і безпека

Ідемпотентність ingestion: 'file _ id + checksum'і журнал завантажень.
Доступи (RBAC) і 4-очний контроль: на ручні корекції/журнальні проводки.
Аудит-трейл: всі матчі/дифи/корекції - в незмінному журналі.
Якість даних: схеми, обов'язкові поля, валідація валют/скейла.

14) Дашборд і алерти

Віджети: Auto-match%, Mismatch Rate, Aging DLQ, Settlement Timeliness, Fee Accuracy, топ-PSP по дифам, карта diff-типів.

Алерти:
  • 'Auto-match% <90%'по провайдеру/дню → P1
  • 'Aging p95> 3 дн'→ P2
  • `AMOUNT_MISMATCH spike` → P1
  • 'Bank≠Settlement'по сумі/валюті → P0

15) Тест-кейси (UAT/Prod)

1. Повторне завантаження того ж файлу → 0 побічних ефектів (ідемпотентність).
2. Часткові рефанди (3 лінії) → сума збігається, матч по sequence.
3. FX-конвертація: розбіжність курсу в межах толерансу → коректний match.
4. Дублікати provider_txid у звіті → дедуп і алерт.
5. Зниклий webhook capture → полінг закрив gap, статус вирівняний.
6. Settlement батч з fee-лінією → правильна розбивка на Revenue/Fee/Net.

16) Часті помилки і як уникнути

Змішування баз порівняння (compare'attempt'vs'capture') → тримайте однакову гранулярність.
Відсутність'provider _ txid'в лозі → втрачається точність матчу.
Ігнор таймзон → зміщення по датах settlement.
Немає DLQ/ретраїв → «вічні» розбіжності.
Ручні правки без журналу → несхідність з аудитом.
Нечіткі толеранси → або пере-матч, або «все в DLQ».

17) Контрольний чек-лист впровадження

  • Єдина схема нормалізації та довідники PSP/методів/акаунтів
  • Дерево ключів зіставлення (txid → merchant_ref → fuzzy)
  • Толеранси за сумою/часом/FX, політика джерела курсу
  • Ідемпотентний ingestion, DLQ, ретраї, алерти
  • Звірка Settlement↔Bank, Suspense Account політика
  • Дашборд KPI, звітність для фінансів/аудиту
  • Плейбуки і SLA розбору diff-кейсів

Резюме

Звірка - це інженерна дисципліна: нормалізація, надійні ключі, толеранси, автоматичні матчі і прозорі корекції. З таким контуром ви стабілізуєте виручку і комісії, мінімізуєте «чорні діри», прискорюєте закриття періоду і проходите аудит без болю: Auto-match%↑, Mismatch↓, Aging↓.

Contact

Зв’яжіться з нами

Звертайтеся з будь-яких питань або за підтримкою.Ми завжди готові допомогти!

Telegram
@Gamble_GC
Розпочати інтеграцію

Email — обов’язковий. Telegram або WhatsApp — за бажанням.

Ваше ім’я необов’язково
Email необов’язково
Тема необов’язково
Повідомлення необов’язково
Telegram необов’язково
@
Якщо ви вкажете Telegram — ми відповімо й там, додатково до Email.
WhatsApp необов’язково
Формат: +код країни та номер (наприклад, +380XXXXXXXXX).

Натискаючи кнопку, ви погоджуєтесь на обробку даних.