Encrypted Premiums 5 min read
When a TPP holds the ReadInsurancePremium permission and calls any /{type}-insurance-policies endpoint, the LFI MAY return the Premium field as an encrypted JWE rather than a structured object. The TPP MUST present the premium to the customer without the unencrypted value ever reaching or being stored on its servers — decryption happens locally on the customer’s device.
Encrypted premiums are an LFI-side choice
The Premium field on every insurance policy response is defined as anyOf a structured AEInsuranceDataSharingPremiumProperties object or an AEInsurancePremiumJWE compact string. Each LFI decides, per policy, whether to return the premium in cleartext or as an encrypted JWE. A TPP holding ReadInsurancePremium MUST therefore be ready for either shape on every call.
- Cleartext —
Premiumis a JSON object containingPremiumAmountExcludingVAT,PremiumVATAmount,TotalPremiumAmount,Currency, andPremiumFrequency. Render directly. No special handling required. - Encrypted (JWE) —
Premiumis a compact JWE string. The TPP server MUST forward this opaque string to the customer’s device without inspecting, logging, or persisting it. Decryption happens in the browser or mobile app using key material tied to the customer’s authenticated session.
Some insurers treat the premium as commercially sensitive — in particular for switching and quote-comparison use cases where premium parity is a competitive lever. The encrypted JWE shape lets the premium flow through the TPP to the customer’s screen without the TPP ever holding the cleartext value.
What you need before calling these endpoints
- A consent that includes
ReadInsurancePremiumfor the relevantInsuranceType— this permission MUST be present in the per-sector block ofauthorization_details.consent.Permissionswhen the TPP creates the consent. See Constructing Authorization Details. - The Access Encrypted Resource Data optional certification — before requesting
ReadInsurancePremiumon a live LFI, the TPP MUST hold this certification with Nebras. See Access Encrypted Resource Data. - A valid access token and the standard FAPI headers —
x-fapi-interaction-id,x-fapi-auth-date, andx-fapi-customer-ip-address. See Request Headers.
Fetch the policy detail as normal
/{type}-insurance-policies/{InsurancePolicyId} Premium values are returned on the per-policy detail endpoint. Use an InsurancePolicyId obtained from a prior GET /{type}-insurance-policies call (Step 8 of the API Guide) and request the detailed policy.
Whether the LFI returns cleartext or an encrypted JWE for Premium, the request itself is unchanged. Make the call as you would for any other Insurance Data Sharing endpoint:
import crypto from 'node:crypto'
// insurancePolicyId comes from a prior GET /{type}-insurance-policies call —
// see Step 8 of the API Guide.
const response = await fetch(
`${LFI_API_BASE}/open-finance/insurance/v2.1/motor-insurance-policies/${insurancePolicyId}`,
{
headers: {
Authorization: `Bearer ${access_token}`,
'x-fapi-interaction-id': crypto.randomUUID(),
'x-fapi-auth-date': lastCustomerAuthDate,
'x-fapi-customer-ip-address': customerIpAddress,
},
// agent: new https.Agent({ cert: transportCert, key: transportKey }),
}
)
const { Data: { Policy: policy } } = await response.json()
Example response — cleartext
{
"Data": {
"Policy": {
"InsurancePolicyId": "policy-001",
"PolicyNumber": "MTR-2025-000123",
"PolicyStatus": "Active",
"Insurer": { "Name": "Example Insurance LLC" },
"Premium": {
"PremiumAmountExcludingVAT": "950.00",
"PremiumVATAmount": "47.50",
"TotalPremiumAmount": "997.50",
"Currency": "AED",
"PremiumFrequency": "Annually"
}
}
},
"Links": {
"Self": "https://rs1.altareq1.sandbox.apihub.openfinance.ae/open-finance/insurance/v2.1/motor-insurance-policies/policy-001"
},
"Meta": {}
}
Example response — encrypted JWE
{
"Data": {
"Policy": {
"InsurancePolicyId": "policy-001",
"PolicyNumber": "MTR-2025-000123",
"PolicyStatus": "Active",
"Insurer": { "Name": "Example Insurance LLC" },
"Premium": "eyJhbGciOiJQQkVTMi1IUzUxMitBMjU2S1ciLCJlbmMiOiJBMjU2R0NNIiwicDJzIjoiNGtBWG..."
}
},
"Links": {
"Self": "https://rs1.altareq1.sandbox.apihub.openfinance.ae/open-finance/insurance/v2.1/motor-insurance-policies/policy-001"
},
"Meta": {}
}
Apart from Premium, every other field on the policy is returned in cleartext in both shapes — PolicyNumber, PolicyStatus, Insurer, dates, coverage, riders, and so on. Only Premium is ever encrypted.
Branch on whether Premium is a string
If Premium is a JSON object, render its fields directly. If it is a string, treat it as an opaque compact JWE and forward it to the customer’s browser or mobile app. The TPP server MUST NOT attempt to decrypt the JWE, parse its header beyond detecting the string type, log its contents, or persist it.
// Premium is anyOf { object | string } per the OpenAPI spec.
// A string value is a compact JWE that must be decrypted on the customer's device.
const premium = policy.Premium
const isEncrypted = typeof premium === 'string'
if (isEncrypted) {
// Forward the opaque JWE to the browser. Do not parse, log, or persist it.
forwardToBrowser({ policyId: policy.InsurancePolicyId, premiumJwe: premium })
} else {
// Cleartext path — render the premium directly from the structured object
renderPremium({ policyId: policy.InsurancePolicyId, premium })
}
The encrypted JWE is opaque to the TPP. Pass it through to the customer device and discard the server-side copy as soon as the response is sent. Do not write the JWE to application logs, request traces, or analytics pipelines — even though it is encrypted, persisting it would put the TPP in scope of the encrypted-data handling requirements documented in Access Encrypted Resource Data.
The decrypted premium never leaves the device
Decryption MUST run on the customer’s device — the cleartext premium MUST NOT be sent to the TPP server or any third party. The mechanism mirrors the Bank Data Sharing encrypted-rate flow described in Encrypted FinanceRates; use the same JOSE-library pattern, keep the OTP/key material in browser memory only, and discard the decrypted premium when the customer navigates away.
The decrypted Premium object MUST stay inside the page’s JavaScript scope. Do not POST it back to your server for “processing”, do not include it in analytics events, and do not echo it back into a form that submits to your domain. The same rule applies to any key material used to unlock the JWE.
