Element events
Cimplify Elements communicate with the parent page via `window.postMessage`. Below is the full event union sent _from_ the iframe, defined as `IframeToParentMessage` in `@cimplify/sdk`. The parent-side controller in the SDK already validates and dispatches these for you; this page is for when you want to wire them up directly.
Origin and routing
Iframe messages are signed with a per-element nonce URL param. The parent controller in elements.ts verifies origin (must be cimplify.io or a subdomain over HTTPS, or localhost) and matches nonce or event.source before dispatching. If you handle messages yourself, do the same.
function isAllowedOrigin(origin: string): boolean {
const url = new URL(origin);
if (url.hostname === "localhost" || url.hostname === "127.0.0.1") return true;
if (url.protocol !== "https:") return false;
return url.hostname === "cimplify.io" || url.hostname.endsWith(".cimplify.io");
}Lifecycle events
ready
First message after iframe load. Carries the initial content height. The parent should respond with an init message containing businessId, publicKey, and any appearance/order options.
{ type: "ready", height: 412 }height_change
Emitted whenever the iframe content resizes. Apply the value to the iframe's style.height for seamless embedding.
{ type: "height_change", height: 564 }Authentication events
requires_otp
The customer entered a contact and an OTP has been dispatched. The masked contact is suitable for a "code sent to ***123" status line.
{ type: "requires_otp", contactMasked: "+233·····001" }contact_provided
The OTP request failed (or was bypassed) but the customer provided a contact you can carry through to a guest checkout.
{
type: "contact_provided",
contact: "jane@example.com",
contactType: "email" // "email" | "phone"
}authenticated
OTP verified. The token is short-lived; the parent controller automatically broadcasts set_token to other Elements (Address, Payment, Account) so they pick up the same session.
{
type: "authenticated",
accountId: "acc_…",
customerId: "cus_…",
token: "lk_…",
customer: { name: "Jane", email: "jane@…", phone: "+233…" }
}token_refreshed
Background re-issue of the Link token. The new value supersedes the old one.
{ type: "token_refreshed", token: "lk_…" }logout_complete
Customer signed out. The parent controller clears address/payment/customer state and aborts any in-flight checkout.
{ type: "logout_complete" }Form-state events
address_selected / address_changed
Emitted when the customer picks a saved address (address_selected) or edits a new one (address_changed). saveToLink only appears on address_changed and indicates whether the customer ticked "save to Link".
{
type: "address_changed",
address: {
street_address: "12 Independence Ave",
city: "Accra",
region: "Greater Accra",
country: "GH",
/* optional: latitude, longitude, apartment, postal_code, phone_for_delivery, delivery_instructions */
},
saveToLink: true
}payment_method_selected
Customer chose a payment method. method.type is "mobile_money", "card", or "cash". saveToLink reflects the "remember me" checkbox state.
{
type: "payment_method_selected",
method: {
type: "mobile_money",
provider: "mtn",
phone_number: "+233200000001"
},
saveToLink: true
}order_type_changed
Customer toggled between delivery, pickup, or dine-in. Emitted only by CheckoutElement.
{ type: "order_type_changed", orderType: "delivery" }request_submit
Customer pressed the in-iframe submit button (when renderSubmitButton is enabled). The parent should respond by calling elements.processCheckout(...).
{ type: "request_submit" }Checkout events
checkout_status
Non-terminal lifecycle transition. See checkout lifecycle for the full state list.
{
type: "checkout_status",
status: "awaiting_authorization",
context: {
display_text: "Approve the prompt on your phone",
authorization_type: "otp",
provider: "mtn"
}
}checkout_complete
Terminal. Either success: true with an order, or success: false with a recoverable/non-recoverable error.
// Success
{
type: "checkout_complete",
success: true,
order: { id, order_number, status, total, currency },
enrolled_in_link: true
}
// Failure
{
type: "checkout_complete",
success: false,
error: {
code: "PAYMENT_DECLINED",
message: "The provider declined the payment.",
recoverable: true
}
}Error event
Anything that doesn't fit a more specific event: initialization failure, lost connectivity, validation errors before submit. Always carries a code and human-readable message.
{ type: "error", code: "BUSINESS_ID_REQUIRED", message: "…" }Parent → iframe messages
For completeness, the parent posts these (ParentToIframeMessage):
| Type | Sent by parent to… |
|---|---|
init | seed businessId, publicKey, appearance, orderTypes |
set_token | broadcast a Link token to non-auth Elements |
set_cart | push the cart summary into CheckoutElement |
get_data | request current address/payment selection |
refresh_token | force a Link token refresh |
logout | sign the customer out |
process_checkout | start a payment flow |
abort_checkout | cancel an in-flight payment |
Next
- Checkout lifecycle: The states
checkout_statusmoves through - Vanilla Elements: Wire postMessage yourself
Checkout lifecycle
Every Cimplify checkout (embedded iframe, hosted Pay session, or controlled React Element) passes through the same ordered set of states. Whether you observe them via `onStatusChange`, the `checkout_status` postMessage event, or the `on_status_change` callback on `processCheckout()`, the names and order are identical.
Catalogue
Browse products, variants, categories, collections, bundles, composites, deals, and price quotes. Read-only on the public client; safe to call from any environment.