Widget Events

Document marker: CLAIMFUL_WIDGET_EVENTS_SENTINEL

The Claimful embedded widget dispatches five CustomEvent instances on window during its lifecycle. These are the authoritative ADR-0038-frozen shapes — downstream listeners and analytics pipelines must target these exact payloads.

Note on legacy Table 10. The historical integration manual (Table 10) listed divergent key names (offerId, feeAmount, feeCurrency, selected). Those names are incorrect — the shapes documented here (ratified from ADR 0038 and the widget source) are the canonical contract. Table 10 is being corrected to match (cross-reference G10).


Event reference

claimful:ready

Fired once the widget has initialised and confirmed your merchant account. Safe to begin checkout-flow orchestration from this point.

window.addEventListener('claimful:ready', (e: CustomEvent) => {
  const { merchantId, version } = e.detail;
  // merchantId: string — your merchant identifier
  // version: string   — widget semver (e.g. "1.3.0")
});

Detail shape

| Field | Type | Description | | ------------ | -------- | ------------------------------------- | | merchantId | string | Your merchant identifier | | version | string | Widget semver string |


claimful:opted-in

Fired when the customer accepts the protection offer. Use this to record acceptance and pass the quote identifier to your order-confirmation logic.

window.addEventListener('claimful:opted-in', (e: CustomEvent) => {
  const { quoteId, fee } = e.detail;
  // quoteId: string — opaque protection-request identifier (Crockford Base32)
  // fee: number     — protection fee in integer cents (e.g. 599 = $5.99)
});

Detail shape

| Field | Type | Description | | --------- | -------- | ------------------------------------------------ | | quoteId | string | Protection-request identifier | | fee | number | Protection fee in integer cents (BIGINT) |

quoteToken is never present in event.detail or on window. It is delivered exclusively as an out-of-band response header and kept in the widget's internal closure (ADR 0038 §"quoteToken NEVER in payloads").


claimful:declined

Fired when the customer explicitly declines the protection offer.

window.addEventListener('claimful:declined', (e: CustomEvent) => {
  const { quoteId, reason } = e.detail;
  // quoteId: string   — the offer that was declined
  // reason?: string   — categorical decline reason (analytics-safe)
});

Detail shape

| Field | Type | Description | | --------- | ------------------ | ------------------------------------------------------------- | | quoteId | string | Protection-request identifier | | reason | string (optional)| Categorical reason — 'consumer_declined' for explicit declines |

'consumer_declined' is the only consumer-initiated decline reason in the current widget. It is non-PHI and safe to send to merchant analytics.


claimful:changed

Fired on every internal state transition. Useful for observability and multi-step checkout orchestration.

window.addEventListener('claimful:changed', (e: CustomEvent) => {
  const { from, to } = e.detail;
  // from: WidgetState — previous state
  // to:   WidgetState — new state
});

Detail shape

| Field | Type | Description | | ------ | ------------- | ------------------- | | from | WidgetState | Previous state name | | to | WidgetState | New state name |

WidgetState values: 'idle' | 'loading' | 'offer' | 'opted-in' | 'declined' | 'ineligible-hidden' | 'error'


claimful:error

Fired when the widget encounters a non-recoverable error (network failure, merchant misconfiguration, or exhausted retries).

window.addEventListener('claimful:error', (e: CustomEvent) => {
  const { code, message } = e.detail;
  // code: ErrorCode — machine-readable error category
  // message: string — human-readable detail (safe to log)
});

Detail shape

| Field | Type | Description | | --------- | ----------- | -------------------------------------- | | code | ErrorCode | Machine-readable error category | | message | string | Human-readable detail string |

ErrorCode values

| Code | When | | -------------------- | --------------------------------------------------------- | | configure_invalid | merchantId missing or malformed at configure-time | | mint_failed | Quote API returned a non-2xx, non-422 status | | network_error | Fetch threw (offline, DNS failure, etc.) |


Frozen contract

These payloads are frozen by ADR 0038 and governed by the Widget API public commitment (ADR 0039). Any breaking change requires a new widget major version and the 90-day overlap window per the SDK semver covenant.