Release candidate

v2.2-rc2 is not ratified and MUST NOT be used for production. Current: v2.1. Changelog

This is v2.2-rc2 — a release candidate for the v2.2 standards, published for review and not yet ratified. It MUST NOT be used as the basis for a production implementation. For the current standards, switch to v2.1 using the version selector. See the v2.1 → v2.2-rc2 changelog for every change in this version.

LFI · Banking · Service Initiation · Domestic Payments

Payment Timing 8 min read

This page defines the sequence and timing your LFI MUST follow for every domestic payment, from the API Hub’s call to your Ozone Connect POST/payments endpoint through to the terminal status recorded on the API Hub. It applies to Single Instant Payment and to every multi-payment type.

Three obligations are timed. Your LFI validates the request and returns 201. Within 3 seconds of that 201, it screens the payment, submits it to the rail, and PATCHes AcceptedSettlementCompleted to the API Hub. When the rail responds, it PATCHes the terminal status immediately. The TPP-facing view of the same timeline is in the TPP Standards Payment Timing page.

01 Timeline

The timeline at a glance

Sequence diagramDomestic payment timing — LFIClick to expand

The clock for the timed stages starts when your Ozone Connect returns the 201 to the API Hub. That moment is T0 in the table below.

#StageWhenWhat your LFI doesStatus on the API Hub
1Respond to POST /paymentsSynchronous, ending at T0Runs the synchronous validations, creates the payment record, and returns 201Pending
2Screen, submit, PATCHBy T0 + 3 sRoutes the payment, runs fraud screening, transaction monitoring and AML checks, submits the payment to the rail, and immediately PATCHes AcceptedSettlementCompletedAcceptedSettlementCompleted
3Rail responseImmediately on receipt of the rail’s responsePATCHes the terminal statusAcceptedWithoutPosting (AANI), AcceptedCreditSettlementCompleted (UAEFTS), or Rejected

A payment booked on your LFI’s own ledger, where the debtor and creditor accounts are both held at your LFI, has no rail and no hand-off to report. Stages 2 and 3 collapse into one: see Intra-bank payments.

02 Stage 1 · Synchronous

Responding to POST /payments

By the time the API Hub calls your Ozone Connect POST/payments, it has already validated the TPP’s access token, confirmed the consent is Authorized, checked the payment against the consent’s control parameters, and validated the request against the OpenAPI schema. Your LFI relies on the API Hub for those checks and does not repeat them.

Your LFI MUST then run the following checks before it creates the payment record. Each failure is returned synchronously, as an error response to the API Hub. No payment record is created and nothing is PATCHed.

CheckApplies toOn failure
Decrypt the payment PII (PersonalIdentifiableInformation)All400 JWE.DecryptionError
Validate the decrypted PII against the payment-time PII schemaAll400 Body.InvalidFormat
The creditor matches the creditor authorised on the consentAll400 Consent.FailsControlParameters
The debtor account has sufficient available fundsAll400 GenericError
The debtor account is not Inactive, Dormant, or SuspendedAll403 Consent.AccountTemporarilyBlocked
The debtor account is not Closed, Deceased, or UnclaimedAll403 Consent.PermanentAccountAccessFailure
x-fapi-customer-ip-address is present and a valid IP addressSingle Instant Payment, Delegated SCA400 Body.InvalidFormat
No identical payment is already Pending under the consentDelegated SCA, Fixed On Demand, Variable On Demand409 Payment.DuplicateInFlight

The authoritative rules, including the type-specific checks not listed here, are on each payment type’s Requirements page — for example Single Instant Payment — Payment Execution.

If every check passes, your LFI creates the payment record and returns 201 with the LFI-assigned id and status: Pending. The 201 means the payment record exists. It does not mean the payment has been screened or submitted. Returning it marks T0, and the 3-second window in the next stage starts.

03 Stage 2 · T0 to T0 + 3 s

Screen, submit to the rail, PATCH AcceptedSettlementCompleted

The 3-second rule

Within 3 seconds of returning the 201, your LFI MUST complete its fraud screening, transaction monitoring and AML checks, MUST submit the payment to the rail, and MUST immediately call PATCH/payment-log/{id} with paymentResponse.status: AcceptedSettlementCompleted.

Within the window, your LFI works through four steps in order:

#StepWhat your LFI does
1RouteSelect the rail. Settle over UAEFTS when UseFTS is true; otherwise submit to AANI, falling back to UAEFTS where your routing rules require it. Assign the payment’s paymentTransactionId. On AANI this is the pacs.008 TxId your LFI assigns, and it MUST start with OFP. On UAEFTS it is the payment’s UAEFTS transaction identifier. Every PATCH on AANI and UAEFTS carries both paymentRail and paymentTransactionId, so routing comes first.
2ScreenRun your fraud screening, transaction monitoring and AML checks on the payment.
3SubmitSubmit the payment to the rail (pacs.008 to AANI or UAEFTS).
4PATCHImmediately on submission, PATCH AcceptedSettlementCompleted with paymentRail and paymentTransactionId. Do not wait for any response from the rail — not the AANI pacs.002, and not the UAEFTS ACK.

The AcceptedSettlementCompleted PATCH is mandatory on AANI and UAEFTS. It is how the API Hub, and through it the TPP, learns that the payment has cleared your LFI’s checks and been handed to the rail. It is not terminal: a second PATCH always follows in Stage 3.

Example PATCH bodies

handed to AANIjson
{
  "paymentResponse.paymentRail": "AANI",
  "paymentResponse.status": "AcceptedSettlementCompleted",
  "paymentResponse.paymentTransactionId": "OFP7d2c1e9a4b6f4c0e8a1b"
}
handed to UAEFTSjson
{
  "paymentResponse.paymentRail": "FTS",
  "paymentResponse.status": "AcceptedSettlementCompleted",
  "paymentResponse.paymentTransactionId": "<UAEFTS end-to-end transaction identifier>"
}
booked on the LFI's own ledgerjson
{
  "paymentResponse.paymentRail": "LFI",
  "paymentResponse.status": "AcceptedCreditSettlementCompleted"
}

Intra-bank payments

Where the debtor and creditor accounts are both held at your LFI, the payment is booked on your own ledger and never reaches a rail. The same 3-second window applies. Within 3 seconds of returning the 201, your LFI MUST complete its screening, book the payment, and immediately PATCH AcceptedCreditSettlementCompleted with paymentRail: LFI. That status is terminal, so no second PATCH follows. paymentTransactionId is not sent on LFI.

04 Stage 3 · On the rail's response

PATCH the terminal status immediately

How long AANI or UAEFTS takes to respond is set by that rail’s own scheme rules, not by the Open Finance standards. The payment stays at AcceptedSettlementCompleted until the rail responds. Your LFI MUST then PATCH the terminal status immediately on receiving the response:

RailRail responsePATCH paymentResponse.statusNotes
AANIPositive Account Verification Response (pacs.002 accepted)AcceptedWithoutPostingTerminal
AANIpacs.002 rejectionRejectedTerminal. rejectReasonCode[].code in the AANI. namespace
UAEFTSACK—Technical acceptance only. No PATCH; the status remains AcceptedSettlementCompleted
UAEFTSCB900 Debit ConfirmationAcceptedCreditSettlementCompletedTerminal
UAEFTSNAKRejectedTerminal. rejectReasonCode[].code in the FTS. namespace

Every terminal PATCH on AANI and UAEFTS carries the same paymentRail and paymentTransactionId as the AcceptedSettlementCompleted PATCH before it. A Rejected PATCH also carries rejectReasonCode, whose message MUST be sanitised for relay to the TPP. The per-rail mapping is in Payment Status.

Example PATCH bodies

AANI acceptedjson
{
  "paymentResponse.paymentRail": "AANI",
  "paymentResponse.status": "AcceptedWithoutPosting",
  "paymentResponse.paymentTransactionId": "OFP7d2c1e9a4b6f4c0e8a1b"
}
AANI rejectedjson
{
  "paymentResponse.paymentRail": "AANI",
  "paymentResponse.status": "Rejected",
  "paymentResponse.paymentTransactionId": "OFP7d2c1e9a4b6f4c0e8a1b",
  "paymentResponse.rejectReasonCode": [
    {
      "code": "AANI.AM04",
      "message": "Payment request cannot be executed as insufficient funds at debtor account."
    }
  ]
}
05 Delivery

What “immediately” requires

Both PATCHes are sent as soon as the triggering event occurs: submission to the rail for the first, and receipt of the rail’s response for the second. In particular, your LFI MUST NOT:

  • batch status updates across payments, or hold them for a scheduled job;
  • defer a PATCH until the TPP polls GET/payments/{paymentId};
  • skip the AcceptedSettlementCompleted PATCH because the rail has already responded — send it first, then the terminal status;
  • send any further status once a terminal status has been PATCHed.

PATCH delivery is durable. Retry a transient failure (5xx, connection error, or timeout) with exponential backoff until it is accepted. Do not retry a 4xx; raise it for operational investigation. Your Ozone Connect GET/payments/{paymentId} MUST return the status most recently PATCHed, so the push and pull views of the payment stay consistent.

06 Summary

PATCH obligations by rail

paymentRailBy T0 + 3 sImmediately on the rail’s response
AANISubmit, then PATCH AcceptedSettlementCompletedPATCH AcceptedWithoutPosting or Rejected
FTSSubmit, then PATCH AcceptedSettlementCompletedPATCH AcceptedCreditSettlementCompleted or Rejected (no PATCH on ACK)
LFIBook, then PATCH AcceptedCreditSettlementCompleted— (no rail)

The field-level contract for each PATCH is in the PATCH /payment-log/{id} API reference. This requirement is recorded in the v2.2 changelog §17.