Bank Data Sharing — Requirements v2.112 min read
The Authentication requirements, Authorization requirements, and User Journeys must be adhered to.
The tables below list the rules that apply to Bank Data Sharing. All request validation of the TPP's credentials, access token, and consent is performed by the Hub before your Ozone Connect endpoints are called. The rules below cover what your Ozone Connect endpoints must validate and what they must return. Two cross-cutting checks apply to every endpoint under /accounts/{accountId} and /accounts/{accountId}/…: Account Access Validation (the account is held by the resolved customer) and Account Status Handling (the account is in a readable state).
Consent Validation
When a TPP creates a consent, the API Hub calls your POST /consent/action/validate endpoint before the consent is created. You MUST validate the consent and respond with status: "valid" or status: "invalid". If you respond with invalid, the API Hub will not create the consent and the TPP will receive an error. This validation runs before the customer is involved — there is no authentication or authorization at this stage. The purpose is to reject consents early that your systems cannot fulfil. The field names in the rules below match the Ozone Connect newConsent payload the Hub delivers — standardVersion sits at the top level of the consent object; BaseConsentId, AccountType, AccountSubType, and Permissions sit under consentBody.Data.
standardVersionstandardVersion (a top-level property on the consent object) is the URL path version the TPP will call on subsequent data sharing requests. If you do not support that version for the Account Information API family, respond with invalid.Where you are dual-running multiple versions during a deprecation window (see Major Version Deprecation) — for example
v2.0 alongside v3.1 — you MUST respond valid for every version you serve.Minor versions are backward compatible (see Version Management), so prior minors within each major you run are also valid (e.g. running
v2.0 and v3.1 means v2.0, v3.0, and v3.1 all resolve to valid).AccountTypeAccountType array contains a value that is not supported by the API Hub integration the consent was received on, respond with invalid. Each API Hub integration is scoped to a single segment (Retail, SME, or Corporate). If the LFI serves multiple segments, each segment MUST be configured as a separate API Hub integration because the API Hub has a single authorization endpoint. Validate that every requested AccountType is within scope of the integration that received the consent.AccountSubTypeAccountSubType array contains a value not supported by this LFI, respond with invalid. For example, if the LFI does not offer Mortgage products but the consent requests Mortgage, the consent MUST be rejected at validation.invalid. For example, if the consent includes ReadStandingOrdersBasic or ReadStandingOrdersDetail but GET /accounts/{AccountId}/standing-orders is not yet available, the consent MUST be rejected at validation.BaseConsentIdBaseConsentId, validate that:- The
BaseConsentIdreferences an existing consent known to the LFI. - The referenced consent is a Data Sharing consent (
authorization_details[0].typeisurn:openfinanceuae:account-access-consent:*). - The referenced consent does not itself have a
BaseConsentId— if it does, the TPP has incorrectly linked to an intermediate consent in the chain rather than the root consent. TheBaseConsentIdmust always reference the original root consent.
invalid.List Accounts
/accountsaccountIdsid matches one of the values in the accountIds query parameter. Populate the Status field on each account so the TPP can see the current state.accountHolderName, status, currency, accountType, and accountSubType where held.accountNumbersschemeName and identification are required on each entry.accountNumbers.schemeNameIBAN for CurrentAccount and Savings; MaskedPAN for CreditCard; MortgageReference for Mortgage; FinanceReference for Finance.customerscustomers must contain at least one entry. For business accounts, populate businessCustomer instead.AccountSubTypeCurrentAccount, Savings, CreditCard, Finance, and Mortgage.accountId in the accountIds query parameter, validate that the account is held by the customer resolved from o3-psu-identifier. Apply the Account Access Validation check before returning — if any of the requested accounts is not held by the customer, return 403 with errorCode: Consent.PermanentAccountAccessFailure.Status. Accounts that are Inactive, Dormant, Suspended, Unclaimed, Deceased, or Closed MUST still be included — the Status field on each account reflects the current state so the TPP can observe it. This endpoint is exempt from the Account Status Handling mapping.Get Account
/accounts/{accountId}accountid matches the value in the accountId path parameter.GET /accounts for the same account. All fields marked as required in the OpenAPI spec must be present.accountNumbersschemeName and identification are required on each entry.accountNumbers.schemeNameIBAN for CurrentAccount and Savings; MaskedPAN for CreditCard; MortgageReference for Mortgage; FinanceReference for Finance.AccountSubTypeCurrentAccount, Savings, CreditCard, Finance, and Mortgage.accountId path parameter is held by the customer resolved from o3-psu-identifier. Apply the Account Access Validation check before status handling — a non-held account MUST return 403 with errorCode: Consent.PermanentAccountAccessFailure.Active, do not return the resource. Apply the Account Status Handling mapping to return 403 with the corresponding errorCode and errorMessage.List Balances
/accounts/{accountId}/balancesaccountid matches the value in the accountId path parameter.accountId, balanceType, amount (with amount and currency), creditDebitIndicator, and timestamp.creditLines where applicable.InterimAvailableCurrentAccount and Savings accounts, a record with balanceType: InterimAvailable must always be included. This is the real-time available balance on the account.AccountSubTypeCurrentAccount, Savings, CreditCard, Finance, and Mortgage.accountId path parameter is held by the customer resolved from o3-psu-identifier. Apply the Account Access Validation check before status handling — a non-held account MUST return 403 with errorCode: Consent.PermanentAccountAccessFailure.Active, do not return the resource. Apply the Account Status Handling mapping to return 403 with the corresponding errorCode and errorMessage.List Beneficiaries
/accounts/{accountId}/beneficiariesaccountid matches the value in the accountId path parameter.accountId, beneficiaryId, beneficiaryType, and addedViaOF.creditorAccount (with schemeName and identification), servicer, and reference where held.200 with an empty data array. Do not return 404.AccountSubTypeCurrentAccount and Savings accounts. Not available for CreditCard, Finance, or Mortgage accounts.accountId path parameter is held by the customer resolved from o3-psu-identifier. Apply the Account Access Validation check before status handling — a non-held account MUST return 403 with errorCode: Consent.PermanentAccountAccessFailure.Active, do not return the resource. Apply the Account Status Handling mapping to return 403 with the corresponding errorCode and errorMessage.List Direct Debits
/accounts/{accountId}/direct-debitsaccountid matches the value in the accountId path parameter.accountId, directDebitId, directDebitStatusCode, mandateIdentification, name, and frequency.previousPaymentDateTime and previousPaymentAmount where available.200 with an empty data array. Do not return 404.AccountSubTypeCurrentAccount and Savings accounts. Not available for CreditCard, Finance, or Mortgage accounts.accountId path parameter is held by the customer resolved from o3-psu-identifier. Apply the Account Access Validation check before status handling — a non-held account MUST return 403 with errorCode: Consent.PermanentAccountAccessFailure.Active, do not return the resource. Apply the Account Status Handling mapping to return 403 with the corresponding errorCode and errorMessage.List Scheduled Payments
/accounts/{accountId}/scheduled-paymentsaccountid matches the value in the accountId path parameter.accountId, scheduledPaymentId, scheduledType, scheduledPaymentDateTime, and instructedAmount (with amount and currency).creditorAccount (with schemeName and identification), creditorAgent, creditorReference, and debtorReference where held.200 with an empty data array. Do not return 404.AccountSubTypeCurrentAccount and Savings accounts. Not available for CreditCard, Finance, or Mortgage accounts.accountId path parameter is held by the customer resolved from o3-psu-identifier. Apply the Account Access Validation check before status handling — a non-held account MUST return 403 with errorCode: Consent.PermanentAccountAccessFailure.Active, do not return the resource. Apply the Account Status Handling mapping to return 403 with the corresponding errorCode and errorMessage.List Standing Orders
/accounts/{accountId}/standing-ordersaccountid matches the value in the accountId path parameter.accountId, standingOrderId, frequency, firstPaymentDateTime, standingOrderStatusCode, and firstPaymentAmount (with amount and currency).nextPaymentDateTime, nextPaymentAmount, lastPaymentDateTime, lastPaymentAmount, finalPaymentDateTime, finalPaymentAmount, numberOfPayments, creditorAccount, creditorAgent, and standingOrderType where held.200 with an empty data array. Do not return 404.AccountSubTypeCurrentAccount and Savings accounts. Not available for CreditCard, Finance, or Mortgage accounts.accountId path parameter is held by the customer resolved from o3-psu-identifier. Apply the Account Access Validation check before status handling — a non-held account MUST return 403 with errorCode: Consent.PermanentAccountAccessFailure.Active, do not return the resource. Apply the Account Status Handling mapping to return 403 with the corresponding errorCode and errorMessage.List Statements
/accounts/{accountId}/statementsaccountid matches the value in the accountId path parameter.fromStatementDatetoStatementDateaccountId, accountSubType, statementId, statementDate, openingDate, closingDate, openingBalance (with creditDebitIndicator, amount, and currency), closingBalance (with creditDebitIndicator, amount, and currency), and summary (with creditDebitIndicator, subTransactionType, amount, and count per entry).creditLine where applicable.fromStatementDate or toStatementDate extends beyond two years into the past is well-formed and MUST NOT be rejected — return 200 with the matching subset (empty where none).200 with an empty data array. Do not return 404.fromStatementDate after toStatementDate), or a toStatementDate in the future — returning 400 with errorCode: Resource.InvalidFormat. The endpoint therefore receives only well-formed ranges and does not re-validate them.meta.paginated, meta.totalRecords, and meta.totalPages must be accurate.AccountSubTypeCurrentAccount, Savings, CreditCard, Finance, and Mortgage.accountId path parameter is held by the customer resolved from o3-psu-identifier. Apply the Account Access Validation check before status handling — a non-held account MUST return 403 with errorCode: Consent.PermanentAccountAccessFailure.Active, do not return the resource. Apply the Account Status Handling mapping to return 403 with the corresponding errorCode and errorMessage.List Transactions
/accounts/{accountId}/transactionsaccountid matches the value in the accountId path parameter.fromBookingDateTimetoBookingDateTimefromBookingDateTime or toBookingDateTime must be ignored. Filter against local booking date-time only.accountId, transactionId, transactionDateTime, transactionType, subTransactionType, creditDebitIndicator, status, bookingDateTime, and amount (with amount and currency).balance (with creditDebitIndicator, balanceType, and amount) where available, merchantDetails, creditorAccount, debtorAccount, cardInstrument, currencyExchange, flags, and paymentPurposeCode where held.transactionInformation and transactionReference must be provided where held to give the TPP meaningful context for the transaction.fromBookingDateTime or toBookingDateTime extends beyond two years into the past is well-formed and MUST NOT be rejected — return 200 with the matching subset (empty where none).200 with an empty data array. Do not return 404.fromBookingDateTime after toBookingDateTime), or a toBookingDateTime in the future — returning 400 with errorCode: Resource.InvalidFormat. The endpoint therefore receives only well-formed ranges and does not re-validate them.meta.paginated, meta.totalRecords, and meta.totalPages must be accurate.AccountSubTypeCurrentAccount, Savings, CreditCard, Finance, and Mortgage.accountId path parameter is held by the customer resolved from o3-psu-identifier. Apply the Account Access Validation check before status handling — a non-held account MUST return 403 with errorCode: Consent.PermanentAccountAccessFailure.Active, do not return the resource. Apply the Account Status Handling mapping to return 403 with the corresponding errorCode and errorMessage.List Products
/accounts/{accountId}/productsaccountid matches the value in the accountId path parameter.FinanceRates is always returned in cleartext, regardless of which response shape is chosen for FinanceRates (see below).FinanceRates — permission gatingFinanceRates field on a Product record when the consent carries the ReadProductFinanceRates permission. If the permission is absent, omit the field entirely — do not substitute null, an empty object, or a placeholder JWE. See Encrypted FinanceRates — Step 1 for the permission-check pattern.FinanceRates — response shapeReadProductFinanceRates is present, the LFI MAY return FinanceRates as either a cleartext AEProductFinanceRates JSON object or as an AEJwe compact serialisation string. The choice is at the LFI's discretion, typically per product type (e.g. cleartext for deposit accounts, JWE for credit cards, finance accounts, and mortgages where the rate is commercially sensitive).FinanceRates — cleartext pathAEProductFinanceRates object alongside the rest of the Product record in the standard JSON response, exactly as every other field on this endpoint is served. No additional handling — no OTP, no encryption, no rate limits beyond the standard ones — applies.FinanceRates — JWE pathAEProductFinanceRates as a PBES2-HS512+A256KW / A256GCM JWE with the OTP as the password, embed a 30-minute exp in the plaintext, and enforce the per-(consent, account) rate limits (60-second interval, 12 fresh OTPs per rolling 24 hours) by rejecting breaches with 429 Too Many Requests and a Retry-After header.200 with an empty data array. Do not return 404.AccountSubTypeCurrentAccount, Savings, CreditCard, Finance, and Mortgage.accountId path parameter is held by the customer resolved from o3-psu-identifier. Apply the Account Access Validation check before status handling — a non-held account MUST return 403 with errorCode: Consent.PermanentAccountAccessFailure.Active, do not return the resource. Apply the Account Status Handling mapping to return 403 with the corresponding errorCode and errorMessage.Get Customer
/accounts/{accountId}/customeraccountid matches the value in the accountId path parameter.id, claims verifiedClaims, customerType, customerCategory, and accountRole.verifiedClaims[].claims must include identityType, fullName, givenName, familyName, emiratesId, emiratesIdExpiryDate, and residentialAddress. Include all optional fields (middleName, birthDate, mobileNumber, email, nationality, etc.) where held.verifiedClaims[].claims must include identityType, businessName, and tradeLicenceNumber. Include all optional fields (taxIdentificationNumber, dateOfIncorporation, countryOfIncorporation, corporateAddress, etc.) where held.200 with an empty data array. Do not return 404.accountId path parameter is held by the customer resolved from o3-psu-identifier. Apply the Account Access Validation check before status handling — a non-held account MUST return 403 with errorCode: Consent.PermanentAccountAccessFailure.Active, do not return the resource. Apply the Account Status Handling mapping to return 403 with the corresponding errorCode and errorMessage.Get Customer
/customero3-psu-identifier header passed by the Hub.id, verifiedClaims, and customerCategory.verifiedClaims[].claims must include identityType, fullName, givenName, familyName, emiratesId, emiratesIdExpiryDate, and residentialAddress. Include all optional fields where held.verifiedClaims[].claims must include identityType, businessName, and tradeLicenceNumber. Include all optional fields where held.Account Access Validation
Every endpoint that takes an account identifier — whether as the accountId path parameter under /accounts/{accountId} and /accounts/{accountId}/…, or as values in the accountIds query parameter on GET /accounts — MUST validate that each account is held by the customer resolved from the o3-psu-identifier header before applying the per-endpoint rules above. Account ownership is authoritative on the LFI side — the Hub stores the accountIds patched onto the consent at authorization, but the LFI is the source of truth for which accounts the customer actually holds. If the patched set ever drifted from the customer's actual holdings, only the LFI can detect it.
If any requested account is not held by the resolved customer, return 403 with errorCode: Consent.PermanentAccountAccessFailure and errorMessage: The account is permanently inaccessible. Apply this check before the Account Status Handling mapping — a non-held account MUST NOT leak status information.
GET /customer is exempt — it is resolved from o3-psu-identifier and not scoped to a specific account.
Account Status Handling
The rules above assume the account is in a readable state. The table below summarises how each value of AEAccountStatusCode maps to a response for endpoints under /accounts/{accountId}.
ActiveInactiveDormantSuspended403 with errorCode: Consent.AccountTemporarilyBlocked and errorMessage: The account is temporarily blocked.Unclaimed403 with errorCode: Consent.PermanentAccountAccessFailure and errorMessage: The account is permanently inaccessible.Deceased403 with errorCode: Consent.PermanentAccountAccessFailure and errorMessage: The account is permanently inaccessible.Closed403 with errorCode: Consent.PermanentAccountAccessFailure and errorMessage: The account is permanently inaccessible.GET /accounts is exempt from this mapping — it returns all consented accounts regardless of status, with the Status field populated so the TPP can see the current state.
