Guide

This guide walks you through embedding Ivy Checkout directly in your website using our iframe integration. You’ll create a seamless checkout experience where customers can complete their payment without leaving your site.

Step 1: Backend Setup

1

Install Dependencies

First, install our official Node SDK:

npm install @getivy/node-sdk
# or
yarn add @getivy/node-sdk
2

Create a Checkout Session

Create an endpoint on your server that initializes a checkout session:

server/routes/checkout.ts
import express from 'express';
import Ivy from '@getivy/node-sdk';
import { CheckoutsessionCreateParams } from '@getivy/node-sdk/resources/checkoutsession';

const router = express.Router();
const ivy = new Ivy('YOUR_API_KEY');

router.post('/api/checkout', async (req, res) => {
  try {
    const params: CheckoutsessionCreateParams = {
      reference: 'order_123', // Your unique order reference
      value: 1000, // Amount in cents
      currency: 'EUR',
      market: req.body.market || 'DE',
      mode: 'iframe', // Important: Set mode to iframe
      redirectUrl: `${process.env.BASE_URL}/payment-status?session={sessionId}`,
    };

    const session = await ivy.checkoutSessions.create(params);
    res.json({ url: session.checkoutUrl });
  } catch (error) {
    res.status(500).json({ error: 'Failed to create checkout session' });
  }
});

export default router;
3

Handle Payment Status

Create an endpoint to verify payment status:

server/routes/payment-status.ts
router.get('/api/payment-status/:sessionId', async (req, res) => {
  try {
    const session = await ivy.checkoutSessions.retrieve(req.params.sessionId);
    res.json({ status: session.status });
  } catch (error) {
    res.status(500).json({ error: 'Failed to get payment status' });
  }
});

Step 2: Frontend Implementation

Choose your preferred frontend implementation:

1

Install Dependencies

npm install axios
# or
yarn add axios
2

Create IvyCheckout Component

components/IvyCheckout.tsx
import { useState, useEffect } from 'react'
import axios from 'axios'

interface IvyCheckoutProps {
  amount: number
  currency?: string
  market?: string
  onSuccess?: (referenceId: string) => void
  onError?: () => void
}

export function IvyCheckout({
  amount,
  currency = 'EUR',
  market = 'DE',
  onSuccess,
  onError
}: IvyCheckoutProps) {
  const [iframeUrl, setIframeUrl] = useState<string | null>(null)

  useEffect(() => {
    const handleMessage = (event: MessageEvent) => {
      try {
        const { source, type, value, referenceId } = JSON.parse(event.data)
        if (source !== 'ivy' || type !== 'iframe') return

        if (value === 'success') {
          onSuccess?.(referenceId)
        } else if (value === 'error') {
          onError?.()
        }
      } catch (error) {
        console.error('Error processing message:', error)
      }
    }

    window.addEventListener('message', handleMessage)
    return () => window.removeEventListener('message', handleMessage)
  }, [onSuccess, onError])

  const startCheckout = async () => {
    try {
      const { data } = await axios.post('/api/checkout', {
        amount,
        currency,
        market
      })
      setIframeUrl(`${data.url}&iframe=true`)
    } catch (error) {
      console.error('Checkout creation failed:', error)
      onError?.()
    }
  }

  return (
    <div className="ivy-checkout">
      {!iframeUrl ? (
        <button
          onClick={startCheckout}
          className="ivy-checkout-button"
        >
          Pay with Ivy
        </button>
      ) : (
        <iframe
          src={iframeUrl}
          className="ivy-checkout-frame"
          sandbox="allow-scripts allow-same-origin allow-popups allow-forms allow-popups-to-escape-sandbox allow-top-navigation"
        />
      )}
    </div>
  )
}
3

Add Styling

styles/ivy-checkout.css
.ivy-checkout {
  width: 100%;
  max-width: 500px;
  margin: 0 auto;
}

.ivy-checkout-frame {
  width: 100%;
  height: 650px;
  border: none;
  border-radius: 8px;
}

.ivy-checkout-button {
  width: 100%;
  padding: 12px;
  background: #000;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

Reference

Instead of redirecting to any callback URLs, the iframe communicates with the parent window via the postMessage API.

The iframe will send a message to the parent window with the following fields:

source
string
required

Always equal to "ivy"

type
string
required

Always equal to "iframe"

value
string
required

Either "success" or "error"

referenceId
string
required

Your original checkoutSession field referenceId. Can also be used to fetch a order with the Retrieve an Order endpoint.

Security Considerations

The iframe sandbox attributes are crucial for security. Each attribute serves a specific purpose:

  • allow-scripts: Required for Ivy Checkout to function
  • allow-same-origin: Enables secure communication
  • allow-forms: Required for payment form input
  • allow-popups and allow-popups-to-escape-sandbox: Required for bank redirects
  • allow-top-navigation: Required for completion redirects

Need Help?