Merchant Hosted
iFrame
Basic Integration
Description
Embed our payment page in an iframe on your website. The payer completes the payment without leaving your page.
The payment page detects that it is opened in an iframe and adapts its layout to it. Everything around the form — the container, its size, the way it is closed — is yours.
Integration Instructions
- Create the order with the Create Order endpoint and take the
paymentLinkfrom the response. - Add an iframe with the
paymentLinkas itssrcand theallowattribute — see Browser Permissions. Size and position the iframe with your own CSS.
<iframe
id="payment-frame"
src="https://pay.example.com/?session-id=..."
allow="clipboard-write *; clipboard-read *; payment *; publickey-credentials-get *; otp-credentials *"
></iframe>
That is the whole integration: your own container — a modal, a window manager, your own close button — closes the iframe, and you learn the result through callbacks or Retrieve Order Details.
Basic integration. The payment page works entirely inside the iframe: it takes the payment and shows the result to the payer. It does not reach your page — it cannot close the iframe or tell your page how the payment ended. Everything outside the iframe is yours: how it is shown, how it is closed, and how your system learns the result.
With the snippet. The payment page gets a channel to your page and brings two things:
- Closing from inside the payment page. The payer can close the payment page from within the form, without leaving it for your controls: the payment page asks your page, and you remove the iframe in the
onClosecallback. - The payment result on your page, right away. When the payment is accepted or declined, the payment page reports it to your page at the same moment the payer sees the final screen — you can close the iframe and show your own confirmation without waiting for the backend callback.
Browser Permissions
Add the allow attribute to the iframe — without it, the browser blocks these features for the embedded payment page:
| Permission | What it enables |
|---|---|
clipboard-write | Copy buttons on the payment page (order number, payment details) |
clipboard-read | Pasting a code from an SMS or an authenticator app |
payment | Payment Request API — Apple Pay and Google Pay |
publickey-credentials-get | WebAuthn and passkeys, used by 3-D Secure |
otp-credentials | Automatic SMS code fill (WebOTP) |
Separate the permissions with semicolons. Add * after each permission so it also covers the acquirer and bank pages opened inside the frame; without * the permission applies to the payment page only.
Customization
Fields, colors, and more can be customized through technical support. Contact support to receive an alias code for the embedded payment form, and pass it in the alias property of paymentPageDesign when creating the order.
Snippet (Optional)
This part is optional. Skip it if your own container closes the iframe and the backend result is enough for you.
Connect the payment page to your page when you need one of these:
- A close button inside the payment form. By design, some payment page layouts place the close button in the form header. The payment page cannot close your iframe by itself, so it asks your page to do it.
- The payment result in your interface right away. When the payment reaches a final screen, the payment page reports
acceptedordeclined, and your page can close the iframe and show its own confirmation without waiting for the backend callback.
The exchange runs over window.postMessage. The ready-made snippet handles it for you.
If you prefer to handle the messages yourself, see the Message Protocol.
Quick Start
- Download payment-page-snippet.js and add it to your page in one of two ways:
- paste its contents into a
<script>tag on your page, the same way analytics code is added; - or host the file on your side and load it with
<script src>.
- paste its contents into a
- Add the iframe as described above.
- Configure the snippet with the iframe and your callbacks:
<iframe
id="payment-frame"
src="https://pay.example.com/?session-id=..."
allow="clipboard-write *; clipboard-read *; payment *; publickey-credentials-get *; otp-credentials *"
></iframe>
<script>
/* contents of payment-page-snippet.js */
</script>
<script>
PaymentPage({
iframe: document.getElementById("payment-frame"),
onClose: function () {
document.getElementById("payment-frame").remove()
},
onPaymentEvent: function (e) {
if (e.event === "accepted") {
document.getElementById("payment-frame").remove()
/* show your own confirmation screen */
}
},
})()
</script>
Load the snippet before the payment page loads: the payment page waits 3 seconds for your page to connect. Without a connection it shows no close button and sends no events.
Pass only the callbacks you need. The close button appears only if you passed onClose, and payment events arrive only if you passed onPaymentEvent.
Options
PaymentPage(options) accepts:
| Option | Required | Type | Description |
|---|---|---|---|
iframe | Yes | HTMLIFrameElement | The iframe with the payment page. Messages are accepted only from the origin of its src |
onClose | No | (payload: { reason: "user" }) => void | Called when the payer clicks the close button. Removing the iframe is up to you |
onPaymentEvent | No | (payload: { event, final?, orderId, traceId? }) => void | Called when the payment reaches a final screen |
onLog | No | (label, message) => void | Logs every message with a label: event for incoming, reply for automatic answers, send for your own calls |
channel | No | string | Message channel name. Do not set it unless support gives you a value |
Callback Payloads
onClose receives the reason for the close request:
{ "reason": "user" }
onPaymentEvent receives the outcome:
{
"event": "accepted",
"orderId": 12345,
"traceId": "550e8400-e29b-41d4-a716-446655440000"
}
{
"event": "declined",
"final": true,
"orderId": 12345,
"traceId": "550e8400-e29b-41d4-a716-446655440000"
}
| Field | Description |
|---|---|
event | accepted or declined |
final | Present for declined only. true means the payment cannot be retried |
orderId | Numeric identifier of the order |
traceId | Optional correlation identifier; include it when contacting support about a payment |
Use these events to update your interface only; confirm the final status on your backend through callbacks or Retrieve Order Details.
Advanced: Reopening the Payment Page
You need this section only if you open the payment page more than once on the same iframe without reloading your page — for example, a new order after a declined one.
PaymentPage(options) returns a create() function. In the Quick Start it is called immediately — PaymentPage({...})(). create() locks onto the origin of iframe.src at the moment it is called, so set iframe.src first. Each call to create() starts a session and returns:
destroy()— stops listening for messages and setsiframe.srctoabout:blank.send(messageType, payload)— sends a message to the payment page. Reserved: the protocol currently defines no messages for you to send.
To open a new payment page on the same iframe:
- Call
destroy()on the current session. - Assign the new
paymentLinktoiframe.src. - Call
create()to start the new session.
Keep this order — otherwise events arrive twice or not at all.
<script>
const iframe = document.getElementById("payment-frame")
// Configure once
const create = PaymentPage({
iframe,
onClose: () => paymentPageSession.destroy(),
})
// Start a session
let paymentPageSession = create()
// Later, open a new session on the same iframe
function reopen(url) {
iframe.src = url // must come before create()
paymentPageSession = create()
}
</script>
PCI DSS Compliant
Description
For merchants compliant with PCI DSS.
Contact
For more information, contact support.