CAAP Operations API Guide 10 min read
When an LFI adopts CAAP, the end user's authentication and consent authorisation experience is delivered by CAAP rather than by the LFI. CAAP drives that experience by calling endpoints on the LFI's Ozone Connect server. This guide walks the end-to-end flow and focuses on what is different about the CAAP path — from the redirect into CAAP, through registration and account or policy selection, to the final redirect back to the TPP.
CAAP Operations endpoints the LFI MUST implement
These endpoints are called on the LFI's Ozone Connect server. They use the same base URL, mTLS, and (where configured) JWT authentication as the LFI's other Ozone Connect surfaces — see Ozone Connect Base URL.
| Endpoint | Direction | Purpose |
|---|---|---|
POST/consent/actions/validate | API Hub → LFI | LFI validates the consent at PAR time; gates whether the consent is created and the request_uri is returned to the TPP. |
POST/users/actions/register/initialize | CAAP → LFI | Identify the end user at the LFI from an encrypted Emirates ID; return the end user's LFI userId. |
POST/users/actions/register/complete | CAAP → LFI | Complete registration after the end user has answered the LFI's OTP challenge. |
GET/accounts | CAAP → LFI | Return every account the end user can share or initiate from, depending on the use case. |
GET/{type}-insurance-policies | CAAP → LFI | Return every insurance policy of the given type the end user can share. |
CAAP also calls the API Hub's Headless Heimdall and Consent Manager at the end of the journey to patch the consent and complete the interaction. The LFI does not implement those — the API Hub does — but they appear in the sequence flow below for completeness.
End-to-end flow diagram
POST /par
The journey begins with the standard POST/par flow — including the API Hub's gating call to POST/consent/actions/validate on the LFI before the consent is created. See Consent Journey — API Guide for the full mechanics; nothing about this step changes for CAAP-adopting LFIs.
Once the TPP has the request_uri, it redirects the end user to the API Hub's authorize URL. The API Hub recognises that this LFI is configured for CAAP and redirects the end user on to CAAP rather than to an LFI-operated authorization endpoint — this is the first point at which CAAP differs from the LFI-operated flow.
End user authenticates at CAAP via EFR or UAE Pass
CAAP authenticates the end user using EFR or UAE Pass. This step does not involve the LFI — CAAP integrates with the national identity rails directly. The end user's Emirates ID is established as a result.
POST /users/actions/register/initialize
Once CAAP has the end user's Emirates ID, it calls POST/users/actions/register/initialize on the LFI's Ozone Connect server. The request body carries the Emirates ID encrypted — never in cleartext.
Encryption with the LFI's ENC1 key
CAAP encrypts the Emirates ID using the LFI's ENC1 public key — the same server-side encryption key referenced in Keys & Certificates. The LFI MUST decrypt the payload using the corresponding ENC1 private key.
The LFI MUST return providerUserIdentifier.userId on the initial response
Regardless of whether the LFI subsequently issues a challenge, the response to register/initialize MUST contain the LFI's identifier for the end user on data.providerUserIdentifier.userId. CAAP uses this identifier from that point on, including the psuIdentifiers.userId it patches onto the consent at the end of the journey — it MUST be identical across all of those uses, and MUST satisfy the opacity rules described in Consent Journey — Identifier requirements.
The userId the LFI returns is stored centrally by the API Hub. It MUST be opaque, non-sensitive, and LFI-defined — never an Emirates ID, passport number, email, phone number, CIF, account number, or any other PII. Use an internal customer reference, a UUID, or another opaque token.
Optional challenge
The LFI may choose to issue its own challenge before registration is final — typically an OTP sent over the LFI's usual SCA channel. To do so, the LFI responds with registrationStatus set to AwaitingChallengeResponse and a challengeId alongside the providerUserIdentifier.userId. CAAP collects the OTP from the end user and calls POST/users/actions/register/complete.
If the LFI does not need to challenge the end user, it responds to the initial register/initialize call directly with registrationStatus: Complete alongside providerUserIdentifier.userId — CAAP skips the complete step entirely.
POST /users/actions/register/complete (challenged journeys only)
Where the LFI issued a challenge, CAAP submits the end user's response via POST/users/actions/register/complete. The LFI verifies the response and returns registrationStatus: Complete. Registration is now finalised and CAAP proceeds to build the authorization page.
Per the CAAP Operations spec, an incorrect challenge response MUST be returned as an HTTP 200 with a result indicator in the payload — not as a 4xx. Reserve non-2xx status codes for genuine error conditions (malformed requests, internal failures).
Fetch the accounts or policies the end user can select from
With the end user registered, CAAP retrieves the data needed to render the authorization page. The endpoint called depends on the consent type, and CAAP signals the use case via the o3-caap-consent-use-case header on the accounts endpoint.
In all three cases, the LFI MUST return every item the end user can choose from — do not pre-filter to a subset. CAAP renders the full list and the end user picks from it on the authorization page.
| Consent type | CAAP calls | LFI returns |
|---|---|---|
| Bank Data Sharing | GET/accounts with o3-caap-consent-use-case: accounts | Every account the end user is permitted to share for data sharing. |
| Bank Service Initiation | GET/accounts with o3-caap-consent-use-case: payments | Every account the end user is permitted to initiate the requested payment from. |
| Insurance Data Sharing | GET/{type}-insurance-policies, once per insurance type in the consent permissions | Every policy of that type the end user is permitted to share. |
