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 Status 8 min read

Every domestic payment initiated through the API Hub is executed in one of three modes: intra-bank (both debtor and creditor accounts are held at your LFI, so no rail is used), or one of the two domestic payment rails — AANI (the UAE's instant payment rail) and UAEFTS (the UAE Funds Transfer System). Your LFI is the only party that sees the raw execution outcome, so your LFI MUST map that outcome to an Open Finance payment status and propagate it to the Hub via the Consent Manager Payment Log.

This page covers both concerns: how your LFI selects an execution mode, and how outcomes from each mode map to Open Finance statuses. For the consent lifecycle, see the Consent Manager section.

01 Payment Statuses

Open Finance payment statuses

The Open Finance payment status enum is defined in the Ozone Connect Bank Service Initiation OpenAPI and aligns with ISO 20022 ExternalPaymentTransactionStatus1Code. Six values are in scope:

Open Finance statusISO 20022Meaning
PendingPDNGPayment accepted for processing; further checks or rail submission outstanding
AcceptedSettlementCompletedACSCYour LFI has submitted the payment to AANI or UAEFTS and is awaiting the rail’s response — not terminal
AcceptedWithoutPostingACWPThe receiving bank has accepted the payment but your LFI cannot confirm the creditor account has been credited — a settlement state
AcceptedCreditSettlementCompletedACCCThe creditor account has been credited with the funds of the payment
RejectedRJCTThe payment was rejected, either by your LFI before submission or by AANI / UAEFTS

Pending is the initial status your Ozone Connect POST/payments response returns — your LFI does not PATCH a payment to Pending. On AANI and UAEFTS your LFI PATCHes twice: AcceptedSettlementCompleted immediately on submitting the payment to the rail, within 3 seconds of returning the 201, and then the terminal status — AcceptedWithoutPosting, AcceptedCreditSettlementCompleted, or Rejected — immediately on the rail’s response. Both PATCHes are mandatory. For an intra-bank payment there is no hand-off, and your LFI PATCHes the terminal status once. The sequence and timing are set out in Payment Timing.

Received status

The Open Finance enum also includes a sixth value, Received (ISO 20022 RCVD), used only for bulk and batch payments where the Hub acknowledges receipt of a file of instructions before processing individual payments. Bulk and batch payments are not yet documented in v2.2 — for the domestic single and multi-payments covered by this page, you can ignore Received.

Once a payment reaches a terminal status (AcceptedWithoutPosting, AcceptedCreditSettlementCompleted, or Rejected), your LFI MUST NOT transition it to a different value.

02 Rail Selection

Rail selection

Your LFI is responsible for choosing the execution mode for every domestic payment. The API Hub does not select a rail on your behalf, and the TPP and customer are not involved in the decision. Apply the following logic on receipt of POST/payments:

  • Intra-bank — if both the debtor and creditor accounts are held at your LFI, execute the payment internally. No rail is used, and your LFI has end-to-end visibility of both legs.
  • AANI — otherwise, submit the payment to AANI as the primary rail whenever the receiving bank and receiving account are reachable on AANI.
  • UAEFTS — if AANI is unavailable or the receiving bank cannot receive via AANI, fall back to UAEFTS. The fall-back is automatic and MUST NOT require TPP or customer intervention.

Your LFI MUST only reject a payment for reachability reasons once both rails have been ruled out — that is, when the receiving bank is reachable on neither AANI nor UAEFTS. As with any rejection raised before submission, it is reported against the rail the payment was routed to and carries that rail’s namespace — see Rejection code prefixes.

Routing comes first in the post-201 sequence. Every PATCH on AANI and UAEFTS carries paymentRail and paymentTransactionId, so your LFI selects the rail and assigns the identifier before it screens the payment. Screening and submission then complete within 3 seconds of the 201 — see Payment Timing.

03 Intra-bank

Intra-bank payments

When the debtor account and creditor account are both held at your LFI, there is no interbank rail involved — the payment is executed by an internal debit-and-credit within your core banking system. Your LFI has full visibility of both legs, so the payment can reach the most specific Open Finance terminal status: AcceptedCreditSettlementCompleted.

The events that trigger a PATCH are:

Intra-bank outcomeNew Open Finance statusNotes
Debtor debit and creditor credit both postedAcceptedCreditSettlementCompletedTerminal for intra-bank — your LFI knows the funds have definitely landed in the creditor account
Internal rejection (screening, insufficient funds, account state, etc.)RejectedSet rejectReasonCode[].code to LFI.<reasonCode> — the only namespace accepted with paymentRail: LFI

Every PATCH for an intra-bank payment carries paymentRail: LFI. There is no hand-off to a rail, so AcceptedSettlementCompleted does not apply. Within 3 seconds of returning the 201, your LFI MUST complete its screening, book the payment, and immediately PATCH AcceptedCreditSettlementCompleted. Intra-bank payments have no paymentTransactionId, and the field is not accepted on LFI, so omit it.

04 AANI

AANI status mapping

Sequence diagramAANI status mappingClick to expand

AANI is the UAE's instant payment rail. An AANI payment either clears to terminal success within seconds and returns a positive Account Verification Response (an ISO 20022 pacs.002 message with an accepted status), or is rejected by the receiving bank with an AANI Reject Reason Code drawn from the AANI Core Service Interface Specification.

Immediately on submitting the payment to AANI — within 3 seconds of returning the 201 — your LFI MUST PATCH AcceptedSettlementCompleted. It does not wait for the AANI response. The payment then remains at AcceptedSettlementCompleted until AANI responds, and your LFI MUST PATCH the terminal status immediately when it does. The events that trigger a PATCH are:

EventNew Open Finance statusNotes
Payment submitted to AANI (pacs.008 sent)AcceptedSettlementCompletedMandatory. Not terminal
Positive Account Verification Response (pacs.002 accepted)AcceptedWithoutPostingTerminal for AANI
pacs.002 rejectionRejectedTerminal. Set rejectReasonCode[].code to AANI.<reasonCode> (for example AANI.AM04)
Warning

AcceptedWithoutPosting is the terminal status for successful AANI payments. Your LFI MUST NOT infer AcceptedCreditSettlementCompleted from an AANI Account Verification Response — AANI does not confirm credit posting at the receiving bank to the originating LFI.

Include paymentTransactionId on every PATCH/payment-log/{id}, including the first. On AANI it is the pacs.008 TxId your LFI assigned to the payment, not an identifier issued by AANI, and it MUST start with OFP. Once set, paymentTransactionId MUST NOT change.

Illustrative AANI Reject Reason Codes

The full list of 40 codes is maintained in the AANI Core Service Interface Specification. The codes you will see most often are:

AANI codeMeaning
AC06Blocked Account
AC07Closed Creditor Account Number
AM04Insufficient Funds
AM14Amount Exceeds Agreed Limit
UCRDUnknown Creditor

Your LFI MUST relay the code in the AANI. namespace — AANI.AM04 — without transposing it to a different namespace. A PATCH with paymentRail: AANI accepts only codes matching ^AANI\.[A-Za-z0-9]+$.

05 UAEFTS

UAEFTS status mapping

Sequence diagramUAEFTS status mappingClick to expand

UAEFTS is the UAE Funds Transfer System, the Central Bank of the UAE's domestic interbank funds transfer rail. UAEFTS carries payment messages using the ISO 20022 pacs.008 schema and returns the following acknowledgements:

  • ACK — UAEFTS has accepted the message after technical validation
  • NAK — UAEFTS has rejected the message with an FTS reason code
  • CB900 — Debit Confirmation: settlement through the Central Bank has completed, the debtor account has been debited, and the corresponding credit to the receiving bank has been settled

Because UAEFTS settles through the Central Bank as a centralised interbank clearing, a CB900 implicitly confirms that the creditor side of the payment has been settled as well. The terminal successful status for a UAEFTS payment is therefore AcceptedCreditSettlementCompleted.

Immediately on submitting the payment to UAEFTS — within 3 seconds of returning the 201 — your LFI MUST PATCH AcceptedSettlementCompleted, carrying the payment’s UAEFTS transaction identifier as paymentTransactionId. ACK is technical acceptance only: it does not trigger a PATCH, and the payment remains at AcceptedSettlementCompleted until CB900 or NAK arrives. Your LFI MUST then PATCH the terminal status immediately. The events that trigger a PATCH are:

EventNew Open Finance statusNotes
Payment submitted to UAEFTS (pacs.008 sent)AcceptedSettlementCompletedMandatory. Not terminal
CB900 Debit ConfirmationAcceptedCreditSettlementCompletedTerminal for UAEFTS
NAK receivedRejectedTerminal. Set rejectReasonCode[].code to FTS.<reasonCode>
06 Reject Codes

Rejection code prefixes

Every Rejected PATCH carries a rejectReasonCode[] array. The first segment of each code is a namespace, and from v2.2 the namespace follows the paymentRail named on the PATCH — not the system in which the check failed:

paymentRailCoverscode patternExample
AANIA payment routed to AANI, whether AANI rejected it or your LFI rejected it before submission (screening, for example)^AANI\.[A-Za-z0-9]+$AANI.AC06
FTSA payment routed to UAEFTS, whether UAEFTS rejected it or your LFI rejected it before submission^FTS\.[A-Za-z0-9]+$FTS.AC06
LFIA payment booked on your LFI’s own ledger — every rejection is your LFI’s own^LFI\.[A-Za-z0-9]+$LFI.InsufficientFunds
Danger

A code from any other namespace does not validate against the PATCH body for the rail named. In particular, a rejection your LFI raises before submitting a payment routed to AANI or UAEFTS MUST carry the AANI. or FTS. prefix, not LFI.. The prefix is relayed to the TPP verbatim and is critical for TPP diagnostics and downstream reconciliation.

On AANI and FTS, a Rejected PATCH also carries paymentTransactionId, as every PATCH on those rails does.

07 Propagation

Propagating status to the Hub

The initial Pending status is set by the 201 response your Ozone Connect POST/payments endpoint returns — no PATCH is required at that point.

What your LFI MUST PATCH

paymentRailOn submission to the rail (within 3 s of the 201)On the rail’s response
AANIAcceptedSettlementCompletedAcceptedWithoutPosting or Rejected
FTSAcceptedSettlementCompletedAcceptedCreditSettlementCompleted or Rejected
LFIAcceptedCreditSettlementCompleted on booking, within 3 s of the 201 — terminal, no rail

Every PATCH in this table is mandatory. Your LFI MUST NOT PATCH any status other than those listed for the rail, and MUST NOT PATCH anything after a terminal status. The full sequence, including what happens between the 201 and submission, is in Payment Timing.

How to PATCH

On each PATCH-triggering event, your LFI MUST immediately:

  • Map the outcome to the new Open Finance status.
  • Call PATCH/payment-log/{id} on the API Hub Consent Manager with paymentResponse.paymentRail, the new paymentResponse.status, paymentResponse.paymentTransactionId (on AANI and FTS), and, for Rejected only, paymentResponse.rejectReasonCode.
  • Update the response your Ozone Connect GET/payments/{paymentId} endpoint returns so that push and pull views of the payment are consistent.

Your LFI MUST NOT batch status updates or defer them waiting for TPP polling. The Hub relays the new status to the TPP via webhook events as soon as it receives the PATCH.

Example PATCH bodies

PATCH /payment-log/{id} — submitted to AANIjson
{
  "paymentResponse.paymentRail": "AANI",
  "paymentResponse.status": "AcceptedSettlementCompleted",
  "paymentResponse.paymentTransactionId": "OFP7d2c1e9a4b6f4c0e8a1b"
}
PATCH /payment-log/{id} — AANI acceptedjson
{
  "paymentResponse.paymentRail": "AANI",
  "paymentResponse.status": "AcceptedWithoutPosting",
  "paymentResponse.paymentTransactionId": "OFP7d2c1e9a4b6f4c0e8a1b"
}
PATCH /payment-log/{id} — 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."
    }
  ]
}