INTRODUCTION: THE NEED FOR PAYMENT FINALITY
In Lessons 6.1 through 6.6, we built the complete payment initiation engine—consents, SCA, CBPII, VRP sweeps, idempotent submission, and settlement reporting. The PSU clicks “Pay”, the TPP submits the payment, the ASPSP processes it, the clearing house settles it, and the final camt.054 report confirms the status. But what happens between submission and settlement? The PSU is waiting for confirmation. The TPP’s UI shows a spinner. The PSU wonders: “Has my money been sent? Is it stuck?”
The PSU requires real-time payment status. The OBIE v4.0 mandates the GET /payments/{PaymentId} endpoint, which allows the TPP to query the current status of a payment. The TPP can poll this endpoint to provide a live status update to the PSU. However, polling is inefficient (as we learned in Module 5). The ASPSP also provides asynchronous webhooks (as part of the payment initiation API) that notify the TPP when the payment status changes.
This lesson deconstructs the payment status query and notification pipeline. We design the GET /payments/{PaymentId} endpoint, which retrieves the payment status from a low‑latency Redis cache (TTL: 60 seconds). We formalise the payment status state machine (a superset of the earlier statuses, including Initiated, Authorised, Submitted, Accepted, Settling, Settled, Rejected, and Cancelled). We map the ISO 20022 status codes (ACSC, RJCT, ACWP for reversal) to the OBIE statuses. We also design the payment reversal pipeline—the rare but critical flow where a settled payment must be reversed due to fraud or error.
We will quantify the latency budget for the status query (Redis lookup: < 2ms) and the webhook notification (80ms). We will mathematically model the probability of a payment requiring a reversal (< 0.01%) using historical fraud data. We will also design the reversal consent—the separate consent required by the PSU to authorise a reversal, which must be initiated within 30 seconds of the original payment (per EBA guidelines on SCA exemptions for reversals).
LEARNING OBJECTIVES
-
Design the Payment Status Query Endpoint—implementing
GET /payments/{PaymentId}with a Redis cache layer (TTL: 60 seconds) that stores the payment status, PaymentId, and metadata, returning a200 OKwith the OBIEPaymentResponseschema, and proving that the query latency is under 2ms (p95). -
Formalize the Payment Status State Machine—defining the 8 statuses:
Initiated(PSU clicks “Pay”),Authorised(consent granted),Submitted(payment sent),Accepted(ASPSP validated),Settling(in clearing),Settled(final),Rejected(failed), andCancelled(PSU cancelled), and mapping each to the ISO 20022camt.054statuses. -
Design the Webhook Notification Pipeline—implementing the
notify_payment_statusfunction that sends an HTTP POST to the TPP’s webhook URL when the payment status changes, with HMAC‑SHA256 signature and a 5‑minute retry window (as defined in Lesson 5.5). -
Analyze the Payment Reversal Flow—designing the
POST /payments/{PaymentId}/reversalendpoint, which requires a new consent (the PSU must explicitly authorise the reversal), and mapping the reversal to the ISO 20022camt.054ReversalIndicator. -
Quantify the Probability of Reversal—deriving the formula
P(Reversal) = P(Fraud_Detection) + P(Processing_Error)and proving that the probability is < 0.01% (1 in 10,000 payments), based on industry data for APP fraud and ASPSP processing errors. -
Calculate the End‑to‑End Status Notification Latency—summing the time from payment settlement (50ms) to webhook delivery (80ms) to TPP UI update (50ms), and proving that the total p95 latency is under 200ms, making the status update near‑real‑time.
PART 1: THE PAYMENT STATUS QUERY ENDPOINT — Fetching the Current State
The TPP needs to fetch the payment status for a given PaymentId. The endpoint is GET /payments/{PaymentId}.
1.1 The OBIE v4.0 Payment Response Schema
Response (200 OK) :
{ "Data": { "PaymentId": "pay-456", "ConsentId": "pc-abc-123", "Status": "AcceptedSettlementInProcess", "CreationDateTime": "2026-08-03T14:30:00Z", "StatusUpdateDateTime": "2026-08-03T14:30:05Z", "Amount": "100.00", "Currency": "GBP", "Reference": "INV-001" }, "Links": { "self": "/payments/pay-456" } }
Mandatory Fields:
-
PaymentId: The unique identifier. -
ConsentId: The consent that authorised the payment. -
Status: The current OBIE status. -
CreationDateTime: When the payment was submitted. -
StatusUpdateDateTime: When the status was last updated.
1.2 The Redis Cache Layer
The payment status is stored in a primary database (PostgreSQL), but querying the database for every status poll is inefficient. We use a Redis cache with a TTL of 60 seconds.
Cache Key: payment:status:{PaymentId}
Cache Value: JSON containing { "status": "AcceptedSettlementInProcess", "updated_at": "..." }
Write‑Through Strategy: When the payment status is updated (e.g., from AcceptedSettlementInProcess to AcceptedSettlementCompleted), the ASPSP updates the database and the Redis cache simultaneously (write‑through).
Latency:
-
Cache Hit: Redis
GETtakes 1.2ms (p95). -
Cache Miss: Database query takes 5ms (p95), and the result is then cached.
The Query Algorithm:
def get_payment_status(payment_id): # 1. Try Redis cache cached = redis_client.get(f"payment:status:{payment_id}") if cached: return json.loads(cached) # 2. Fallback to database payment = db.get_payment(payment_id) if not payment: return None, "Payment not found" # 3. Cache for future requests (60 seconds) cache_data = {"status": payment.status, "updated_at": payment.updated_at.isoformat()} redis_client.setex(f"payment:status:{payment_id}", 60, json.dumps(cache_data)) return cache_data
PART 2: THE PAYMENT STATUS STATE MACHINE — A Complete Lifecycle
The payment status transitions through 8 states. This is a superset of the OBIE statuses, including internal states for the TPP.
| State | OBIE Status | ISO 20022 camt.054 |
Description | Transition |
|---|---|---|---|---|
| 1. Initiated | N/A | N/A | PSU clicks “Pay”. Payment record created in TPP’s internal DB. | → Authorised |
| 2. Authorised | N/A | N/A | Consent granted (SCA completed). Payment ready to submit. | → Submitted |
| 3. Submitted | AcceptedSettlementInProcess |
N/A | Payment submitted to ASPSP (POST /payments). |
→ Accepted or Rejected |
| 4. Accepted | AcceptedSettlementInProcess |
ACSP |
ASPSP validates payment (balance, fraud). Sent to clearing. | → Settling or Rejected |
| 5. Settling | AcceptedSettlementInProcess |
ACSP |
Clearing house processes the payment. | → Settled or Rejected |
| 6. Settled | AcceptedSettlementCompleted |
ACSC |
Clearing house settles the payment. Final state. | N/A |
| 7. Rejected | Rejected |
RJCT |
Payment failed (insufficient funds, fraud, etc.). Final state. | N/A |
| 8. Cancelled | Cancelled |
N/A | PSU cancels the payment before submission. Final state. | N/A |
The ISO 20022 Mapping:
-
camt.054TxSts = ACSC→ OBIEAcceptedSettlementCompleted. -
TxSts = RJCT→ OBIERejected. -
TxSts = ACSP→ OBIEAcceptedSettlementInProcess.
PART 3: THE WEBHOOK NOTIFICATION PIPELINE — Real‑Time Status Updates
When the payment status changes, the ASPSP must notify the TPP. The webhook endpoint was registered during the payment consent creation (Lesson 6.1).
3.1 The Notification Payload
HTTP POST to https://tpp.com/webhook/payments:
{ "eventType": "payment.status.updated", "eventId": "evt-123-abc", "timestamp": "2026-08-03T14:30:05Z", "paymentId": "pay-456", "consentId": "pc-abc-123", "status": "AcceptedSettlementCompleted", "statusUpdateDateTime": "2026-08-03T14:30:05Z", "amount": "100.00", "currency": "GBP" }
Headers:
x-webhook-timestamp: 1691234567 x-webhook-signature: sha256=hmac_signature_hex
3.2 The Retry Policy
If the TPP’s webhook endpoint returns a 5xx error or times out (3 seconds), the ASPSP retries with exponential backoff:
-
Attempt 1: 1s
-
Attempt 2: 2s
-
Attempt 3: 4s
-
Attempt 4: 8s
-
Attempt 5: 16s
-
Attempt 6: 32s
-
Attempt 7: 64s
-
Attempt 8: 128s
-
Attempt 9: 256s
-
Attempt 10: 512s
Max Retry Window: 30 minutes.
Latency:
-
First Attempt: 50ms (network) + 30ms (TPP processing) = 80ms (p95).
-
Retry (if needed): Adds up to 30 minutes, but only occurs in < 0.1% of cases.
PART 4: PAYMENT REVERSAL MANAGEMENT — The Correction Flow
A payment reversal is a rare but critical flow. It occurs when:
-
Fraud Detection: The ASPSP detects fraud after the payment was settled.
-
Processing Error: The ASPSP made an error (e.g., credited the wrong account).
-
PSU Dispute: The PSU claims the payment was unauthorised.
4.1 The Reversal Consent
Under EBA guidelines, a reversal requires explicit consent from the PSU. The TPP cannot initiate a reversal without the PSU’s authorisation.
The Reversal Flow:
-
Detection: ASPSP detects fraud or receives a dispute from the PSU.
-
Notification: ASPSP notifies the TPP (webhook) that a reversal is required.
-
PSU Authorisation: The TPP redirects the PSU to the ASPSP’s reversal consent page. The PSU authenticates (SCA) and authorises the reversal.
-
Submission: The TPP submits
POST /payments/{PaymentId}/reversalwith the reversal consent ID. -
Processing: The ASPSP processes the reversal (sends a
camt.054withReversalIndicator = true). -
Settlement: The funds are reversed to the PSU’s account.
The Reversal Endpoint:
POST /payments/{PaymentId}/reversal request:
{ "Data": { "ReversalId": null, "ConsentId": "rev-consent-123", "Reason": "Fraud detection", "Amount": "100.00", "Currency": "GBP" } }
Response (201 Created):
{ "Data": { "ReversalId": "rev-456", "PaymentId": "pay-456", "Status": "Accepted" } }
4.2 The Probability of Reversal
We derive the probability of a payment requiring a reversal:
Let P(Fraud) be the probability of APP fraud (0.001, as in Lesson 6.2). Let P(Error) be the probability of a processing error (0.0001).
P(Reversal) = P(Fraud) × P(Detection_After_Settlement) + P(Error)
Assuming Detection_After_Settlement = 0.01 (1% of frauds are detected after settlement):P(Reversal) = 0.001 × 0.01 + 0.0001 = 0.00001 + 0.0001 = 0.00011 = 0.011%.
Conclusion: Reversals occur in approximately 1 in 10,000 payments.
PART 5: LATENCY BUDGET FOR STATUS QUERY AND NOTIFICATION
| Component | Operation | Latency (p95) |
|---|---|---|
| Status Query | Redis GET | 1.2ms |
| Status Query | Database fallback | 5ms |
| Status Update | DB write + cache invalidation | 8ms |
| Webhook Notification | HTTP POST to TPP | 80ms |
| TPP UI Update | Frontend render | 50ms |
| Total (Status Query) | 1.2ms (cache hit) / 5ms (miss) | |
| Total (Status Update to UI) | 80ms + 50ms = 130ms |
CLOSING — THE FINALITY OF FUNDS
The payment status query and notification pipeline ensures that the PSU receives near‑real‑time updates on their payment’s progress. The Redis cache reduces query latency to under 2ms. The webhook pipeline delivers status changes in under 130ms. The reversal pipeline handles the rare (0.011%) cases where a payment must be corrected.
Operational Risk: If the Redis cache is stale (TTL: 60 seconds), the PSU might see a slightly outdated status. However, the actual payment status is only updated at settlement (≤ 6s), so a 60s TTL is acceptable.
Transition to Lesson 6.8: With the payment status and reversal pipelines complete, we now synthesise the entire Module 6 into a capstone framework. Lesson 6.8—Module 6 Capstone: The Unified Payment Initiation Framework—brings together the consent flow, SCA, CBPII, VRP, idempotency, settlement reporting, and reversal management into a single, auditable architecture. We will present the complete regulatory evidence bundle, the end‑to‑end latency budget across all stages, and the final mapping to PSD2 and CMA requirements.