Preview. The API is shared with design partners and may change before launch. Register interest for sandbox access.
Iframe embed
The iframe embed shows the same offer as the drop-in SDK, but inside an isolated iframe
served from Phew. No Phew JavaScript runs in your page, nothing from your page is readable by Phew, and the only
connection between the two is a small set of postMessage events. This is the integration most banks and payment
providers choose for their payment pages, hosted checkouts and in-app web views.
Your server ──▶ POST /v1/offers ──▶ offer.embed_urlYour page ──▶ <iframe src=embed_url> ──▶ customer chooses a plan ◀── postMessage: phew:changeYour server ──▶ POST /v1/policies when the order is paidAdd the embed
Section titled “Add the embed”-
Create the offer on your server with
POST /v1/offers. The response includesembed_url: a signed, single-use URL for that offer that expires with it.{"id": "off_01JD7Q8S4M5W2X3Y4Z6A7B8C9D","object": "offer","embed_url": "https://embed.getphew.com/o/off_01JD7Q8S4M5W2X3Y4Z6A7B8C9D?t=eyJ2Ijox...","items": [{ "reference": "SKU-CBX-48", "eligible": true, "plans": ["..."] }]}If no item is
eligible, there’s nothing to show: skip the iframe. -
Render the iframe where the offer should appear.
<iframeid="phew-offer"src="https://embed.getphew.com/o/off_01JD7Q8S...?t=eyJ2Ijox..."title="Product protection from Phew"sandbox="allow-scripts allow-same-origin allow-popups"style="width: 100%; border: 0"></iframe> -
Listen for messages, always checking the origin:
const frame = document.getElementById("phew-offer");window.addEventListener("message", (event) => {if (event.origin !== "https://embed.getphew.com" || event.source !== frame.contentWindow) return;const message = event.data;if (message.type === "phew:resize") frame.style.height = `${message.height}px`;if (message.type === "phew:change") {// message.selections: [{ reference, plan }], message.total: premium in minor units}}); -
Create the policy on your server when the order is paid, with the offer ID and the selections, using
POST /v1/policies.
Messages
Section titled “Messages”type |
Fields | When |
|---|---|---|
phew:ready |
offer |
The offer has rendered |
phew:resize |
height |
The content height changed; set the iframe height to match |
phew:change |
offer, selections, total |
The customer chose a plan, changed plan or declined |
phew:error |
code |
The offer couldn’t load; hide the iframe and continue |
Messages are sent only to the parent window, and the iframe ignores all incoming messages except phew:update, which
you can send with a new embed_url after the cart changes.
Styling
Section titled “Styling”Pass appearance when you create the offer, and the embed renders in your colours and type:
{ "currency": "NOK", "market": "NO", "items": ["..."], "embed": { "appearance": { "theme": "light", "color_primary": "#0b5fff", "border_radius": 10, "font": "inter" } }}Mobile apps
Section titled “Mobile apps”Load embed_url in a web view (WKWebView on iOS, WebView on Android). Messages are delivered through the platform’s
script bridge: register a handler named phew and you’ll receive the same message objects as on the web.
Why banks choose the embed
Section titled “Why banks choose the embed”- Isolation. The offer runs in its own origin. It can’t read your DOM, cookies, storage or form fields, and you don’t load any Phew script.
- Strict CSP. You only need
frame-src https://embed.getphew.com. - Server-controlled. The embed can only show an offer your server created, with your credentials, for that cart.
- Signed and short-lived.
embed_urlis signed, bound to one offer, and expires with it.