Communication Protocol
The host app uses postMessage to send messages to the embedded app. This is the recommended and secure method for authentication and session management. Alternatively, for convenience in specific scenarios, the signature may be passed via URL parameters, though this approach offers lower security and should be avoided when possible.
Events
The embedded myFlowpay application emits and listens for the following events:
The following diagram illustrates the typical event flow between the host application and the embedded app:
sequenceDiagram
participant PartnerBackend as Partner: Backend Server
participant Host as Partner: Host App
participant Embedded as Flowpay: Embedded App
participant Backend as Flowpay: Backend Server
Note over Embedded: Iframe loads
Embedded->>Host: fp:READY
Note over Host: App is ready<br />to receive login
Host->>PartnerBackend: Request signature<br />(payload)
PartnerBackend->>Host: Payload & signature
Host->>Embedded: fp:LOGIN<br />(with payload & signature)
Note over Embedded: Validates signature
alt Authentication Success
Embedded->>Backend: Authenticate<br />(payload & signature)
Backend->>Embedded: Auth token
Note over Embedded: Saves token to<br />browser cookies
Embedded->>Host: fp:LOGIN_SUCCESS
Note over Host,Embedded: Session active
loop During Active Session
Note over Embedded: ~60 seconds before<br />token expiry
Embedded->>Host: fp:SESSION_EXPIRING
Note over Host: Refresh session
Host->>PartnerBackend: Request signature<br />(payload)
PartnerBackend->>Host: Payload & new signature
Host->>Embedded: fp:LOGIN<br />(with payload & signature,<br />reason: "refresh")
Embedded->>Backend: Authenticate<br />(payload & signature)
Backend->>Embedded: Auth token
Note over Embedded: Updates token in<br />browser cookies
Embedded->>Host: fp:LOGIN_SUCCESS
end
opt User Action: Logout
Host->>Embedded: fp:LOGOUT
Note over Embedded: Clears cookies
Embedded->>Host: fp:LOGOUT_SUCCESS
end
opt External URL Needed
Embedded->>Host: fp:OPEN_EXTERNAL (url)
Note over Host: Opens URL in<br />new window
end
else Authentication Failure
Embedded->>Host: fp:ERROR
Note over Host: Can retry with<br />new fp:LOGIN
end
Events Emitted by Embedded App (Embedded → Host)
| Event | Direction | Payload | Description |
|---|---|---|---|
fp:READY |
Embedded → Host | undefined |
Emitted when the embedded app is loaded and ready to receive authentication messages. |
fp:LOGIN_SUCCESS |
Embedded → Host | undefined |
Emitted after successful authentication. The session is now active. |
fp:LOGOUT_SUCCESS |
Embedded → Host | undefined |
Emitted after logout is complete. The session has been terminated. |
fp:SESSION_EXPIRING |
Embedded → Host | { secondsLeft?: number } |
Emitted approximately 60 seconds before the JWT token expires. The host should refresh the session by sending a new fp:LOGIN message. |
fp:ERROR |
Embedded → Host | { code?: string; message: string; detail?: unknown } |
Emitted when an error occurs during authentication or session management. |
fp:OPEN_EXTERNAL |
Embedded → Host | { url: string } |
Emitted when the embedded app requests opening a URL in a new window/tab (e.g. new open banking connection, contract signature). The host should handle this by opening the URL. |
Events Sent by Host App (Host → Embedded)
| Event | Direction | Payload | Description |
|---|---|---|---|
fp:LOGIN |
Host → Embedded | Base64URL-encoded canonical JSON payload | Initiates authentication. Must include payload and signature fields in the envelope. |
fp:LOGOUT |
Host → Embedded | undefined |
Terminates the current session. |
fp:SIMULATION |
Host → Embedded | { enableToolbar: boolean } |
Enables or disables the simulation toolbar in the embedded app (development only). |
Event Handling Example:
window.addEventListener("message", (event) => {
// Always verify origin for security
if (event.origin !== "https://my.flowpay.io") return;
const envelope = event.data;
if (!envelope || envelope.channel !== "flowpay-embedded") return;
switch (envelope.event) {
case "fp:READY":
console.log("Flowpay is ready, can now send login");
// Send login message here
break;
case "fp:LOGIN_SUCCESS":
console.log("Login successful");
break;
case "fp:LOGOUT_SUCCESS":
console.log("Logout complete");
break;
case "fp:SESSION_EXPIRING":
const secondsLeft = envelope.payload?.secondsLeft;
console.log(`Session expiring in ${secondsLeft} seconds`);
// Refresh session by sending new fp:LOGIN
refreshSession();
break;
case "fp:ERROR":
const error = envelope.payload;
console.error("Flowpay error:", error.message, error.code);
break;
case "fp:OPEN_EXTERNAL":
const url = envelope.payload?.url;
if (url) {
window.open(url, "_blank");
}
break;
}
});
Logout
The host application is responsible for explicitly terminating the user's session inside the embedded myFlowpay app. To log the user out, the host must send a fp:LOGOUT message to the iframe using postMessage. After receiving this event, the embedded myFlowpay app clears the active session and returns to its initial unauthenticated state, then emits fp:LOGOUT_SUCCESS to confirm.
// Host App posting logout message
const iframe = document.getElementById("fp-embedded");
iframe.contentWindow.postMessage(
{
channel: "flowpay-embedded",
version: "1.0",
event: "fp:LOGOUT",
},
"https://my.flowpay.io"
);
The embedded app will respond with fp:LOGOUT_SUCCESS when the logout is complete.
External URL Handling
The embedded myFlowpay application may need to open external URLs in certain scenarios (e.g. new open banking connection, contract signature). When this occurs, the embedded app emits a fp:OPEN_EXTERNAL event with the URL to open.
The host application should listen for this event and open the URL in a new window or tab:
window.addEventListener("message", (event) => {
if (event.origin !== "https://my.flowpay.io") return;
const envelope = event.data;
if (envelope.event === "fp:OPEN_EXTERNAL") {
const url = envelope.payload?.url;
if (url) {
window.open(url, "_blank", "noopener,noreferrer");
}
}
});
Security Considerations:
- Always verify the
event.originbefore processing messages - Validate that the URL is from a trusted domain if needed
Handling of session expiration
The JWT generated by myFlowpay is valid for 60 minutes. The embedded app emits fp:SESSION_EXPIRING approximately 60 seconds before expiry to allow the host application to refresh the session.
Session Refresh Process:
- When
fp:SESSION_EXPIRINGis received, the host should prepare a new login payload. - The host should update the
createdAttimestamp to the current time. - The host should generate a new signature for the updated payload.
- The host should send a new
fp:LOGINmessage with the refreshed payload and signature.
If the host fails to respond with a valid fp:LOGIN message before the token expires, the session will be terminated and the user will need to re-authenticate.
Example Session Refresh:
let launchPayload = {
country: "CZ",
merchantId: "merchant-123",
partnerCode: "SomePartner",
userId: "user-999",
regNum: "12345678",
email: "user@example.com",
phone: "+420123456789",
};
window.addEventListener("message", async (event) => {
if (event.origin !== "https://my.flowpay.io") return;
const envelope = event.data;
if (!envelope || envelope.channel !== "flowpay-embedded") return;
switch (envelope.event) {
case "fp:SESSION_EXPIRING":
// Refresh session by updating createdAt and sending new LOGIN
const refreshedPayload = {
...launchPayload,
createdAt: new Date().toISOString(),
};
// Canonicalize, encode, and sign the refreshed payload
// Note: If using the SDK, session refresh is handled automatically.
// For manual implementation, you need to implement payload canonicalization
// and signature generation. See [Implementation with SDK](secure-embed-sdk.md) and [Authentication](secure-embed-auth.md) for reference.
const { payload: encodedPayload, signature } = await createSignedLogin(
refreshedPayload
);
// Send refreshed login
const iframe = document.getElementById("fp-embedded");
iframe.contentWindow.postMessage(
{
channel: "flowpay-embedded",
version: "1.0",
event: "fp:LOGIN",
payload: encodedPayload,
signature: signature,
meta: {
sentAt: new Date().toISOString(),
reason: "refresh",
},
},
"https://my.flowpay.io"
);
break;
}
});
Note: The SDK libraries (@flowpay-io/embed-core, @flowpay-io/embed-react) handle session refresh automatically when configured with a signature provider. If signatureProvider is not configured, you must handle fp:SESSION_EXPIRING events manually as shown in the example above.
Error Handling
The embedded myFlowpay application performs strict validation of all authentication messages received from the host. If any validation step fails, the embedded app will not proceed with session initialization and will instead display an error message to the end user. The host application is not required to take further action unless it chooses to retry the login flow.
The following conditions result in an error being shown inside the embedded iframe:
-
Invalid or malformed signature
The provided signature does not match the canonicalized payload when verified with the partner's shared secret.
-
Expired signature
The createdAt timestamp in the payload differs by more than 5 minutes from server time.
-
Malformed payload
The payload does not follow the required JSON structure, contains unsupported fields, or violates character constraints.
-
Unknown or unauthorized partner identifier
The value of partner does not correspond to an active partner onboarding record.
-
Missing required fields
One or more mandatory fields (e.g., merchantId, userId, country, createdAt) are missing.
-
Invalid tenant structure
A tenant object is missing an id, contains duplicate IDs, or includes characters outside the allowed identifier set.
-
Internal activation or identity provisioning failure
Any backend failure during service activation, tenant linking, or user identity creation prevents login and results in an error screen.
When an error occurs, the embedded app:
- Displays a clear error message within the iframe (e.g., "Authentication failed. Please try again or contact support.").
- Stops further initialization and does not issue or store a JWT token.
- Waits for a new valid
fp:LOGINmessage from the host if the host chooses to retry.
Errors are contained inside the iframe and do not affect the host page or its navigation flow.
For a signature computation example, see Authentication.