Payment Provider Integration Specification
A fill-in specification for connecting a payment provider — idempotency, the ambiguous timeout state, ledger entries per event, reconciliation source, refunds and chargebacks, and the failure behaviour customers see.
Markdown. No sign-up, no email.
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 |