Zum Hauptinhalt springen

Embedded Hosted Checkout - COPE-Zahlung direkt in deiner Seite

Embedded Hosted Checkout lässt deine Seite ihr Layout behalten, während COPE das Zahlungsformular in einem iFrame rendert. Deine Seite besitzt das umgebende Erlebnis. COPE übernimmt Checkout-Route, Zahlungsabwicklung, Steuerfinalisierung, Bestellerstellung und alle käuferseitigen Endstatus.

Nutze Embedded Checkout wenn du einen eigenen Storefront oder ein In-Page Checkout Modal benötigst. Nutze Redirect Checkout wenn die einfachste Integration ausreicht oder ein Browser den iFrame-Flow blockiert.

📄 Die vollständige Dokumentation findest du hier: [Embedded hosted checkout - COPE]


Voraussetzungen

Bevor du Embedded Checkout Sessions erstellst:

  • Publishable Key für das COPE Business erstellen

  • Jede Parent-Page-Origin registrieren, die den iFrame hosten soll (z. B. https://shop.example.com)

  • Nur den Origin angeben: Schema, Host und optionaler Port – kein Pfad, keine Query, kein Fragment

  • Nur HTTPS in Produktion (http://localhost nur für Entwicklung)

  • Erlaubte Success- und Cancel-URLs für Redirect-basierte Completion oder Fallback konfigurieren

Die Parent-Origin muss exakt mit dem Browser-Origin der Seite übereinstimmen, die checkout({ embed_origin }) aufruft. https://shop.example.com und https://www.shop.example.com sind unterschiedliche Origins.


Integration

ts

import { CopeCart } from "@copecart/sdk"  const cope = new CopeCart({   publishableKey: "cope_pk_live_...", })  async function openEmbeddedCheckout(productId: string, planId: number) {   const cart = await cope.createCart({ currency: "EUR" })    await cope.addLine(cart.id, {     product_id: productId,     plan_id: planId,   })    await cope.setBuyerIdentity(cart.id, {     email: "buyer@example.com",     tax_location: { country: "DE", postal_code: "10115" },   })    await cope.reprice(cart.id)    const checkout = await cope.checkout(cart.id, {     embed_origin: window.location.origin,     success_url: "https://shop.example.com/thank-you",     cancel_url: "https://shop.example.com/cart",     consents: [{ type: "buyer_tos" }],   })    return cope.mountCheckout("#cope-checkout-frame", checkout, {     fallback: "redirect",     onReady: () => showCheckoutFrame(),     onResize: ({ height }) => resizeContainer(height),     onSuccess: () => showOrderConfirmation(),     onCancel: () => closeCheckoutFrame(),     onError: ({ code, retryable }) => reportCheckoutError(code, retryable),   }) }

Die Checkout-Response enthält beide URL-Varianten:

Feld

Bedeutung

checkout.checkoutUrl

Redirect-Route, z. B. https://app.cope.com/checkout/:token

checkout.embedCheckoutUrl

iFrame-Route, z. B. https://app.cope.com/checkout/embed/:token

checkout.embedOrigin

Bestätigter Parent-Origin von COPE

mountCheckout() verweigert den Mount wenn checkout.embedOrigin fehlt oder nicht exakt mit window.location.origin übereinstimmt.


Mount-Verhalten

mountCheckout() erstellt den iFrame automatisch:

  • srccheckout.embedCheckoutUrl

  • titleCOPE checkout

  • allowpayment * für Browser-Wallet-Support

  • referrerPolicyno-referrer

  • width100%

  • min-height720px

  • Kein sandbox-Attribut

Den iFrame nicht manuell bauen – das SDK führt auch den Trusted Mount Handshake durch und filtert alle iFrame-Messages nach Origin, Source Window, Message Source und Version.


Fallback

fallback: "redirect" setzt einen sicheren Fallback, wenn der iFrame den Trusted Ready Handshake nicht vor readyTimeoutMs abschließt:

ts

cope.mountCheckout("#cope-checkout-frame", checkout, {   fallback: "redirect",   readyTimeoutMs: 8000,   onFallbackRedirect: () => {     console.log("Fallback auf Hosted Checkout")   }, })

Ohne expliziten Fallback (fallback: "error") ruft das SDK auf:

ts

onError({ code: "load_failed", retryable: true })

Events

Der iFrame sendet sanitized Events an das SDK. Callback-Payloads enthalten keine Checkout-Credentials, Payment Client Secrets oder Buyer PII.

Event

Bedeutung

onReady

iFrame geladen und bereit

onSuccess

Zahlung erfolgreich abgeschlossen

onCancel

Nutzer hat abgebrochen

onError

Fehler im Zahlungsprozess (inkl. retryable-Flag)

onResize

iFrame-Höhe hat sich geändert

Für den rohen Event-Stream:

ts

cope.mountCheckout("#cope-checkout-frame", checkout, {   onMessage: (event) => {     analytics.track("cope_checkout_embed_event", event)   }, })

Sicherheitsmodell

Embedded Checkout hat zwei Autorisierungsschichten:

  1. COPE validiert embed_origin gegen die Business-Allowlist beim Erstellen der Checkout Session

  2. Die iFrame-Route validiert denselben Embed-Vertrag vor dem Rendern des Zahlungsformulars

Das SDK sendet die Mount-Message mit einem spezifischen targetOrigin – niemals *. iFrame-Messages werden nur akzeptiert wenn event.origin, event.source, event.data.source (cope.checkout) und event.data.version (1) übereinstimmen.


Use Cases

In-Page Checkout Modal
Das Zahlungsformular öffnet sich als Overlay innerhalb deiner Seite. Kein Redirect, kein Kontextverlust – der Nutzer bleibt in deiner Navigation und deinem Layout.

SaaS Upgrade Flow
Ein Nutzer upgradet von Free auf Pro direkt im Dashboard. mountCheckout() rendert das Zahlungsformular als iFrame in einem Modal oder einem dedizierten Bereich der Seite, ohne den aktuellen State zu verlieren.

Custom Storefront
Du baust eine vollständig eigene Produktseite mit eigenem Branding – COPE rendert nur das Zahlungsformular im iFrame. Deine Seite behält vollständige Kontrolle über Layout, Farben und Nutzererlebnis.

High-Conversion Checkout
Jeder Redirect ist ein potenzieller Absprungpunkt. Embedded Checkout eliminiert diesen Reibungspunkt und hält den Nutzer auf deiner Seite bis zur erfolgreichen Zahlung.


Troubleshooting

Fehler

Ursache

Lösung

embed_origin_not_allowed

Origin nicht registriert

Exakte Parent-Origin registrieren, neue Session erstellen

mountCheckout requires checkout.embedOrigin

checkout() ohne embed_origin aufgerufen

embed_origin: window.location.origin übergeben

Checkout embed origin ... does not match

Session für anderen Origin erstellt

checkout() und mountCheckout() auf derselben Origin aufrufen

iFrame wird nie ready

Token abgelaufen, geblockt oder Handshake fehlgeschlagen

fallback: "redirect" nutzen, onError und Browser-Konsole prüfen

Browser-Wallet nicht verfügbar

Wallet-Domain-Registrierung unvollständig

allow="payment *" prüfen, Wallet-Setup für beide Origins verifizieren

Hat dies deine Frage beantwortet?