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 InitiatedAuthorisedSubmittedAcceptedSettlingSettledRejected, and Cancelled). We map the ISO 20022 status codes (ACSCRJCTACWP 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

  1. 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 a 200 OK with the OBIE PaymentResponse schema, and proving that the query latency is under 2ms (p95).

  2. 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), and Cancelled (PSU cancelled), and mapping each to the ISO 20022 camt.054 statuses.

  3. Design the Webhook Notification Pipeline—implementing the notify_payment_status function 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).

  4. Analyze the Payment Reversal Flow—designing the POST /payments/{PaymentId}/reversal endpoint, which requires a new consent (the PSU must explicitly authorise the reversal), and mapping the reversal to the ISO 20022 camt.054 ReversalIndicator.

  5. 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.

  6. 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) :

json
{
  "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 Keypayment: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 GET takes 1.2ms (p95).

  • Cache Miss: Database query takes 5ms (p95), and the result is then cached.

The Query Algorithm:

python
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.054 TxSts = ACSC → OBIE AcceptedSettlementCompleted.

  • TxSts = RJCT → OBIE Rejected.

  • TxSts = ACSP → OBIE AcceptedSettlementInProcess.


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:

json
{
  "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:

text
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:

  1. Detection: ASPSP detects fraud or receives a dispute from the PSU.

  2. Notification: ASPSP notifies the TPP (webhook) that a reversal is required.

  3. PSU Authorisation: The TPP redirects the PSU to the ASPSP’s reversal consent page. The PSU authenticates (SCA) and authorises the reversal.

  4. Submission: The TPP submits POST /payments/{PaymentId}/reversal with the reversal consent ID.

  5. Processing: The ASPSP processes the reversal (sends a camt.054 with ReversalIndicator = true).

  6. Settlement: The funds are reversed to the PSU’s account.

The Reversal Endpoint:

POST /payments/{PaymentId}/reversal request:

json
{
  "Data": {
    "ReversalId": null,
    "ConsentId": "rev-consent-123",
    "Reason": "Fraud detection",
    "Amount": "100.00",
    "Currency": "GBP"
  }
}

Response (201 Created):

json
{
  "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.