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) |
quoteTokenis never present inevent.detailor onwindow. 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.