Financial Pixel SDK Integration Guide

Financial Pixel SDK Integration Guide

Overview

The Financial Pixel SDK provides a secure and flexible way to integrate payment forms into your web application. The SDK supports two integration modes:

  • Iframe Mode - Embeds the payment form directly in your page
  • Popup Mode - Opens the payment form in a fullscreen overlay

Both modes use the same API and configuration, making it easy to switch between them.

Key Features

  • ๐Ÿ”’ Secure - All communication uses postMessage API with frame isolation
  • ๐Ÿ“ฑ Responsive - Automatic height adjustment based on content
  • ๐ŸŽจ Customizable - Support for custom width and theming (theming coming soon)
  • ๐Ÿ”„ Multiple Instances - Run multiple payment forms on the same page
  • ๐Ÿงน Memory Safe - Proper cleanup with destroy() method

Integration Modes

Iframe Mode

Best for:

  • Embedded checkout flows
  • Custom-styled payment pages
  • Single-page applications
  • Cases where you want the payment form as part of your page layout

Features:

  • Embedded directly in a container element
  • Customizable width (default: 100%)
  • Automatic height adjustment
  • Seamless user experience

Best for:

  • Minimal integration effort
  • Quick payments without layout changes
  • Mobile-optimized flows
  • Cases where you want to focus user attention on payment

Features:

  • Fullscreen overlay
  • Easy to trigger from buttons/links
  • Better mobile experience

Quick Start

Iframe Integration

Step 1: Include the SDK script in your HTML

<script type="module">
import { createPaymentPage } from 'https://pay.genome.eu/sdk/iframe.es.js';
</script>

Step 2: Create a container element

<div id="payment-container"></div>

Step 3: Initialize and show the payment form

import { createPaymentPage } from 'https://pay.genome.eu/sdk/iframe.es.js';
// Create payment page instance
const paymentPage = createPaymentPage({
// Required parameters
url: 'https://pay.genome.eu/',
container_id: 'payment-container',
api_key: 'your_api_key',
signature: 'generated_signature',
amount: '100.00',
currency_iso: 'EUR',
user_id: 'USER12345',
order_id: 'ORDER67890',
mcc: '4121',
success_url: 'https://your-site.com/success',
failure_url: 'https://your-site.com/failure',
// Optional parameters
width: 400, // Width in pixels
});
// Show the payment form
paymentPage.show();

Step 1: Include the SDK script

<script type="module">
import { createPaymentPage } from 'https://pay.genome.eu/sdk/popup.es.js';
</script>

Step 2: Create a container element

Note: Container is required even for popup mode. The SDK uses it to attach the fullscreen overlay to the DOM. The container itself won't be visible, but it must exist.

<div id="popup-container"></div>

Step 3: Initialize and show the popup

import { createPaymentPage } from 'https://pay.genome.eu/sdk/popup.es.js';
// Create payment page instance
const paymentPage = createPaymentPage({
// Same configuration as iframe mode
url: 'https://pay.genome.eu/',
container_id: 'popup-container',
api_key: 'your_api_key',
signature: 'generated_signature',
amount: '100.00',
currency_iso: 'EUR',
user_id: 'USER12345',
order_id: 'ORDER67890',
mcc: '4121',
success_url: 'https://your-site.com/success',
failure_url: 'https://your-site.com/failure',
});
// Show the popup
paymentPage.show();

Configuration

Required Parameters

All parameters must be provided when creating a payment page instance.

ParameterTypeDescription
urlstringPayment page URL (base URL without query parameters)
container_idstringID of the HTML element that will contain the iframe
api_keystringYour merchant API key
signaturestringRequest signature for security (see Signature Generation)
amountstringPayment amount (e.g., "100.00")
currency_isostringCurrency code (ISO 4217, e.g., "EUR", "USD")
user_idstringYour customer/user identifier
order_idstringYour order/transaction identifier
mccstringMerchant Category Code
success_urlstringURL to redirect on successful payment
failure_urlstringURL to redirect on failed payment

Optional Parameters

ParameterTypeDefaultDescription
widthnumber100%Iframe only. Width in pixels (e.g., 400). If not specified, uses 100% of container
ts_noncenumber-Timestamp nonce for MODE_A_TS signature mode

๐Ÿ“‹ Full Parameter Reference: For a complete list of all supported parameters and detailed descriptions, please refer to the Payment Page API Documentation.

Signature Generation

IMPORTANT: Signatures must be generated on your backend server to keep your secret key secure. Never expose your secret key in frontend code.

The SDK supports two signature modes:

MODE_A (Basic)

Format: secret|MODE_A|amount|currency|orderId|userId|mcc

// Backend code example (Node.js)
const crypto = require('crypto');
function generateSignature(secret, amount, currency, orderId, userId, mcc) {
const formattedAmount = parseFloat(amount).toFixed(2);
const message = `${secret}|MODE_A|${formattedAmount}|${currency}|${orderId}|${userId}|${mcc}`;
return crypto.createHash('sha256').update(message).digest('hex');
}
const signature = generateSignature(
'your_secret_key',
'100.00',
'EUR',
'ORDER67890',
'USER12345',
'4121'
);

MODE_A_TS (With Timestamp)

Format: secret|MODE_A_TS|timestamp|amount|currency|orderId|userId|mcc

This mode includes a timestamp to prevent replay attacks.

// Backend code example (Node.js)
function generateSignatureWithTimestamp(secret, amount, currency, orderId, userId, mcc) {
const timestamp = Math.floor(Date.now() / 1000);
const formattedAmount = parseFloat(amount).toFixed(2);
const message = `${secret}|MODE_A_TS|${timestamp}|${formattedAmount}|${currency}|${orderId}|${userId}|${mcc}`;
const signature = crypto.createHash('sha256').update(message).digest('hex');
return { signature, timestamp };
}
const result = generateSignatureWithTimestamp(
'your_secret_key',
'100.00',
'EUR',
'ORDER67890',
'USER12345',
'4121'
);
// Use both signature and timestamp in SDK config:
// signature: result.signature,
// ts_nonce: result.timestamp

Reference: See signature-generator.js for complete implementation examples (testing purposes only).


API Reference

createPaymentPage()

Creates a new payment page instance.

const paymentPage = createPaymentPage({...});

Parameters:

  • config - Configuration object with required and optional parameters (see Configuration)

Returns: PaymentPageAPI object with methods to control the payment form

Example:

const paymentPage = createPaymentPage({
url: 'https://pay.genome.eu/',
container_id: 'payment-container',
api_key: 'pk_test_123',
signature: 'abc123...',
amount: '50.00',
currency_iso: 'USD',
user_id: 'user_456',
order_id: 'order_789',
mcc: '5999',
success_url: 'https://example.com/success',
failure_url: 'https://example.com/failure',
});

Methods

show()

Displays the payment form (iframe or popup).

paymentPage.show();

Behavior:

  • Creates and displays the iframe/popup if not already visible
  • If already visible, does nothing
  • Automatically adds iframe to the specified container
  • Starts listening for messages from the payment form

close()

Hides or removes the payment form.

paymentPage.close();

Behavior:

  • Removes the iframe from DOM
  • Sets visibility state to false
  • Keeps the instance alive for reuse (you can call show() again)

getState()

Returns the current internal state (useful for debugging).

const state = paymentPage.getState();
console.log(state);

Returns: State object containing:

  • context - Configuration and runtime context
  • options - Current options (type, etc.)
  • isVisible - Whether the form is currently visible
  • iframe - Reference to the iframe element (if created)

destroy()

Completely destroys the payment page instance and cleans up all resources.

paymentPage.destroy();

Behavior:

  • Removes message event listeners
  • Clears internal state
  • Frees memory
  • After calling destroy(), the instance cannot be reused

Important: Always call destroy() when you're done with a payment page instance to prevent memory leaks, especially in single-page applications.

Events

The SDK uses the postMessage API for secure communication between your page and the payment form. The following events are handled automatically:

Event TypeDescriptionAuto-handled
GENOME_FRAME_RESIZEPayment form height changedโœ… Yes - automatically resizes iframe
readyPayment form loaded and readyโœ… Yes - logged to console
initializedPayment session initializedโœ… Yes - logged to console
redirectPayment completed, redirect requiredโœ… Yes - automatically redirects to success/failure URL
closeUser requested to close the formโœ… Yes - automatically closes iframe

All events are isolated by frameId to prevent conflicts when multiple payment forms are on the same page.


Usage Examples

Basic Iframe Integration

Simple embedded payment form with default settings:

<!DOCTYPE html>
<html lang="en">
<head>
<title>Payment Example</title>
</head>
<body>
<h1>Complete Your Payment</h1>
<div id="payment-container" style="max-width: 600px; margin: 0 auto;"></div>
<script type="module">
import { createPaymentPage } from 'https://pay.genome.eu/sdk/iframe.es.js';
const paymentPage = createPaymentPage({
url: 'https://pay.genome.eu/',
container_id: 'payment-container',
api_key: 'your_api_key',
signature: 'signature_from_backend',
amount: '99.99',
currency_iso: 'EUR',
user_id: 'customer_123',
order_id: 'order_456',
mcc: '5999',
success_url: window.location.origin + '/success',
failure_url: window.location.origin + '/failure',
});
// Show immediately
paymentPage.show();
</script>
</body>
</html>

Basic Popup Integration

Payment triggered by a button click:

<!DOCTYPE html>
<html lang="en">
<head>
<title>Payment Example</title>
</head>
<body>
<h1>Product Checkout</h1>
<button id="pay-button">Pay $99.99</button>
<!-- Container still required for popup -->
<div id="popup-container"></div>
<script type="module">
import { createPaymentPage } from 'https://pay.genome.eu/sdk/popup.es.js';
let paymentPage = null;
document.getElementById('pay-button').addEventListener('click', async () => {
// Create instance on first click
if (!paymentPage) {
// In production, get signature from your backend
const signatureResponse = await fetch('/api/create-payment-signature', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
amount: '99.99',
currency: 'EUR',
orderId: 'order_' + Date.now(),
userId: 'customer_123',
mcc: '5999'
})
});
const { signature, ts_nonce } = await signatureResponse.json();
paymentPage = createPaymentPage({
url: 'https://pay.genome.eu/',
container_id: 'popup-container',
api_key: 'your_api_key',
signature: signature,
ts_nonce: ts_nonce,
amount: '99.99',
currency_iso: 'EUR',
user_id: 'customer_123',
order_id: 'order_' + Date.now(),
mcc: '5999',
success_url: window.location.origin + '/success',
failure_url: window.location.origin + '/failure',
});
}
// Show popup
paymentPage.show();
});
</script>
</body>
</html>

Custom Width Iframe

Fixed-width payment form (mobile-optimized):

import { createPaymentPage } from 'https://pay.genome.eu/sdk/iframe.es.js';
const paymentPage = createPaymentPage({
url: 'https://pay.genome.eu/',
container_id: 'payment-container',
width: 390, // Fixed width for mobile device simulation
api_key: 'your_api_key',
signature: 'signature_from_backend',
amount: '29.99',
currency_iso: 'USD',
user_id: 'user_001',
order_id: 'mobile_order_123',
mcc: '5999',
success_url: 'https://example.com/success',
failure_url: 'https://example.com/failure',
});
paymentPage.show();

Multiple Iframes

Running multiple payment forms on the same page (each isolated by unique frameId):

<!DOCTYPE html>
<html lang="en">
<head>
<title>Multiple Payments Example</title>
<style>
.payment-section {
display: inline-block;
width: 400px;
margin: 20px;
padding: 20px;
border: 1px solid #ddd;
}
</style>
</head>
<body>
<h1>Multiple Payment Forms</h1>
<div class="payment-section">
<h2>Product A - $50</h2>
<div id="payment-container-a"></div>
</div>
<div class="payment-section">
<h2>Product B - $75</h2>
<div id="payment-container-b"></div>
</div>
<script type="module">
import { createPaymentPage } from 'https://pay.genome.eu/sdk/iframe.es.js';
// Payment form for Product A
const paymentPageA = createPaymentPage({
url: 'https://pay.genome.eu/',
container_id: 'payment-container-a',
api_key: 'your_api_key',
signature: 'signature_a_from_backend',
amount: '50.00',
currency_iso: 'USD',
user_id: 'user_123',
order_id: 'order_product_a',
mcc: '5999',
success_url: window.location.origin + '/success?product=a',
failure_url: window.location.origin + '/failure?product=a',
width: 380,
});
// Payment form for Product B
const paymentPageB = createPaymentPage({
url: 'https://pay.genome.eu/',
container_id: 'payment-container-b',
api_key: 'your_api_key',
signature: 'signature_b_from_backend',
amount: '75.00',
currency_iso: 'USD',
user_id: 'user_123',
order_id: 'order_product_b',
mcc: '5999',
success_url: window.location.origin + '/success?product=b',
failure_url: window.location.origin + '/failure?product=b',
width: 380,
});
// Show both forms
paymentPageA.show();
paymentPageB.show();
// Each iframe operates independently with its own frameId
// Messages are automatically isolated and routed correctly
</script>
</body>
</html>

Manual Show/Hide Control

Control when to show and hide the payment form:

<!DOCTYPE html>
<html lang="en">
<body>
<button id="show-payment">Show Payment Form</button>
<button id="hide-payment">Hide Payment Form</button>
<button id="destroy-payment">Destroy Instance</button>
<div id="payment-container"></div>
<script type="module">
import { createPaymentPage } from 'https://pay.genome.eu/sdk/iframe.es.js';
let paymentPage = createPaymentPage({
url: 'https://pay.genome.eu/',
container_id: 'payment-container',
api_key: 'your_api_key',
signature: 'signature_from_backend',
amount: '100.00',
currency_iso: 'EUR',
user_id: 'user_123',
order_id: 'order_456',
mcc: '5999',
success_url: window.location.origin + '/success',
failure_url: window.location.origin + '/failure',
});
document.getElementById('show-payment').addEventListener('click', () => {
paymentPage.show();
console.log('Payment form shown');
});
document.getElementById('hide-payment').addEventListener('click', () => {
paymentPage.close();
console.log('Payment form hidden');
});
document.getElementById('destroy-payment').addEventListener('click', () => {
paymentPage.destroy();
paymentPage = null;
console.log('Payment instance destroyed');
});
</script>
</body>
</html>

Cleanup and Destroy

Proper cleanup in a single-page application (React example):

import { useEffect, useRef } from 'react';
function PaymentComponent({ config }) {
const paymentPageRef = useRef(null);
useEffect(() => {
// Dynamically import the SDK from CDN
import('https://pay.genome.eu/sdk/iframe.es.js')
.then(({ createPaymentPage }) => {
// Create payment page after SDK loads
paymentPageRef.current = createPaymentPage({
url: 'https://pay.genome.eu/',
container_id: 'payment-container',
...config, // api_key, signature, amount, etc.
});
paymentPageRef.current.show();
})
.catch(error => {
console.error('Failed to load payment SDK:', error);
});
// Cleanup on unmount
return () => {
if (paymentPageRef.current) {
paymentPageRef.current.destroy();
paymentPageRef.current = null;
}
};
}, []); // Empty dependency array - run once on mount
return <div id="payment-container" />;
}

Security

Best Practices

  1. Never expose your secret key in frontend code
  • Always generate signatures on your backend server
  • Use HTTPS for all API calls
  • Validate all requests on your backend
  1. Use MODE_A_TS for production
  • Includes timestamp to prevent replay attacks
  • More secure than basic MODE_A
  • Timestamp must be sent as ts_nonce parameter
  1. Validate redirect URLs
  • Ensure success_url and failure_url are on your domain
  • Implement proper session validation on redirect endpoints
  • Don't trust client-side payment status - always verify on backend
  1. Container element security
  • Use unique container IDs to prevent conflicts
  • Ensure container elements are properly isolated in your DOM
  • Don't reuse container IDs across different payment instances
  1. CSP (Content Security Policy)
  • Allow frame-src for the payment page and script-src for SDK scripts

Example: Content-Security-Policy: frame-src https://pay.genome.eu; script-src 'self' https://pay.genome.eu


Troubleshooting

Payment form doesn't appear

Problem: The iframe is not visible after calling show()

Solutions:

  1. Check that the container element exists:
const container = document.getElementById('payment-container');
if (!container) {
console.error('Container not found!');
}
  1. Check browser console for errors
  2. Verify that the url parameter is correct and accessible
  3. Ensure your API key and signature are valid
  4. Check that the container has sufficient size:
#payment-container {
min-height: 400px;
width: 100%;
}

Signature validation fails

Problem: Backend returns signature validation error

Solutions:

  1. Verify signature generation format matches exactly:
  • MODE_A: secret|MODE_A|amount|currency|orderId|userId|mcc
  • MODE_A_TS: secret|MODE_A_TS|timestamp|amount|currency|orderId|userId|mcc
  1. Check amount formatting (must be 2 decimal places):
const amount = parseFloat('100.5').toFixed(2); // "100.50"
  1. Ensure all parameters match between signature generation and SDK config
  2. Verify timestamp is in seconds, not milliseconds:
const timestamp = Math.floor(Date.now() / 1000); // Correct
const timestamp = Date.now(); // Wrong
  1. Check that secret key is correct and matches between environments

Multiple iframes conflict

Problem: Messages from one iframe affect another, or both forms behave erratically

Solutions:

  1. Each iframe automatically gets a unique frameId - this should prevent conflicts
  2. Verify each payment page has a unique container_id
  3. Check browser console for warnings about frameId mismatches
  4. Ensure you're not reusing the same instance:
// Wrong - reusing instance
const page = createPaymentPage(config);
page.show(); // Container A
page.show(); // Container B - will still use Container A
// Correct - separate instances
const pageA = createPaymentPage(configA);
const pageB = createPaymentPage(configB);
pageA.show();
pageB.show();

Payment form height doesn't adjust

Problem: The iframe height is stuck or shows scrollbars

Solutions:

  1. This is handled automatically via GENOME_FRAME_RESIZE messages
  2. Ensure the iframe is not inside an overflow: hidden container that restricts height
  3. Verify the iframe is not restricted by parent container CSS (max-height, fixed height, etc.)
  4. For popup mode, height should always be 100vh (fullscreen)
  5. Check browser console for resize events:
// The SDK logs resize events
// [SDK] Received GENOME_FRAME_RESIZE: 650 for frameId: genome-frame-...

Memory leaks in SPA

Problem: Payment form instances accumulate in single-page applications

Solution: Always call destroy() when unmounting components:

// React example
useEffect(() => {
const page = createPaymentPage(config);
page.show();
return () => {
page.destroy(); // Critical for cleanup
};
}, []);
// Vue example
export default {
mounted() {
this.paymentPage = createPaymentPage(this.config);
this.paymentPage.show();
},
beforeUnmount() {
if (this.paymentPage) {
this.paymentPage.destroy();
}
}
}

CSP blocks iframe loading

Problem: Browser blocks iframe from loading, console shows CSP violation error

Solutions:

  1. Add frame-src directive to your site's Content Security Policy:
<meta http-equiv="Content-Security-Policy"
content="frame-src https://pay.genome.eu; script-src 'self' https://pay.genome.eu">

Or via HTTP header:

Content-Security-Policy: frame-src https://pay.genome.eu; script-src 'self' https://pay.genome.eu
  1. If using a strict CSP with default-src 'none', ensure you include all required directives:
Content-Security-Policy:
default-src 'none';
frame-src https://pay.genome.eu;
script-src 'self' https://pay.genome.eu;
  1. Check browser console for the exact CSP violation message to identify which directive is missing

Legacy Browser Support

For older browsers that don't support ES modules (e.g., Internet Explorer 11, older versions of Safari, Chrome, and Firefox), the SDK provides IIFE (Immediately Invoked Function Expression) versions.

IIFE Version URLs

Instead of ES module versions, use the IIFE builds:

  • Iframe mode: https://pay.genome.eu/sdk/iframe.iife.js
  • Popup mode: https://pay.genome.eu/sdk/popup.iife.js

Usage Example

The IIFE version exposes the SDK as a global variable GenomeSDK on the window object:

<!DOCTYPE html>
<html lang="en">
<head>
<title>Legacy Browser Payment Example</title>
</head>
<body>
<h1>Complete Your Payment</h1>
<div id="payment-container"></div>
<!-- Load IIFE version via script tag (no type="module") -->
<script src="https://pay.genome.eu/sdk/iframe.iife.js"></script>
<script>
// SDK is available as GenomeSDK global variable
var paymentPage = GenomeSDK.createPaymentPage({
url: 'https://pay.genome.eu/',
container_id: 'payment-container',
api_key: 'your_api_key',
signature: 'signature_from_backend',
amount: '99.99',
currency_iso: 'EUR',
user_id: 'customer_123',
order_id: 'order_456',
mcc: '5999',
success_url: window.location.origin + '/success',
failure_url: window.location.origin + '/failure',
});
// Show the payment form
paymentPage.show();
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<body>
<button id="pay-button">Pay Now</button>
<div id="popup-container"></div>
<script src="https://pay.genome.eu/sdk/popup.iife.js"></script>
<script>
var paymentPage = null;
document.getElementById('pay-button').addEventListener('click', function() {
if (!paymentPage) {
paymentPage = GenomeSDK.createPaymentPage({
url: 'https://pay.genome.eu/',
container_id: 'popup-container',
api_key: 'your_api_key',
signature: 'signature_from_backend',
amount: '99.99',
currency_iso: 'EUR',
user_id: 'customer_123',
order_id: 'order_456',
mcc: '5999',
success_url: window.location.origin + '/success',
failure_url: window.location.origin + '/failure',
});
}
paymentPage.show();
});
</script>
</body>
</html>

Browser Compatibility

ES Module Version (iframe.es.js, popup.es.js):

  • โœ… Chrome 61+
  • โœ… Firefox 60+
  • โœ… Safari 11+
  • โœ… Edge 79+
  • โŒ Internet Explorer (not supported)

IIFE Version (iframe.iife.js, popup.iife.js):

  • โœ… Chrome 49+
  • โœ… Firefox 52+
  • โœ… Safari 10+
  • โœ… Edge 15+
  • โœ… Internet Explorer 11 (with polyfills for Promise and fetch)

Important Notes

  1. No import statement: IIFE versions are loaded via <script src="..."></script> without type="module"
  2. Global variable: Access the SDK via GenomeSDK.createPaymentPage() instead of importing
  3. All features work: Both ES and IIFE versions have identical functionality
  4. Polyfills: For IE11, you may need polyfills for:
  • Promise (e.g., https://cdn.jsdelivr.net/npm/promise-polyfill@8/dist/polyfill.min.js)
  • fetch (e.g., https://cdn.jsdelivr.net/npm/whatwg-fetch@3/dist/fetch.umd.js)

Need Help?

If you encounter issues not covered in this guide:

  1. Check the browser console for error messages
  2. Enable SDK debug logging by checking console output (SDK logs all major events)
  3. Contact technical support with:
  • Browser and version
  • Error messages from console
  • SDK configuration (without sensitive data like secret keys)
  • Steps to reproduce the issue

Document Version: 1.0 Last Updated: December 2025 SDK Version: Compatible with Financial Pixel SDK v1.x