# Payment Provider Integration Specification

> Complete before writing the integration. The sections that decide whether this works are §3
> (idempotency), §4 (the ambiguous state) and §7 (reconciliation) — the rest is detail around them.

**Provider:** _______________  **Product / flow:** _______________
**Owner:** _______________  **Date:** _______

## 1. Scope

| | |
|---|---|
| Payment methods supported | |
| Currencies | |
| Markets / jurisdictions | |
| Who holds customer funds | |
| Our regulated status for this flow | (confirmed in writing? yes / no) |

## 2. Money movement map

Draw every path money can take, including failures.

| # | Event | Money moves | Ledger entries written |
|---|---|---|---|
| 1 | Authorisation | | |
| 2 | Capture | | |
| 3 | Settlement | | |
| 4 | Refund | | |
| 5 | Partial refund | | |
| 6 | Chargeback | | |
| 7 | Chargeback reversal | | |
| 8 | Provider fee | | |

**Every row must have a ledger entry pair.** A movement with no entry is a break waiting to happen.

## 3. Idempotency

| | |
|---|---|
| **Key generated by** | client / server |
| Scope of one key | one logical payment attempt |
| Where stored, and for how long | |
| What a repeat of the same key returns | |
| Provider's own idempotency support | |
| **Tested by submitting the same payment twice** | yes / no — result: |

🔴 The key must be generated by the **client**. A server-generated key is new on every request,
which defeats the mechanism entirely — and the code looks correct.

## 4. The ambiguous state — the section most often skipped

**When a request times out, how do we determine whether it happened?**

_______________

| | |
|---|---|
| Our own reference sent with every request | yes / no |
| Provider endpoint to query by our reference | |
| Timeout value | |
| Retry policy | |
| **Does a retry carry the idempotency key** | yes / no |
| Maximum time before a payment is resolved either way | |

A timeout is **not** a failure. It is an unknown, and treating it as a failure is how customers are
charged twice.

## 5. Failure behaviour the customer sees

| Condition | What the customer sees | What happens to the basket / order |
|---|---|---|
| Declined | | |
| Timeout | | |
| Provider unavailable | | |
| Our system unavailable mid-flow | | |
| Duplicate detected | | |

## 6. Data

| | |
|---|---|
| Card data touches our systems | yes / no |
| If yes, PCI DSS scope and justification | |
| Tokenisation used | |
| What we store | |
| Retention | |
| Personal data, lawful basis | |

Storing card data pulls a large and permanent compliance scope into your systems. If the answer to
the first row is yes, it needs an explicit reason.

## 7. Reconciliation

| | |
|---|---|
| Source of truth from the provider | |
| Frequency and cut-off | |
| Matched on which field | |
| **Where fees appear, and are they reconciled separately** | |
| Tolerance before a break is raised | |
| **Who investigates a break, within what time** | |
| Escalation if unresolved after | |

**Match on your own reference, not on amount.** Duplicates are invisible in totals and obvious when
grouped by order.

## 8. Operations

- [ ] Every provider call logged with our reference and their response
- [ ] Support can see payment status and history without engineering
- [ ] Support **cannot** move money
- [ ] Alert on: authorisation failure rate, timeout rate, reconciliation break age
- [ ] Runbook for "customer says they were charged twice"
- [ ] Provider status page monitored

## 9. Before go-live

- [ ] End-to-end test with real money, small amount, **including a refund**
- [ ] Reconciliation run on that test and balanced
- [ ] Duplicate submission tested — one authorisation resulted
- [ ] Timeout simulated and resolved correctly
- [ ] Ledger balanced after every test scenario
- [ ] Rollback plan that does not strand customer funds

## Sign-off

| | Name | Date |
|---|---|---|
| Engineering | | |
| Finance / ledger owner | | |
| Compliance | | |
| Approved for live traffic | | |
