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
Popup Mode
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 instanceconst 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 formpaymentPage.show();Popup Integration
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 instanceconst 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 popuppaymentPage.show();Configuration
Required Parameters
All parameters must be provided when creating a payment page instance.
| Parameter | Type | Description |
|---|---|---|
| url | string | Payment page URL (base URL without query parameters) |
| container_id | string | ID of the HTML element that will contain the iframe |
| api_key | string | Your merchant API key |
| signature | string | Request signature for security (see Signature Generation) |
| amount | string | Payment amount (e.g., "100.00") |
| currency_iso | string | Currency code (ISO 4217, e.g., "EUR", "USD") |
| user_id | string | Your customer/user identifier |
| order_id | string | Your order/transaction identifier |
| mcc | string | Merchant Category Code |
| success_url | string | URL to redirect on successful payment |
| failure_url | string | URL to redirect on failed payment |
Optional Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| width | number | 100% | Iframe only. Width in pixels (e.g., 400). If not specified, uses 100% of container |
| ts_nonce | number | - | 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.timestampReference: 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 contextoptions- Current options (type, etc.)isVisible- Whether the form is currently visibleiframe- 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 Type | Description | Auto-handled |
|---|---|---|
| GENOME_FRAME_RESIZE | Payment form height changed | โ Yes - automatically resizes iframe |
| ready | Payment form loaded and ready | โ Yes - logged to console |
| initialized | Payment session initialized | โ Yes - logged to console |
| redirect | Payment completed, redirect required | โ Yes - automatically redirects to success/failure URL |
| close | User 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
- 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
- Use MODE_A_TS for production
- Includes timestamp to prevent replay attacks
- More secure than basic MODE_A
- Timestamp must be sent as
ts_nonceparameter
- Validate redirect URLs
- Ensure
success_urlandfailure_urlare on your domain - Implement proper session validation on redirect endpoints
- Don't trust client-side payment status - always verify on backend
- 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
- CSP (Content Security Policy)
- Allow
frame-srcfor the payment page andscript-srcfor 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:
- Check that the container element exists:
const container = document.getElementById('payment-container');if (!container) { console.error('Container not found!');}- Check browser console for errors
- Verify that the
urlparameter is correct and accessible - Ensure your API key and signature are valid
- Check that the container has sufficient size:
#payment-container { min-height: 400px; width: 100%;}Signature validation fails
Problem: Backend returns signature validation error
Solutions:
- 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
- Check amount formatting (must be 2 decimal places):
const amount = parseFloat('100.5').toFixed(2); // "100.50"- Ensure all parameters match between signature generation and SDK config
- Verify timestamp is in seconds, not milliseconds:
const timestamp = Math.floor(Date.now() / 1000); // Correctconst timestamp = Date.now(); // Wrong- 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:
- Each iframe automatically gets a unique
frameId- this should prevent conflicts - Verify each payment page has a unique
container_id - Check browser console for warnings about frameId mismatches
- Ensure you're not reusing the same instance:
// Wrong - reusing instanceconst page = createPaymentPage(config);page.show(); // Container Apage.show(); // Container B - will still use Container A
// Correct - separate instancesconst 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:
- This is handled automatically via
GENOME_FRAME_RESIZEmessages - Ensure the iframe is not inside an overflow: hidden container that restricts height
- Verify the iframe is not restricted by parent container CSS (max-height, fixed height, etc.)
- For popup mode, height should always be 100vh (fullscreen)
- 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 exampleuseEffect(() => { const page = createPaymentPage(config); page.show();
return () => { page.destroy(); // Critical for cleanup };}, []);
// Vue exampleexport 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:
- Add
frame-srcdirective 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- 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;- 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>Popup Mode with IIFE
<!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
- No import statement: IIFE versions are loaded via
<script src="..."></script>withouttype="module" - Global variable: Access the SDK via
GenomeSDK.createPaymentPage()instead of importing - All features work: Both ES and IIFE versions have identical functionality
- 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:
- Check the browser console for error messages
- Enable SDK debug logging by checking console output (SDK logs all major events)
- 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