Why this guide exists and who it’s for
In August 2023, Allianz Global Corporate & Specialty (AGCS) disclosed that 37% of its large corporate property claims from 2018–2022 could have been avoided with real-time API-driven data sharing between carrier, broker, and inspection vendors. The loss impact exceeded €1.2 billion in direct and indirect costs. I’ve spent the last six months working with a Lloyd’s syndicate to replicate AGCS’s results for SME cyber and property risks. The biggest blocker wasn’t the AI model; it was the plumbing—specifically, which open insurance API standard to adopt and how to wire it into an embedded ecosystem before the underwriting cycle blows past 30 days. This guide is for the engineers, product managers, and integration leads who own that plumbing.
Which standard to pick: FAPI 2.0 vs. OpenAPI 3.1 vs. ISO 20022
There are three viable paths, and none are free of friction.
Path A: FAPI 2.0 (Financial-grade API) – for high-value, regulated cash flows
FAPI 2.0 is the only standard that satisfies PSD2 RTS SCA and GDPR Article 9 consent requirements out of the box. It is also the slowest to implement because of its layered security profile (PAR, CIBA, JARM). If your embedded use case touches payments, commissions, or claims payouts, this is the only realistic choice. Expect 12–18 engineering weeks for a minimal viable integration.
- Strengths: Regulatory-ready, auditable, supports delegated authority scenarios (e.g., broker acting on behalf of client).
- Weakness: Certificate management overhead (e.g., eIDAS QSealC) adds 20% to infra cost.
Path B: OpenAPI 3.1 – for rapid prototyping and sandbox ecosystems
OpenAPI 3.1 is the default if you are launching a pre-MGA or parametric product that only needs claims notices and exposure data. It lacks built-in consent and strong authentication, so you must bolt on OAuth 2.1 and FAPI 1.0 Message Signing yourself. I’ve seen teams go from spec to sandbox in 6 weeks, but moving to production required a 3-month security audit. That audit uncovered a broken refresh token rotation bug that let expired tokens call the FNOL endpoint for 48 hours.
Path C: ISO 20022 pain/gain – when you must talk to reinsurers and banks
ISO 20022 is the lingua franca of large commercial lines, but it is not an API standard; it is a messaging framework. To expose it as an API, you must implement the ISO 20022 REST profile (pain.001, camt.053, see [ISO 20022, REST Profile, v2.2]). The conversion layer (XSD → JSON) alone consumes 30% of compute budget at >10k TPS. If your embedded flow writes bordereaux to a reinsurer on a daily basis, budget 10 senior weeks and a dedicated middleware engineer.
Decision matrix
| Criteria | FAPI 2.0 | OpenAPI 3.1 | ISO 20022 |
|---|---|---|---|
| Regulatory compliance | PSD2, GDPR, UK Open Banking | None (must add OAuth 2.1 + FAPI 1.0) | None (reinsurance contracts) |
| Time to first sandbox call | 12–18 weeks | 4–6 weeks | 8–12 weeks |
| Token size (JWT) | ~2 KB (JARM + PAR) | ~0.5 KB (basic JWT) | N/A (binary encoded) |
| Annual audits required | 2 (QSA + ISAE 3402) | 1 (internal security) | 0 (reinsurer acceptance) |
Step 1: Map your embedded use cases to data shapes
Start by listing every touchpoint in the customer journey where data crosses an organizational boundary. I keep a simple spreadsheet with four columns: Trigger Event, Data Entity, Frequency, and SLA. Below is the exact template we used for a parametric flood product embedded in a UK mortgage broker portal.
| Trigger Event | Data Entity | Frequency | SLA |
|---|---|---|---|
| Property address submitted | GeoRisk (lat/long + BFE) | Once per submission | 5 s |
| Lender submits valuation | ValuationReport (XML) | Batch 4x/day | 2 h |
| Flood event triggers alarm | |||
| Alert (time, location, severity) | Real-time | 1 s | |
| Claim lodged | FNOL payload | On demand | 30 s |
Risk: If any single entity in the chain (e.g., the GeoRisk provider) is slow or rate-limits you, the embedded UX will freeze. In our pilot, the GeoRisk provider throttled us after 100 QPS, causing address lookups to stall for 8 seconds. We mitigated by caching responses for 5 minutes and falling back to a slower, free tier when the paid tier was unavailable.
Actionable artifact
Export the spreadsheet as a JSON schema bundle and validate against draft-07 to catch shape mismatches early. Use JSON Schema Validator.
Step 2: Choose your transport layer (gRPC vs. REST vs. GraphQL)
I’ve seen teams waste six weeks arguing over this. The decision is binary:
- REST over HTTPS: Use when you must traverse corporate firewalls, need browser support, or will integrate with older TPAs. Tooling is mature (OpenAPI 3.1), but latency grows with payload size.
- gRPC: Use when you control both ends (e.g., embedded widget talking to your own microservice). Latency is <100 ms at 99th percentile, but you need Envoy or Linkerd for cross-cluster routing.
- GraphQL: Avoid unless you have highly variable client needs (e.g., a broker portal that wants to choose which fields it pulls). The resolver depth and N+1 query risk introduce flaky timeouts in production.
Trade-off: gRPC gives you bidirectional streaming, but the server must speak HTTP/2. Most cloud load balancers (AWS ALB, GCP External HTTP(S) LB) still default to HTTP/1.1. You’ll need to enable HTTP/2 explicitly and test with curl --http2 or you’ll get silent 502s.
Step 3: Implement identity and consent (FAPI 2.0 deep dive)
If you selected FAPI 2.0, follow this exact sequence. The first three steps must run in sequence; parallelizing them invites race conditions in the authorization server.
Step 3.1: Register your client
POST to the authorization server’s registration endpoint. Use the exact payload below. Notice the software_statement is a signed JWT (JWS) containing your company’s LEI and regulatory scope.
POST /register HTTP/1.1
Host: auth.fapi2.uk
Content-Type: application/jose+json
{
"software_statement": "eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9...",
"redirect_uris": ["https://embedded.mycarrier.com/callback"],
"token_endpoint_auth_method": "private_key_jwt",
"grant_types": ["authorization_code", "refresh_token"]
}
Gotcha: Many FAPI 2.0 implementations reject the registration if the software_statement expires in <30 days. Rotate it monthly; automate with a cron job and the jwt.io CLI.
Step 3.2: Get a PAR request object
PAR (Pushed Authorization Request) is mandatory in FAPI 2.0. Push the entire request object via POST to /par. The server returns a request URI that you must pass to the OAuth authorization endpoint.
POST /par HTTP/1.1
Host: auth.fapi2.uk
Content-Type: application/x-www-form-urlencoded
request=eyJhbGciOiJQUzI1NiIsInR5cCI6Ikp...&client_id=7f38a1c2
Trade-off: PAR adds 1 RTT but eliminates open redirector attacks. If you try to skip PAR (looking at you, fintech startups), the audit will fail.
Step 3.3: Initiate authorization flow
Redirect the user’s browser to the authorization endpoint with the request URI from PAR. Include the claims parameter to request granular consent for each data entity (e.g., GeoRisk, ValuationReport).
GET /authorize?
client_id=7f38a1c2&
request_uri=urn:fapi2:request:9F26D3B1&
scope=openid+accounts+claims&
claims=%7B%22id_token%22%3A%7B%22https%3A%2F%2Fclaims.mycarrier.com%2Fclaims%2Fgeorisk%22%3A%7B%22essential%22%3Atrue%7D%7D%7D
Risk: If the user denies consent, your embedded UX must handle a consent_required error and fall back to a manual form. In our pilot, 14% of users rejected GeoRisk sharing, forcing a 2-step address lookup.
Step 3.4: Exchange code for tokens
Exchange the authorization code for tokens at the token endpoint. Use MTLS for the client_assertion as required by FAPI 2.0.
POST /token HTTP/1.1
Host: auth.fapi2.uk
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&
code=SplxlOBeZQQYbYS6WxSbIA&
redirect_uri=https%3A%2F%2Fembedded.mycarrier.com%2Fcallback&
client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&
client_assertion=eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9...
Monitoring: Log the expires_in value. If it’s <300 s, your token refresh loop will thrash. Most FAPI 2.0 servers default to 600 s, but some issuers (e.g., Okta) allow 3600 s if your software_statement includes exp:3600.
Step 4: Build the embedded widget (frontend considerations)
I’ve reviewed a dozen embedded portals. The ones that load in <2 s under 3G do three things correctly:
- Lazy-load the SDK: Load the OAuth client library only after the user clicks “Get Quote.”
- Use a service worker: Cache the FAPI 2.0 discovery document and consent screen to avoid round-trips.
- Debounce rapid clicks: If the user toggles the mortgage term between 15y and 30y, debounce for 300 ms to prevent 50 token refreshes.
Code snippet (React + FAPI 2.0 SDK):
import { FapiClient } from "@fapi2/client-sdk";
const client = new FapiClient({
issuer: "https://auth.fapi2.uk",
clientId: "7f38a1c2",
redirectUri: "https://embedded.mycarrier.com/callback",
scope: "openid accounts claims",
});
const handleClick = async () => {
const authUrl = await client.authorizationUrl({
claims: JSON.stringify({
id_token: {
"https://claims.mycarrier.com/claims/georisk": { essential: true },
},
}),
});
window.location.href = authUrl;
};
Trade-off: The SDK adds 120 KB to the bundle. If your customer base skews mobile or developing markets, consider a slimmed-down version that only supports the PAR flow.
Step 5: Harden the backend pipeline
Your microservice must handle three failure modes that I’ve seen bring down embedded flows:
Failure 1: Token expiration during a long-running underwriting call
If the FNOL endpoint takes >600 s, the access token may expire mid-flow. Use the refresh token proactively:
const { access_token, refresh_token } = await client.refreshTokens(refresh_token);
await fetch("/underwrite", {
headers: { Authorization: `Bearer ${access_token}` },
});
Risk: Refresh tokens are long-lived. If stolen, they can mint new access tokens indefinitely. Implement token binding (RFC 8705) or rotate refresh tokens on every use.
Failure 2: API provider rate limits
GeoRisk providers often throttle at 100 QPS. Implement exponential backoff with jitter:
const backoff = (retryAfter) => {
const delay = Math.min(retryAfter * 1000 * (1 + Math.random() * 0.5), 30000);
return new Promise(resolve => setTimeout(resolve, delay));
};
while (true) {
const res = await fetch("https://georisk.com/api/v2/risk", {
headers: { Authorization: `Bearer ${token}` },
});
if (res.status === 429) {
const retryAfter = res.headers.get("Retry-After") || 5;
await backoff(retryAfter);
continue;
}
break;
}
Failure 3: Consent revocation mid-session
Users can revoke consent in their banking portal. Your service must detect consent_revoked errors and gracefully degrade to manual entry:
try {
const geoRisk = await client.claims.get("georisk");
} catch (err) {
if (err.code === "consent_revoked") {
showManualForm();
}
}
Step 6: Security controls and audit artifacts
If you selected FAPI 2.0, the audit trail must include:
- JARM (JWT-secured authorization response mode): Sign the authorization response JWT with RS256 and embed the
statehash to prevent CSRF. - PAR request object: Store the
request_uriand its signed JWT for 12 months (GDPR Article 30). - Token introspection: Log the
activestatus of every access token on every call to detect replay.
Tooling shortcut: Use the Starling FAPI 2.0 Validator to run a pre-audit scan against your endpoints.
Step 7: Performance benchmarking and SLA tracking
Embedded flows live or die on latency. I run these three tests nightly:
- Cold start: Time from user click to first OAuth redirect. Target: <1500 ms.
- Token exchange: Time from redirect back to token endpoint to first API call. Target: <800 ms.
- Data fetch:
Comments