# Hosted Payment Page Iframe Integration

Embed the Hosted Payment Page in an iframe and communicate over the postMessage lifecycle protocol.

**Category:** Integration

**Last reviewed:** 5 August 2026

# Hosted Payment Page Iframe Integration

The Hosted Payment Page (HPP) supports two embedding modes: redirect mode (you navigate the cardholder to the HPP URL) and iframe mode (you embed the HPP inside a parent page and communicate over the `postMessage` lifecycle protocol). This guide covers iframe mode: authorizing a parent origin, the lifecycle event protocol, the command channel, and the security model.

## Two pieces of configuration

Iframe embedding requires two independent settings to line up:

1. **Page-level `AllowedEmbeddingDomains`**: a list of domains (max 20) authorized to embed a given HPP. Wildcards such as `*.example.com` are supported. Raw IP addresses, `localhost`, and entries without a TLD are rejected. This is the security envelope: a page without your origin in its allow list cannot be framed by your site.
2. **Per-session `parentOrigin`**: set when creating each session. It must be a valid HTTPS origin whose host matches an `AllowedEmbeddingDomains` entry. If it is omitted, the session is still valid for non-embedded use, but the postMessage channel is disabled fail-closed (no events flow to a parent).

If the host does not match, session creation returns `400` with `HostedPaymentPage:HppSession:ParentOriginNotAllowed`.

## The postMessage lifecycle protocol

Once a session has a `parentOrigin`, the embedded HPP emits a stream of `postMessage` events to the parent throughout the session lifecycle. Every event shares one envelope shape; the `data` payload varies by `type`. Filter on the `source` discriminator (`winkpg-hpp`).

A successful payment fires events in this order:

```
session_loaded -> ready -> payment_started -> payment_succeeded -> navigated(to: 'result')
```

Subscribe to `ready` (not `session_loaded`) when you need the iframe to be visually interactive: `ready` fires once the form root has mounted in the DOM.

Key events include `payment_succeeded`, `payment_failed`, `payment_pending`, `height_changed` (for auto-resize), `validation_failed`, `session_expired`, `session_invalid`, and `card_saved` (for save-card-only sessions). If no event arrives within a few seconds, fall back to a timeout and treat it like `session_invalid`: a session that never existed has no `parentOrigin` to address, so it is intentionally silent.

## What the parent receives on a payment

Payment payloads are restricted to fields the public session endpoint already exposes. No PAN, CVV, expiration, network token, wallet cryptogram, or PII is ever included. A successful payment carries the transaction id, requested and approved amounts (compare them to detect a partial approval), masked `last4` and `brand`, the auth code, and the result status. Token fields (`paymentTokenPublicReference`, `customerId`, `schemeTransactionId`) are present only when the cardholder saved a card; key any card-on-file workflow off the presence of `paymentTokenPublicReference`.

## Locking the amount

A session decides who sets the amount the shopper pays. There are three choices. **Customer-entered** puts the shopper in control: they type the figure themselves, which suits an open balance or an ad-hoc payment. **Suggested** pre-fills a figure the shopper can still change, which suits a suggested donation or a recommended top-up. **Locked** fixes the figure so the shopper cannot change it, which suits an invoice or a known order total.

On a locked session, the read-only field is the visible part of the guarantee, not the whole of it. The amount set when the session is created is held with the session on WinkPG's servers, and every submitted payment is checked against it before anything is authorized. A submission whose amount does not match the locked value is rejected, so editing the page in a browser, replaying the request with a different figure, or calling the submit endpoint directly all reach the same outcome: the shopper pays the amount you set, or nothing is charged. The check does not depend on how the shopper pays, so card entry and digital wallets such as Apple Pay and Google Pay are all covered.

A locked session fixes the whole payable total, including any tax, shipping, or convenience fee supplied with the session. The clearest setup is a single figure: fold tax and shipping into the locked amount and send one total. The page then shows the shopper exactly what will be charged, and there is one number to reconcile against the payment afterwards.

## Two-way command channel

The parent can send a small, strictly allowlisted set of commands back into the iframe: `cancel`, `set_locale`, `prefill`, and `request_height`. Inbound commands carry a distinct discriminator (`winkpg-hpp-cmd`) so an outbound envelope cannot be replayed back into the iframe as a command. There is no programmatic `submit`: payment authorization stays user-initiated.

## Security model

A receiver written against the raw `addEventListener('message', ...)` API must do all three checks before trusting an event:

```js
window.addEventListener('message', (event) => {
  if (event.origin !== 'https://hpp.winkpg.com') return;   // (1) origin
  const msg = event.data;
  if (!msg || msg.source !== 'winkpg-hpp') return;          // (2) source discriminator
  if (msg.sessionId !== mySessionId) return;                // (3) session scope
  // handle msg.type
});
```

Skipping any one of these weakens the model. Prefer the client helper library, which performs these checks and exposes typed `on(...)` and `send(...)` APIs.

## Quick-start checklist

- Confirm the HPP page has the embedding feature enabled and add your origin to `AllowedEmbeddingDomains`.
- Set `parentOrigin` to your exact origin on each session create.
- Embed the iframe using the session response URL and serve the parent over HTTPS.
- Register handlers for at least `ready`, `payment_succeeded`, `payment_failed`, `session_invalid`, and `height_changed`.
- Implement a "no event within N seconds" timeout fallback.

## See also

- [The Embedded Payments SDK](/help/guides/embedded-payments-sdk): the supported browser loader over this protocol, which performs the origin, source, and session checks above and exposes the lifecycle as callbacks.
- [Setting Up a Hosted Payment Page](/help/guides/hosted-payment-page-setup): choose a page mode, walk the creation wizard, and configure page options before you get to embedding it.

## See also

- [All documentation](https://docs.winkpg.io/llms.txt): the machine-readable index of every public page on this site.
