Integrate faster without weakening identity.
Use typed server and mobile clients, Beta native UI kits, a versioned Web Widget, or a privacy-minimized AI-native rewards surface without weakening identity or value controls.
Use only what is actually published.
A dependency-free, typed API 1.13 server client with all 121 operations, safe retries, exact ledger-close evidence, 40 webhook event types, Reward Gifts frameworks, and synthetic Shopify and Klaviyo mapping conformance. Public npm-registry availability and provider connectivity are not claimed.
Review the SDK →A typed, SSR-safe Web Widget v1 wrapper for React 18.2 and 19 with session handoff, events, theming, and an imperative sign-out control. Public npm-registry availability is not claimed.
Review the React wrapper →A guided command line for a persisted official-origin Sandbox proof and common membership, commerce, governed value, import, operation, audit, analytics, ledger-close, webhook, program, export, and widget workflows. It writes API 1.11 project configuration and does not claim command parity with all 121 API 1.13 operations.
Install from the CLI guide →A dependency-free Swift Package for iOS 15+ that calls the merchant's authenticated backend gateway and includes Native UI Kit 1.0.0-beta.1.
Install the iOS SDK →A Kotlin library for Android API 23+ that calls the merchant's authenticated backend gateway and includes Native UI Kit 1.0.0-beta.1. Coroutines remain its only runtime dependency.
Install the Android SDK →SwiftUI and Android View components for balance, tier progress, reward cards and catalog, activity, and a composed rewards home. They emit intent; they do not move value.
Build a native surface →A versioned browser loader, a Shadow DOM host with a sandboxed hosted iframe, four widget families, guest mode, and signed personalized mode.
Copy the embed →Semantic balance, tier, catalog, and activity components plus confirmed, idempotent entitlement actions under the existing widget session and origin boundary.
Integrate the semantic surface →A POST-only typed surface for selected reads and value lifecycle mutations. It delegates to existing scopes and state machines rather than claiming full API parity.
Open GraphQL guide →121 environment-scoped API 1.13 operations across 106 paths, represented by OpenAPI 3.1 for trusted server integrations.
Open reference →Configure, preview, validate, publish, pause, and version a Web Widget deployment identifier.
Publish safely →One current API. Separate package release states.
API compatibility and package maturity are different facts. The checked-in OpenAPI document is the source for the public HTTPS JSON API contract; the rendered API reference uses that same document.
HTTPS JSON API + OpenAPICurrent: 1.13.0. The account-free contract publishes 121 operations across 106 paths and 40 privacy-minimized webhook event types.
GraphQL APIBeta · selected lifecycle. POST-only JSON over HTTPS with checked-in SDL, bounded execution, one top-level mutation, and delegation to the existing scope and value paths. It does not claim 121-operation parity.
@loyumi/sdk2.3.0 → API 1.13.0. Official stable downloadable ESM server package with all 121 operations, 40 webhook event types, Reward Gifts frameworks, portability 1.6, and merchant-operated Shopify 2026-07 and Klaviyo 2026-07-15 mapping conformance for Node.js 20+ and compatible Web Crypto edge runtimes.
@loyumi/cli1.5.1 · API 1.11 project config. Stable downloadable release for common integration and operating workflows, including the opt-in official-origin Sandbox proof, with portability 1.6. It does not claim command parity with all 121 API 1.13 operations.
Web Widgetv1 · Available Beta. Use /widgets/v1/ for compatible loader fixes or the immutable /widgets/v1.0.0/ loader with its published SRI. That freezes the merchant-page loader, not the hosted iframe runtime.
@loyumi/react1.0.0 → Web Widget v1. Official stable downloadable wrapper, typed and SSR-safe for React 18.2 and 19, with event callbacks, theming, session handoff, and optional immutable loader URL plus SRI; public npm-registry availability is not claimed.
LoyumiMobile for iOS1.1.0 · stable source distribution. Swift Package for iOS 15+ and macOS 12+ with typed merchant-gateway calls and additive Native UI Kit 1.0.0-beta.1. It has no Loyumi API-key setting and is not claimed on a package registry.
Loyumi Mobile for Android1.1.0 · stable source distribution. Kotlin library for Android API 23+ with typed merchant-gateway calls, coroutines, and additive Native UI Kit 1.0.0-beta.1 built with framework Views. It has no Loyumi API-key setting and is not claimed on a package registry.
AI-native rewards surface1.0 · Beta. Versioned, privacy-minimized semantic JSON derived from a published widget deployment, with a checked-in JSON Schema and confirmed, idempotent native-entitlement redemption action.
Portability export1.6.0 · 53 collections. Preserves migration-critical business state, including durable Reward Gifts evidence, while excluding and naming the authority and runtime records that must be reissued.
Integration startersOne synthetic mapping pack plus three contract-reviewed patterns. Shopify and Klaviyo mapping conformance, commerce earn and return, recipient-bound Reward Gifts, and signed webhooks are published with merchant-owned boundaries. The provider mapping status remains configuration_required; a native or connected provider integration and broad turnkey connector catalog are not claimed.
Typed API 1.13 server integration with guarded retries.
@loyumi/sdk covers all 121 Public API 1.13.0 operations with typed requests and responses, Reward Gifts frameworks, explicit membership, exact ledger-close evidence, cursor-paged back-office queries, 40 lifecycle webhook types plus verification, portability schema 1.6.0, and merchant-operated Shopify and Klaviyo mapping helpers. It retries reads and idempotency-protected mutations safely; member updates, widget session creation, and one-time code exchange deliberately never retry.
npm install --save-exact https://docs.loyumi.com/downloads/loyumi-sdk-2.3.0.tgzSHA-256 6ae6ca12753af4168e4cd3a041d9cd4d153d005ae790320ef2a316d3af6611a2The package manifest names the downloaded artifact @loyumi/sdk, so import from that package name after installation. It is ESM-only, requires Node.js 20 or a compatible Web Crypto edge runtime, and belongs only in trusted server code. Commit the resulting lockfile and do not copy dist files into browser or mobile bundles.
import { LoyumiClient } from "@loyumi/sdk";
const loyumi = new LoyumiClient({
apiKey: process.env.LOYUMI_API_KEY!,
environment: process.env.LOYUMI_ENVIRONMENT_ID!,
});
const member = await loyumi.getMember("<external-customer-id>");await loyumi.enrollMemberProgram(
"<external-customer-id>",
"<program-id>",
{
consentStatus: "opted_in",
noticeVersion: "<rewards-notice-version>",
evidence: { source: "<consent-capture-channel>" },
},
{ idempotencyKey: "<stable-enrollment-key>" },
);
await loyumi.unenrollMemberProgram(
"<external-customer-id>",
"<program-id>",
{
reason: "<approved-withdrawal-reason>",
evidence: { source: "<withdrawal-channel>" },
},
{ idempotencyKey: "<stable-unenrollment-key>" },
);postPurchase + postReturnTypes receipt-time and pinned event-time earning plus original-line return evidence without falling back to untyped JSON.
Shopify + Klaviyo mapping helpersNormalize HMAC-gated Shopify 2026-07 webhook payloads, build credential-free Klaviyo 2026-07-15 requests, and run eight synthetic local vectors while status remains configuration_required.
LoyumiRewardGiftExperienceFrameworkOrchestrates invitation-first, recipient-bound catalog-entitlement gifts across separate value, Widget, delivery, fulfillment, and recovery authorities.
createMember + enrollMemberProgram + unenrollMemberProgramSeparates identity from explicit consent and zero-value program exit without erasing governed history.
listTransactions + getTransactionSearches by customer, program, event, source reference, state, or time and opens balanced entry detail.
getLedgerCloseReportReturns exact decimal-string roll-forward and double-entry controls, policy valuation, readiness lights, and a deterministic evidence hash.
webhook endpoint + verification methodsCreates, rotates, inspects, retries, and verifies 40 privacy-minimized public lifecycle event types under separate scopes.
exportPortabilityBundleReads portability schema 1.6.0 across all 53 published business-state collections.
Typed React bindings for Web Widget v1.
@loyumi/react is a stable SSR-safe wrapper for React 18.2 and 19 around the shipped custom element. It types the four widget event families, same-origin sessionEndpoint, supported theme variables, and the imperative clearSession() sign-out boundary. It contains no Loyumi API credential and does not infer customer identity.
npm install --save-exact https://docs.loyumi.com/downloads/loyumi-react-1.0.0.tgzSHA-256 89903851bc27ba38ebade9cf0e88b3a82745376ed46968f0c35d7e84c9860c5c"use client";
import { useRef } from "react";
import { LoyumiRewards, type LoyumiRewardsHandle } from "@loyumi/react";
export function Rewards({ cspNonce }: { cspNonce: string }) {
const widget = useRef<LoyumiRewardsHandle>(null);
async function signOut() {
widget.current?.clearSession();
await endMerchantSession();
}
return <LoyumiRewards
ref={widget}
deployment="wdg_…"
sessionEndpoint="/api/loyumi/widget-session"
nonce={cspNonce}
onAction={({ action }) => handleLoyaltyAction(action)}
style={{ "--loyumi-accent": "#176348" }}
/>;
}Framework-native rewards views, with value movement still behind your gateway.
The stable iOS and Android 1.1.0 source packages include additive Beta presentation components. iOS uses SwiftUI. Android uses framework View classes, not a claimed Jetpack Compose package. Both consume the SDK's typed member, catalog, and activity models and return reward-selection intent to the merchant app.
BalanceAvailable value plus pending and reserved context.
Tier progressCurrent tier, progress, and distance to the next threshold.
Reward cardName, description, point cost, availability, and a selection callback.
Reward catalogA typed collection with its own empty and retry states.
ActivityCustomer-facing activity rows using SDK models.
Rewards homeA composed balance, tier, catalog, and activity surface with separate retry callbacks.
Theme and states
- Accent, on-accent, surface, text, secondary text, separator, radius, and spacing tokens
- Loading, content, empty, and failure as explicit values
- Platform-standard typography and localized point formatting
- Independent retry callbacks for member, catalog, and activity
Accessibility hooks
- Descriptive balance, tier-progress, reward-action, and activity semantics
- Platform heading traits where available
- At least 44-point iOS and 48-dp Android action targets
- Merchant remains responsible for contrast, localization, VoiceOver/TalkBack, text scaling, and device testing
Add loyalty to iOS without putting a Loyumi secret on the phone.
LoyumiMobile is a dependency-free Swift Package for iOS 15+ and macOS 12+. It gives the app typed member summary, explicit program enrollment and unenrollment, activity, reward catalog, quote, reserve, commit, release, and reverse calls against a merchant-owned backend gateway.
- 1
Download and verify
Unpack the exact source archive. In Xcode choose File → Add Package Dependencies → Add Local, select the folder containing
Package.swift, and addLoyumiMobileto the app target. - 2
Build the merchant gateway first
Expose the documented
/loyalty/v1/…routes from your authenticated backend. The backend derives member identity from the signed-in customer and calls Loyumi with its least-privilege server credential. - 3
Give the SDK only a customer session
The token provider returns your short-lived, audience-bound customer session. It never returns a Loyumi API key.
import LoyumiMobile
let loyalty = LoyumiMobileClient(
configuration: try LoyumiMobileConfiguration(
backendURL: URL(string: "https://<merchant-host>/api")!,
tokenProvider: {
try await customerSessionStore.loyaltyToken()
}
)
)
let summary = try await loyalty.memberSummary()
let rewards = try await loyalty.catalog(limit: 25)let enrollment = try await loyalty.enrollInProgram(
programID: "<program-id>",
input: .init(
noticeVersion: "<rewards-notice-version>",
evidence: ["source": "<consent-capture-channel>"]
),
options: .init(idempotencyKey: "<stable-enrollment-key>")
)
let exit = try await loyalty.unenrollFromProgram(
programID: "<program-id>",
input: .init(
reason: "<approved-withdrawal-reason>",
evidence: ["source": "<withdrawal-channel>"]
),
options: .init(idempotencyKey: "<stable-unenrollment-key>")
)import SwiftUI
import LoyumiMobile
LoyumiRewardsHomeView(
member: .content(summary.value),
catalog: .content(rewards.value),
activity: .content(activity.value),
unit: summary.value.balance.unit,
theme: .loyumi,
onSelectedReward: { reward in
// Show your review + confirmation screen. Do not redeem here.
pendingReward = reward
},
onRetryMember: reloadMember,
onRetryCatalog: reloadCatalog,
onRetryActivity: reloadActivity
)Use LoyumiBalanceView, LoyumiTierProgressView, LoyumiRewardCard, LoyumiRewardCatalogView, or LoyumiActivityView when the composed home is more than the screen needs. Supply .loading, .content, .empty, or .failure explicitly so the customer never sees invented placeholder value.
SHA-256 0aff636dfdf5265a8dae88db3b2d285aeba329b17079449c39548e993b38b63eAdd loyalty to Android through the same safe gateway.
com.loyumi.mobile is a Kotlin library for Android API 23+ with Kotlin coroutines as its only runtime dependency. It exposes the same typed merchant-gateway member, explicit program enrollment and unenrollment, activity, catalog, quote, reserve, commit, release, and reverse lifecycle as the iOS SDK.
- 1
Download and verify
Unpack the exact source archive beside the app, include it as
:loyumi-mobile, and add the project dependency. The app's root build supplies its Android and Kotlin plugin versions. - 2
Use the same reviewed gateway contract
The merchant backend authenticates the customer, derives identity, authorizes value movement, and keeps the Loyumi credential server-side.
- 3
Call from lifecycle-aware coroutines
Give the SDK only a short-lived merchant customer session and cancel work with the owning lifecycle.
// settings.gradle.kts
include(":loyumi-mobile")
project(":loyumi-mobile").projectDir = file("../loyumi-android-1.1.0")
// app/build.gradle.kts
dependencies {
implementation(project(":loyumi-mobile"))
}val loyalty = LoyumiMobileClient(
LoyumiMobileConfiguration(
backendUrl = "https://<merchant-host>/api",
tokenProvider = {
customerSessionStore.loyaltyToken()
},
),
)
viewModelScope.launch {
val summary = loyalty.memberSummary()
val rewards = loyalty.catalog(limit = 25)
}val enrollment = loyalty.enrollInProgram(
programId = "<program-id>",
input = MemberProgramEnrollmentRequest(
noticeVersion = "<rewards-notice-version>",
evidence = mapOf("source" to "<consent-capture-channel>"),
),
options = LoyumiMutationOptions(idempotencyKey = "<stable-enrollment-key>"),
)
val exit = loyalty.unenrollFromProgram(
programId = "<program-id>",
input = MemberProgramUnenrollmentRequest(
reason = "<approved-withdrawal-reason>",
evidence = mapOf("source" to "<withdrawal-channel>"),
),
options = LoyumiMutationOptions(idempotencyKey = "<stable-unenrollment-key>"),
)val rewardsHome = LoyumiRewardsHomeView(requireContext()).apply {
theme = LoyumiRewardsTheme()
onRewardSelected = { reward ->
// Show your review + confirmation screen. Do not redeem here.
viewModel.reviewReward(reward)
}
onRetryMember = viewModel::reloadMember
onRetryCatalog = viewModel::reloadCatalog
onRetryActivity = viewModel::reloadActivity
}
rewardsHome.submit(
member = LoyumiSurfaceState.Content(summary.value),
catalog = LoyumiSurfaceState.Content(rewards.value),
activity = LoyumiSurfaceState.Content(activity.value),
unit = summary.value.balance.unit,
)Use LoyumiBalanceView, LoyumiTierProgressView, LoyumiRewardCard, LoyumiRewardCatalogView, or LoyumiActivityView directly when the composed home is more than the screen needs. Call submit with Loading, Content, Empty, or Error; the UI kit does not fetch or invent customer value.
SHA-256 452f23950622e9f0f2d22c06c84c262e746417e71adefe09c5e869667c9d286bGive an AI host structured rewards, not screenshots or prompts.
A published Web Widget deployment can also produce a vendor-neutral semantic JSON surface. It contains versioned balance, tier-progress, reward-catalog, and activity components plus explicit action descriptors. The endpoint derives this projection from the same widget runtime, so publication status, exact origin, session permission, customer scope, and rate limits remain authoritative.
const endpoint = new URL(
"https://app.loyumi.com/api/v1/widgets/<deployment-id>/agent/v1",
);
endpoint.searchParams.set("parentOrigin", "https://<approved-merchant-origin>");
const response = await fetch(endpoint, {
headers: {
Accept: "application/json",
// Omit for guest mode. Keep this token in the adapter, not model context.
Authorization: "Widget <origin-bound-widget-session>",
},
});
if (!response.ok) throw new Error("Rewards surface unavailable");
const surface = await response.json();
// Validate against the published JSON Schema before rendering or planning.
console.log(surface.surface.version); // "1.0"
console.log(surface.surface.stability); // "beta"loyumi.balanceAvailable, pending, and reserved values with the program unit, or an explicit sign_in_required state.
loyumi.tier_progressCurrent tier, qualification points, and the next configured threshold, or an explicit sign-in state.
loyumi.reward_catalogBounded published rewards, eligibility, points needed, pagination state, and references to available actions.
loyumi.activityBounded customer-facing event type, point movement, and timestamp without internal transaction IDs.
loyumi.reward.redeemA POST action is returned only for an eligible reward when the signed session may redeem. It binds the exact reward ID and declares confirmation and idempotency requirements.
const action = surface.actions.find(
(item) => item.kind === "loyumi.reward.redeem",
);
await requireCustomerConfirmation({
rewardId: action.input.properties.rewardId.const,
label: action.label,
});
const result = await fetch(new URL(action.href, "https://app.loyumi.com"), {
method: action.method,
headers: {
Authorization: "Widget <same-origin-bound-widget-session>",
"Content-Type": "application/json",
},
body: JSON.stringify({
action: "redeem",
rewardId: action.input.properties.rewardId.const,
confirmed: true,
idempotencyKey: "agent-confirmation:<durable-confirmation-id>",
}),
});Data stays data
- Every merchant-authored label is marked
merchantContentIsData: true - The safety envelope marks merchant content as
untrusted_data - No API secret or signed token is projected, and direct identifiers such as member ID, email, or phone are omitted
- Personalized balances, tier, eligibility, and activity are still customer-sensitive and must remain access-controlled
Actions stay explicit
- Guest mode has no redeem action
- Confirmation must be exactly
true - Reward ID and idempotency key must be strings; the key is stable and 12–160 characters
- Unknown action-body fields are rejected instead of ignored
- The action re-verifies origin, session, permission, deployment, inventory, balance, enrollment, program readiness, and rate limit
Publish once, then add two lines.
Replace wdg_… with a deployment published by Widget Studio. With no customer session, the element deliberately starts in public guest mode.
<script async src="https://docs.loyumi.com/widgets/v1/loyumi.js"></script>
<loyumi-rewards deployment="wdg_…">
<a href="/account/rewards">View rewards</a>
</loyumi-rewards>Public content is easy. Customer value is verified.
Guest catalog
- Published reward catalog and program explanation
- No customer balance, tier, or activity
- No redemption or value-moving action
- Works with the copy-paste embed alone
Signed personalized mode
- Member balance, tier progress, rewards, and activity
- Customer identity mapped by the merchant backend
- The page handles only a single-use code valid for at most 60 seconds
- The signed token stays inside the isolated frame and expires within 10 minutes
Your backend vouches for the customer.
Your merchant backend sends a trusted server request to POST https://app.loyumi.com/api/v1/widget-sessions. Loyumi returns an opaque sessionCode that is single-use and expires in at most 60 seconds. Your same-origin endpoint passes only that code to the loader. The loader hands it to the isolated frame on widgets.loyumi.com, where it is atomically exchanged for an origin-bound signed token. The reusable token stays inside the hosted iframe, lives for no more than 10 minutes, and never enters the merchant page, DOM, URL, storage, analytics, or logs.
// Runs on your server at POST /api/loyumi/widget-session.
export async function POST(request) {
const customer = await requireSignedInCustomer(request);
const { deploymentId, origin } = await request.json();
const response = await fetch(
"https://app.loyumi.com/api/v1/widget-sessions",
{
method: "POST",
headers: {
Authorization: "Bearer <server-api-key>",
"X-Environment": "<environment-id>",
"Content-Type": "application/json",
},
body: JSON.stringify({
deploymentId,
externalCustomerId: customer.id,
origin,
permissions: ["profile:read"],
}),
},
);
return new Response(response.body, {
status: response.status,
headers: {
"Content-Type": "application/json",
"Cache-Control": "no-store",
},
});
}<script async src="https://docs.loyumi.com/widgets/v1/loyumi.js"></script>
<loyumi-rewards
deployment="wdg_…"
session-endpoint="/api/loyumi/widget-session"
>
<a href="/account/rewards">View rewards</a>
</loyumi-rewards>document.querySelector("loyumi-rewards")?.clearSession();- Authenticate the current customer before mapping
externalCustomerId. - Accept
deploymentIdandoriginfrom the loader, but derive the customer ID from your authenticated session. - Configure an exact origin allowlist for every deployment. Match scheme, host, and non-default port; do not use wildcards or suffix matching.
- Request only
profile:readunless this surface truly needs native entitlement redemption; that action also requiresrewards:redeemand a credential withwidgets:redemptions. - Never put a Loyumi API secret or signed session token in a custom-element property, attribute, URL, mobile code, analytics, logs, or screenshots.
- Treat
sessionCodeas one-use delivery material: do not persist or log it, and returnCache-Control: no-store. - Call
clearSession()before ending the merchant login session when the customer signs out or changes account.
Content-Security-Policy:
script-src 'self' https://docs.loyumi.com;
style-src 'self' 'nonce-<per-request-nonce>';
frame-src https://widgets.loyumi.com;
connect-src 'self';Merge these exact sources into an existing CSP rather than replacing the rest of the merchant's policy. For a strict style-src, put the same per-request nonce on the loader <script>; the loader carries it into its Shadow DOM stylesheet. The hosted frame applies its own restrictive CSP and exact frame-ancestors origin policy.
One deployment, the loyalty surfaces customers expect.
Use <loyumi-rewards> for the Studio-composed experience, or one of these exact custom-element tags for a focused surface.
<loyumi-balance>Shows the signed-in member’s available balance. Guest mode renders no personal value.
<loyumi-tier-progress>Shows current status and progress toward the next configured tier.
<loyumi-reward-catalog>Shows the published catalog in guest mode and member eligibility when signed. Direct hosted redemption is deliberately limited to Loyumi-native entitlements; coupons and external fulfillment use a merchant connector.
<loyumi-activity>Shows aggregated member-facing activity only in signed personalized mode, without exposing internal transaction identifiers.
Widget Studio decides which families appear and in what order. The runtime provides accessible loading, empty, error, offline, and success states for each family.
Match the brand without giving away the boundary.
The custom element uses Shadow DOM and the hosted loyalty UI runs in a sandboxed iframe on a dedicated origin, so merchant-page CSS and console cookies cannot cross into its structure. Customize supported design tokens on the host element; private selectors, frame markup, and post-message details are not APIs.
loyumi-rewards {
--loyumi-accent: #176348;
--loyumi-background: #f4f6f4;
--loyumi-surface: #ffffff;
--loyumi-text: #18211d;
--loyumi-radius: 16px;
--loyumi-min-height: 220px;
}The loader emits composed browser events across the Shadow DOM boundary. Event details never include an API secret, session code, or signed session token. For sign_in and view_all_rewards, the loader clicks the fallback link inside <loyumi-rewards> by default. A merchant handler can call event.preventDefault() only when it takes over navigation.
const widget = document.querySelector("loyumi-rewards");
widget.addEventListener("loyumi:ready", () => {
// No detail payload. The isolated runtime is ready.
});
widget.addEventListener("loyumi:loaded", (event) => {
const { personalized, version } = event.detail;
});
widget.addEventListener("loyumi:action", (event) => {
const { action, rewardId } = event.detail;
// Optional: handle sign-in or "view all" yourself.
// Call preventDefault() only when your handler completes navigation.
if (action === "sign_in") {
event.preventDefault();
window.location.assign("/account/login?next=/account/rewards");
}
});
widget.addEventListener("loyumi:error", (event) => {
const { code } = event.detail;
});loyumi:readyNo detail payload. The isolated runtime is ready to receive appearance and the one-time session code.loyumi:loadedDetail contains personalized and version.loyumi:actionDetail contains action (sign_in, view_all_rewards, reward_selected, or reward_redeemed) and an optional rewardId. Fulfillment and value movement remain server-authorized.loyumi:errorDetail contains a typed code for load, session, origin, network, or render failures.Choose compatible fixes or an exact loader artifact.
/widgets/v1/Major-pinned channel. Backward-compatible accessibility, security, and performance fixes can ship within v1 without changing the integration contract.
/widgets/v1.0.0/Immutable merchant-page loader for artifact review and SRI. It still loads the hosted Web Widget v1 iframe/runtime; it does not freeze that full runtime.
A breaking element, attribute, event, event-detail, or documented theme-token change requires a new major loader path.
Before a supported major is retired, Loyumi publishes a notice, migration guide, and end-of-support date. Do not copy an unversioned loader URL.
<script
async
src="https://docs.loyumi.com/widgets/v1.0.0/loyumi.js"
integrity="sha384-Y7E2UevWddDH2ijQE+/3oDT1dlG6MHRZjX2BD6fmRz45hiGUXtMoJKGA78jtDa5k"
crossorigin="anonymous"
nonce="<per-request-csp-nonce>"
></script>Modern by default. Useful when blocked.
Current and previous stable Chrome, Edge, Firefox, and Safari releases.
Currently supported iOS Safari and maintained Android System WebView releases.
Custom Elements, Shadow DOM, postMessage, Fetch, Web Crypto, and CSP nonces. ResizeObserver and random UUIDs have built-in fallbacks.
The fallback link inside the custom element remains ordinary HTML. If JavaScript, the frame, CSP, DNS, or an extension blocks the runtime, customers still have a merchant-controlled rewards destination and the loader emits a typed loyumi:error instead of waiting forever.