Skip to content

SDK

Overview

The SDK packages provide a complete solution for integrating myFlowpay into your application:

The SDK handles:

  • Payload canonicalization
  • Signature generation (via your server endpoint)
  • Message envelope formatting
  • Event handling
  • Automatic session refresh
  • Automatic createdAt timestamp generation before calling the signature provider (enabled by default via autoSetCreatedAt option)

Packages

Installation

# For authentication utilities
npm install @flowpay-io/embed-auth

# For core embed functionality
npm install @flowpay-io/embed-core

# For React applications
npm install @flowpay-io/embed-react

# Shared types (usually installed as dependency)
npm install @flowpay-io/shared

Basic Usage with Core SDK

import { createFlowpayDomController } from "@flowpay-io/embed-core";
import { createSignedLogin, createRemoteSigner } from "@flowpay-io/embed-auth/client";
import type { InputLaunchPayload } from "@flowpay-io/embed-core";
import { IsoCountryCode } from "@flowpay-io/shared/types";

// Launch payload
const launchPayload: InputLaunchPayload = {
  country: IsoCountryCode.CZ,
  merchantId: "merchant-123",
  partnerCode: "partner-abc",
  userId: "user-456",
  regNum: "12345678",
  email: "user@example.com",
  phone: "+420123456789",
};

// Create DOM controller (simplifies iframe management)
const controller = createFlowpayDomController({
  embedOrigin: "https://my.flowpay.io",
  signatureProvider: {
    signPayload: async (payload) => {
      return await createSignedLogin(
        payload,
        createRemoteSigner("/api/sign-payload")
      );
    },
  },
});

// Set launch payload
controller.setLaunchPayload(launchPayload);

// Listen to events
controller.on("loginSuccess", () => {
  console.log("Login successful");
});

controller.on("error", (error) => {
  console.error("Flowpay error:", error.message);
});

// Mount iframe and login
const iframe = document.getElementById("fp-embedded") as HTMLIFrameElement;
iframe.src = controller.client.urls.embedInitUrl;

iframe.addEventListener("load", async () => {
  controller.mount(iframe);
  await controller.client.waitUntilReady();
  await controller.login();
}, { once: true });

HTML setup:

<iframe id="fp-embedded" style="width: 100%; height: 600px; border: none;"></iframe>

Embed Client State Flow

The @flowpay-io/embed-core client transitions through several states during its lifecycle. The following diagram illustrates the main flow:

%%{init: {'flowchart': {'curve': 'linear'}}}%%
flowchart TD
    Start([Client Created]) --> Idle[Idle]
    Idle -->|attach| Loading[Loading]
    Loading -->|fp:READY| Ready[Ready]
    Ready -->|login| Authenticating[Authenticating]
    Authenticating -->|fp:LOGIN_SUCCESS| Authenticated[Authenticated]
    Authenticated -->|fp:SESSION_EXPIRING| Authenticating
    Authenticated -->|logout| Unauthenticated[Unauthenticated]
    Authenticating -->|fp:ERROR| Error[Error]
    Unauthenticated -->|login| Authenticating
    Loading -->|fp:ERROR| Error

Note

Reload transitions (e.g., Error → Loading, Authenticated → Loading, Unauthenticated → Loading) are omitted from the diagram for clarity. The reload() method can transition most states back to Loading.

Main Flow:

  1. Idle → Client is created, waiting for iframe attachment
  2. Loading → Iframe is loading, waiting for fp:READY event
  3. Ready → Embedded app is ready to receive authentication messages
  4. Authenticating → Login request sent, waiting for fp:LOGIN_SUCCESS
  5. Authenticated → User is logged in and session is active
  6. Unauthenticated → Session terminated (logout or expiration)
  7. Error → Error occurred, can recover via reload()

Server-side Signature Generation

The client-side code calls /api/sign-payload to sign the canonical payload. Here's an example server-side implementation:

import { generateSignature } from "@flowpay-io/embed-auth/server";

// This endpoint is called by the client-side handleSign callback
app.post("/api/sign-payload", async (req, res) => {
  const { payload: canonicalPayload } = req.body;

  const signature = await generateSignature(
    canonicalPayload,
    async () => process.env.PARTNER_SHARED_SECRET // Store securely
  );

  res.json({ signature });
});

React Integration

For React applications, use the @flowpay-io/embed-react package:

import { FlowpayModal, useFlowpayEmbed } from "@flowpay-io/embed-react";
import { createSignedLogin } from "@flowpay-io/embed-auth/client";
import type { InputLaunchPayload } from "@flowpay-io/embed-core";
import { IsoCountryCode } from "@flowpay-io/shared/types";
import "@flowpay-io/embed-react/assets/modal.css";

function App() {
  const flowpay = useFlowpayEmbed({
    embedOrigin: "https://my.flowpay.io",
    getLaunchPayload: async (): Promise<InputLaunchPayload> => {
      // Note: The `createdAt` field is automatically added by FlowpayEmbedClient
      // before calling the signature provider when `autoSetCreatedAt` is true (default).
      // You don't need to include it in your InputLaunchPayload.
      return {
        country: IsoCountryCode.CZ,
        merchantId: "merchant-123",
        partnerCode: "partner-abc",
        userId: "user-456",
        regNum: "12345678",
        email: "user@example.com",
        phone: "+420123456789",
      };
    },
    signatureProvider: {
      signPayload: async (payload) => {
        // Note: The payload parameter already includes `createdAt` (if autoSetCreatedAt is enabled)
        return await createSignedLogin(
          payload,
          async (canonicalPayload: string) => {
            const response = await fetch("/api/sign-payload", {
              method: "POST",
              headers: { "Content-Type": "application/json" },
              body: JSON.stringify({ payload: canonicalPayload }),
            });
            if (!response.ok) {
              throw new Error(`Signing failed: ${response.status}`);
            }
            const { signature } = await response.json();
            return signature;
          }
        );
      },
    },
  });

  return (
    <>
      <button onClick={flowpay.open}>Open Flowpay</button>
      <FlowpayModal
        client={flowpay.client}
        {...flowpay.modalProps}
      />
    </>
  );
}

Example Implementation

A complete reference implementation is available in the Embed Sandbox App repository. This sandbox application demonstrates a full working example of the secure embed integration using the @flowpay-io/embed-react package.

Features:

  • Complete React-based host application using Vite
  • Standalone Node.js signing server for secure payload signing
  • Demonstrates all SDK features including authentication, session management, and event handling
  • Includes server-side signature generation endpoint
  • Ready-to-use development environment

Repository Structure:

  • Frontend: Vite application using @flowpay-io/embed-react for the embed integration
  • Backend: Simple Node.js server handling HMAC-SHA256 signature generation
  • Environment configuration: Supports both local development and cloud deployment

Getting Started:

  1. Clone the repository: git clone https://github.com/flowpay-io/embed-sandbox-app.git
  2. Install dependencies: pnpm install
  3. Configure environment variables (see .env.example)
  4. Start the signing server: pnpm dev:server
  5. Start the frontend: pnpm dev

The sandbox app serves as a reference implementation and can be used as a starting point for your own integration or for testing the embedded Flowpay functionality.

Security Note:
Never include your PARTNER_SHARED_SECRET in frontend code. All cryptographic signing must be done server-side.