Lifecycle events
embed.js validates each message's origin against the iframe it owns, then
re-dispatches these as CustomEvents on your window. Wire a handler with
addEventListener:
Code
Every event's detail carries the fields listed below plus frame, the source
<iframe> element, so a page with several embeds can tell which one fired. These
events carry ids, the plan slug, and a coarse status only; no email or other PII
crosses the iframe boundary.
ledgerbee:embed:pageLoaded
The cards finished their first data-driven paint. Reveal the frame or drop your loading skeleton.
No payload beyond frame.
ledgerbee:embed:checkoutInitiated
The visitor clicked a buy CTA, fired just before the break-out to checkout. In target=callback mode it fires instead of opening anything, so your listener owns the buy action (e.g. route to your signup funnel first, then resume into the bound checkout).
| Field | Description |
|---|---|
planVersionId | The plan version being purchased. |
planItemId | The chosen item within the plan. |
vanity | The plan's public vanity slug — build the resume URL …/embed/checkout/<vanity>/<planItemId> straight from it. |
deferred | true only in target=callback mode, where the iframe opened nothing and your listener owns the action; absent otherwise. |
ledgerbee:embed:customCtaClicked
The visitor clicked a custom CTA card's button (a "talk to sales" / "book a demo" card, not a checkout). Fired only when the embed was generated with ctaCallback=1: the iframe navigates nothing and hands the click to your page.
| Field | Description |
|---|---|
planVersionId | The plan version the card belongs to. |
planItemId | The card item that was clicked. |
vanity | The plan's public slug, so you can correlate which embed fired. |
ctaLink | The operator-configured link the card would otherwise have followed (absolute URL, relative path, mailto:, tel:), or null if unset. Navigate to it yourself, or open your own chat / contact UI instead. |
ledgerbee:embed:checkoutConfirmed
The in-frame checkout finished — swap the frame for your own thank-you or remove the iframe. A bound OnPay checkout does not fire this (it breaks out to OnPay to take payment first); reconcile that path via webhooks instead.
| Field | Description |
|---|---|
planVersionId | The plan version that was purchased. |
planItemId | The item that was purchased. |
status | How the in-frame flow finished: CONFIRMED (subscribed directly — safe to remove the frame), PENDING_VERIFICATION (anonymous buyer, magic link sent — keep the frame so they can read "check your inbox"). |
ledgerbee:embed:checkoutError
An in-frame checkout attempt failed. The buyer still sees the actionable message inside the frame; hook this for analytics or your own retry chrome. A coarse reason only — never the buyer's email, the raw backend error, or any PII.
| Field | Description |
|---|---|
planVersionId | The plan version the attempt was for. |
planItemId | The item the attempt was for. |
reason | Coarse, non-sensitive classification: SESSION_MINT_FAILED (the checkout session could not be created — self-signup turned off mid-flow, or a transient 5xx), CONFIRM_FAILED (a confirm submit was rejected — expired or double-spent session, stale terms, invalid start date). |
ledgerbee:embed:checkoutClosed
The buyer closed a forced single-item checkout (Cancel/Back on a …/embed/checkout/<vanity>/<planItemId> or gated …/by-id/… surface, which has no cards to fall back to, so it lands on a terminal "Checkout closed" state). The pricing-card surface instead returns the buyer to its cards and emits nothing. A failed session mint emits checkoutError, not this — you never see both for one attempt.
| Field | Description |
|---|---|
planVersionId | The plan version that was abandoned. |
planItemId | The item that was abandoned. |
When no event fires
checkoutError is session-mint/confirm-specific — it covers in-frame checkout
attempts only. If the browser refuses to frame the embed at all (CSP
frame-ancestors — your origin isn't on the partner-origin allowlist), no
embed event fires and pageLoaded never arrives. Detect it by the absence of
pageLoaded plus the console error, not by listening for an error event. See
Errors.