brainerce 1.39.0 → 1.42.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -46,6 +46,7 @@ Every Brainerce storefront must include **all mandatory features** below. Featur
46
46
  | Forgot / reset password | `client.forgotPassword()`, `client.resetPassword()` | ✅ |
47
47
  | OAuth sign-in buttons + callback handler | `client.getAvailableOAuthProviders()` | ✅ |
48
48
  | Account area (profile + order history) | `client.getMyProfile()`, `client.getMyOrders()` | ✅ |
49
+ | Loyalty & rewards (points balance + redeem) | `client.getLoyaltyStatus()`, `client.getAvailableRewards()`, `client.redeemLoyaltyReward(id)` | conditional |
49
50
  | Global header: cart count + search autocomplete | `client.getCart()`, `client.getSearchSuggestions(query)` | ✅ |
50
51
  | Discount banners + product badges | `client.getDiscountBanners()`, `client.getProductDiscountBadge(productId)` | ✅ |
51
52
  | Product reviews on PDP + JSON-LD aggregateRating | `client.listProductReviews(id)`, `client.submitProductReview(id, …)` | ✅ |
@@ -376,7 +377,7 @@ await client.addToCart(cart.id, {
376
377
 
377
378
  Money on the wire is **always strings** (`priceDelta: "5.00"`). Validation failures arrive as a structured 400 envelope on `BrainerceError.details` with `code: 'MODIFIER_VALIDATION_FAILED'` and `errors[]` — see INTEGRATION-RULES.md "Modifier validation errors" for the full code list.
378
379
 
379
- Full rendering guide: [Core Integration §2.9](https://brainerce.com/docs/integration/core). Restaurant features (allergens, scheduled availability, nested combos to depth 3, downsell modifiers): [Optional Features "Restaurant / build-your-own products"](https://brainerce.com/docs/integration/optional).
380
+ Full rendering guide: [Core Integration §2.9](https://brainerce.com/docs/integration/core). Restaurant features (scheduled availability, nested combos to depth 3, downsell modifiers): [Optional Features "Restaurant / build-your-own products"](https://brainerce.com/docs/integration/optional).
380
381
 
381
382
  ### Content (FAQ / Footer / Header / Announcements / Pages)
382
383
 
@@ -400,7 +401,7 @@ if (!page) notFound();
400
401
 
401
402
  All `get` / `getBySlug` return `null` on 404 — render a hard-coded fallback so the page never crashes when the merchant hasn't seeded yet.
402
403
 
403
- **Security**: `FAQ.items[i].answer`, `RICH_TEXT.html`, and `PAGE.html` are **merchant-authored HTML**. The server does NOT pre-sanitize (merchants may embed iframes). ALWAYS sanitize before injecting:
404
+ **Security**: `FAQ.items[i].answer`, `RICH_TEXT.html`, `PAGE.html`, and `Product.description` are **merchant-authored HTML**. The server does NOT pre-sanitize FAQ/RICH_TEXT/PAGE (merchants may embed iframes); `Product.description` is server-sanitized on write but you still sanitize on render. `Product.description` may contain `<video>` and host-locked YouTube/Vimeo `<iframe>` embeds — allow those tags (iframe restricted to `www.youtube.com` / `www.youtube-nocookie.com` / `player.vimeo.com`) and add those hosts to your CSP `frame-src`. ALWAYS sanitize before injecting:
404
405
 
405
406
  ```typescript
406
407
  import DOMPurify from 'isomorphic-dompurify';
@@ -2375,7 +2376,16 @@ const checkoutId = checkout.id;
2375
2376
 
2376
2377
  #### Get All Payment Providers (Recommended)
2377
2378
 
2378
- Use this method to get ALL enabled payment providers and build dynamic UI:
2379
+ Use this method to get ALL enabled payment providers and build dynamic UI.
2380
+
2381
+ **Primary vs. additive methods (Shopify-parity).** Each provider carries a
2382
+ `methodType`. A `CREDIT_CARD` provider is the *primary* card processor — the
2383
+ single method that settles the order (`defaultProvider`, `isAdditive: false`,
2384
+ `presentation: 'card_form'`). Everything else is *additive* (`isAdditive: true`),
2385
+ e.g. PayPal is a `'WALLET'` with `presentation: 'express_button'`. Render additive
2386
+ methods as accelerated-checkout **express buttons above the card form** — they sit
2387
+ *alongside* the primary, never replace it. (Exception: a wallet-only store has no
2388
+ card processor, so its wallet becomes the `defaultProvider` and stands alone.)
2379
2389
 
2380
2390
  ```typescript
2381
2391
  const { hasPayments, providers, defaultProvider } = await client.getPaymentProviders();
@@ -2391,7 +2401,10 @@ const { hasPayments, providers, defaultProvider } = await client.getPaymentProvi
2391
2401
  // publicKey: 'pk_live_xxx...',
2392
2402
  // supportedMethods: ['card', 'ideal'],
2393
2403
  // testMode: false,
2394
- // isDefault: true
2404
+ // isDefault: true,
2405
+ // methodType: 'CREDIT_CARD', // primary card processor
2406
+ // presentation: 'card_form',
2407
+ // isAdditive: false
2395
2408
  // },
2396
2409
  // {
2397
2410
  // id: 'provider_yyy',
@@ -2400,12 +2413,20 @@ const { hasPayments, providers, defaultProvider } = await client.getPaymentProvi
2400
2413
  // publicKey: 'client_id_xxx...',
2401
2414
  // supportedMethods: ['paypal'],
2402
2415
  // testMode: false,
2403
- // isDefault: false
2416
+ // isDefault: false,
2417
+ // methodType: 'WALLET', // additive — render as an express button
2418
+ // presentation: 'express_button',
2419
+ // isAdditive: true
2404
2420
  // }
2405
2421
  // ],
2406
- // defaultProvider: { ... } // The default provider (first one)
2422
+ // defaultProvider: { ... } // The settling primary (never an additive wallet
2423
+ // // while a card processor is installed)
2407
2424
  // }
2408
2425
 
2426
+ // Recommended pattern: express buttons (additive) above the primary card form.
2427
+ const expressMethods = providers.filter(p => p.isAdditive); // e.g. PayPal
2428
+ const primary = defaultProvider && !defaultProvider.isAdditive ? defaultProvider : undefined;
2429
+
2409
2430
  // Build dynamic UI based on available providers
2410
2431
  if (!hasPayments) {
2411
2432
  return <div>Payment not configured for this store</div>;
@@ -2459,6 +2480,25 @@ const intent = await client.createPaymentIntent(checkout.id);
2459
2480
  // }
2460
2481
  ```
2461
2482
 
2483
+ **Routing to a specific provider (`providerId`).** With `getPaymentProviders()` you
2484
+ render additive **express buttons** (e.g. PayPal as a `WALLET`) alongside the primary
2485
+ card form. When the buyer taps one, pass that provider's `id` so the charge routes to
2486
+ it instead of the store's default card processor:
2487
+
2488
+ ```typescript
2489
+ const { providers } = await client.getPaymentProviders();
2490
+ const paypal = providers.find((p) => p.isAdditive && p.provider === 'paypal');
2491
+
2492
+ // Buyer tapped the PayPal express button:
2493
+ const intent = await client.createPaymentIntent(checkout.id, {
2494
+ providerId: paypal.id,
2495
+ });
2496
+ ```
2497
+
2498
+ Omit `providerId` to settle through the primary card processor (`defaultProvider`).
2499
+ The platform scopes it to the store, so only that store's own installed providers are
2500
+ selectable.
2501
+
2462
2502
  #### Confirm Payment with Stripe.js
2463
2503
 
2464
2504
  Use the client secret with Stripe.js to collect payment:
@@ -2873,6 +2913,32 @@ const { data: orders, meta } = await client.getMyOrders({
2873
2913
  });
2874
2914
  ```
2875
2915
 
2916
+ #### Loyalty & Rewards
2917
+
2918
+ Storefront-mode only (requires `storeId` + `customerToken`). Let logged-in
2919
+ customers check their points balance, enroll, and redeem rewards for one-time
2920
+ coupons that apply at checkout.
2921
+
2922
+ ```typescript
2923
+ // Current status — points balance + program display config.
2924
+ // `program` is null if the store has no loyalty program.
2925
+ const status = await client.getLoyaltyStatus();
2926
+ if (status.enrolled) {
2927
+ console.log(`${status.pointsBalance} ${status.program?.pointsName}`);
2928
+ }
2929
+
2930
+ // Enroll (idempotent) — only if the program is ACTIVE.
2931
+ await client.enrollInLoyalty();
2932
+
2933
+ // Rewards the customer can redeem, cheapest first.
2934
+ const rewards = await client.getAvailableRewards();
2935
+
2936
+ // Redeem → spends points, returns a one-time coupon code to apply to the cart.
2937
+ const { couponCode, discountValue, pointsBalance } =
2938
+ await client.redeemLoyaltyReward(rewards[0].id);
2939
+ await client.applyCoupon(cartId, couponCode);
2940
+ ```
2941
+
2876
2942
  #### Auth Response Type
2877
2943
 
2878
2944
  ```typescript
@@ -3424,6 +3490,8 @@ client.trackEvent({ eventType: 'engagement', path: '/products/shoes', engagedMs:
3424
3490
 
3425
3491
  > `trackEvent()` is fire-and-forget — errors are silently swallowed so a failed beacon never breaks your storefront. Available in `salesChannelId` and `storeId` modes.
3426
3492
 
3493
+ > **Analytics always goes directly to the Brainerce API** (`keepalive` beacon), even when you route the rest of the SDK through a same-origin BFF proxy (`proxyMode` / `baseUrl: '/api/store'`). This is deliberate: a beacon relayed through your server would arrive from the server's datacenter IP and mis-geolocate **every** visitor to that region (e.g. a Vercel US function → all visitors show as US). When `proxyMode` is on — or `baseUrl` shares the page origin — the SDK auto-targets `https://api.brainerce.com` for beacons; override with `analyticsBaseUrl` only if your API is self-hosted.
3494
+
3427
3495
  **Privacy:** cookieless, no PII stored. The visitor IP is resolved to a country server-side and then discarded. No cookie-consent banner required under GDPR/ePrivacy.
3428
3496
 
3429
3497
  ---
package/dist/index.d.mts CHANGED
@@ -112,6 +112,32 @@ interface BrainerceClientOptions {
112
112
  * ```
113
113
  */
114
114
  proxyMode?: boolean;
115
+ /**
116
+ * Base URL used for analytics beacons (`trackEvent`) ONLY — everything else
117
+ * keeps using `baseUrl`.
118
+ *
119
+ * Analytics must reach the Brainerce API **directly from the browser** so the
120
+ * visitor's real IP — and therefore country — is preserved. If a beacon is routed
121
+ * through a same-origin BFF proxy (see `proxyMode`), it arrives at the backend from
122
+ * the proxy server's datacenter IP instead (e.g. a Vercel US region), and every
123
+ * visitor is mis-geolocated to that datacenter.
124
+ *
125
+ * You normally do NOT need to set this: when `proxyMode` is on (or `baseUrl` shares
126
+ * the current page's origin), the SDK automatically sends analytics to
127
+ * `https://api.brainerce.com`. Set it explicitly only when your Brainerce API lives
128
+ * at a custom / self-hosted origin.
129
+ *
130
+ * @example
131
+ * ```typescript
132
+ * const client = new BrainerceClient({
133
+ * connectionId: 'vc_abc123...',
134
+ * baseUrl: '/api/store', // products / cart / auth go through the BFF proxy
135
+ * proxyMode: true,
136
+ * // analytics auto-routes direct to https://api.brainerce.com — no config needed
137
+ * });
138
+ * ```
139
+ */
140
+ analyticsBaseUrl?: string;
115
141
  }
116
142
  interface StoreInfo {
117
143
  id: string;
@@ -222,6 +248,51 @@ interface CustomerProfile {
222
248
  createdAt: string;
223
249
  updatedAt: string;
224
250
  }
251
+ /** A store's loyalty program status for a logged-in customer. */
252
+ interface LoyaltyStatus {
253
+ /** Whether the customer has a membership in the program. */
254
+ enrolled: boolean;
255
+ /** Redeemable points balance (pending earns excluded). */
256
+ pointsBalance: number;
257
+ /** Total points ever earned (confirmed). */
258
+ lifetimeEarned: number;
259
+ /** Program display config, or null when the store has no loyalty program. */
260
+ program: {
261
+ /** Display name for points (e.g. "points", "coins"). */
262
+ pointsName: string;
263
+ /** Points needed to redeem one unit of store currency. */
264
+ currencyRatio: number;
265
+ status: 'DRAFT' | 'ACTIVE' | 'PAUSED';
266
+ } | null;
267
+ }
268
+ /** A reward a customer can redeem points for (fixed-amount discount coupon). */
269
+ interface LoyaltyReward {
270
+ id: string;
271
+ name: string;
272
+ description: string | null;
273
+ /** Points required to redeem this reward. */
274
+ pointsCost: number;
275
+ /** Fixed discount amount the minted coupon is worth, in store currency. */
276
+ discountValue: number;
277
+ /** Minimum order amount for the coupon to apply, or null. */
278
+ minOrderAmount: number | null;
279
+ /** How many times a single customer may redeem this reward. */
280
+ maxUsesPerUser: number;
281
+ isActive: boolean;
282
+ createdAt: string;
283
+ updatedAt: string;
284
+ }
285
+ /** Result of redeeming a reward — a one-time coupon plus the new balance. */
286
+ interface RedeemRewardResult {
287
+ /** The minted one-time coupon code to apply at checkout. */
288
+ couponCode: string;
289
+ /** Fixed discount amount the coupon is worth. */
290
+ discountValue: number;
291
+ /** Points spent on this redemption. */
292
+ pointsSpent: number;
293
+ /** The customer's remaining points balance after redemption. */
294
+ pointsBalance: number;
295
+ }
225
296
  interface ProductMetafield {
226
297
  id: string;
227
298
  definitionId: string;
@@ -256,13 +327,20 @@ interface Product {
256
327
  */
257
328
  localeSlugs?: Record<string, string> | null;
258
329
  /**
259
- * Product description as HTML. **Always sanitize before rendering**, e.g.:
330
+ * Product description as HTML. May contain self-hosted `<video>` and
331
+ * host-locked YouTube/Vimeo `<iframe>` embeds. **Always sanitize before
332
+ * rendering**, e.g.:
260
333
  *
261
334
  * import { sanitizeHTML } from '@brainerce/utils';
262
335
  * <div dangerouslySetInnerHTML={{ __html: sanitizeHTML(product.description) }} />
263
336
  *
264
- * The backend strips dangerous tags/attributes on write, but storefronts should
265
- * still treat product description as untrusted HTML and sanitize on render.
337
+ * The backend strips dangerous tags/attributes on write, but storefronts
338
+ * should still treat this as untrusted HTML and sanitize on render. Your
339
+ * sanitizer must allow `video`/`source` and — for embeds — `iframe` restricted
340
+ * to the hosts `www.youtube.com`, `www.youtube-nocookie.com`,
341
+ * `player.vimeo.com` (never arbitrary iframes). Sizing is on the `width`/
342
+ * `height` attributes (inline `style` is stripped). If you set a CSP, add
343
+ * those three hosts to `frame-src` or embeds render blank.
266
344
  */
267
345
  description?: string | null;
268
346
  descriptionFormat?: 'text' | 'html' | 'markdown' | null;
@@ -443,6 +521,14 @@ interface WriteProductReviewInput {
443
521
  rating: number;
444
522
  body?: string;
445
523
  }
524
+ /**
525
+ * @deprecated Use `WriteProductReviewInput`. Customers no longer pass author info
526
+ * directly; it's derived from the authenticated customer profile.
527
+ */
528
+ interface SubmitProductReviewInput extends WriteProductReviewInput {
529
+ authorName?: string;
530
+ authorEmail?: string;
531
+ }
446
532
  /**
447
533
  * Returned by `client.getMyProductReview(productId)`. Tells the storefront which
448
534
  * UI to render: sign-in / not-eligible / submit / edit.
@@ -1064,7 +1150,14 @@ interface CreateProductDto {
1064
1150
  status?: 'active' | 'draft';
1065
1151
  type?: 'SIMPLE' | 'VARIABLE';
1066
1152
  isDownloadable?: boolean;
1153
+ /** Existing category IDs to assign. Unknown/cross-store IDs are rejected with 400. To assign by name (auto-creating if missing), use `categoryNames`. */
1067
1154
  categories?: string[];
1155
+ /** Category names to assign — matched case-insensitively and auto-created if none exists. Merged with any IDs in `categories`. */
1156
+ categoryNames?: string[];
1157
+ /** Existing brand IDs to assign. Unknown/cross-store IDs are rejected with 400. To assign by name (auto-creating if missing), use `brandNames`. */
1158
+ brands?: string[];
1159
+ /** Brand names to assign — matched case-insensitively and auto-created if none exists. Merged with any IDs in `brands`. */
1160
+ brandNames?: string[];
1068
1161
  tags?: string[];
1069
1162
  images?: ProductImage[];
1070
1163
  }
@@ -1078,7 +1171,14 @@ interface UpdateProductDto {
1078
1171
  costPrice?: number | null;
1079
1172
  status?: 'active' | 'draft';
1080
1173
  isDownloadable?: boolean;
1174
+ /** Existing category IDs to assign (replaces the current set). Pass `[]` to clear. Unknown/cross-store IDs are rejected with 400. To assign by name (auto-creating if missing), use `categoryNames`. */
1081
1175
  categories?: string[];
1176
+ /** Category names to assign — matched case-insensitively and auto-created if missing. Additive: added to `categories` (or to the product's current categories when `categories` is omitted). */
1177
+ categoryNames?: string[];
1178
+ /** Existing brand IDs to assign (replaces the current set). Pass `[]` to clear. Unknown/cross-store IDs are rejected with 400. To assign by name (auto-creating if missing), use `brandNames`. */
1179
+ brands?: string[];
1180
+ /** Brand names to assign — matched case-insensitively and auto-created if missing. Additive: added to `brands` (or to the product's current brands when `brands` is omitted). */
1181
+ brandNames?: string[];
1082
1182
  tags?: string[];
1083
1183
  images?: ProductImage[];
1084
1184
  }
@@ -3098,6 +3198,18 @@ interface PaymentClientSdk {
3098
3198
  *
3099
3199
  * **Alias:** `PaymentProvider` is the same type (use either name).
3100
3200
  */
3201
+ /**
3202
+ * Payment-method taxonomy (Shopify-parity). `CREDIT_CARD` is a *primary* card
3203
+ * processor — the single method that settles the order; everything else is an
3204
+ * *additive* method (wallet/alt/local/redeemable) that coexists alongside it.
3205
+ */
3206
+ type PaymentMethodType = 'CREDIT_CARD' | 'WALLET' | 'OFFSITE' | 'LOCAL' | 'REDEEMABLE';
3207
+ /**
3208
+ * How a storefront should render a payment method. `card_form` = the main card
3209
+ * fields; `express_button` = an accelerated-checkout button (render it ABOVE the
3210
+ * card form, like PayPal / Apple Pay); `redirect` = send the buyer offsite.
3211
+ */
3212
+ type PaymentPresentation = 'card_form' | 'express_button' | 'redirect' | 'local_option' | 'redeemable_field';
3101
3213
  interface PaymentProviderConfig {
3102
3214
  /** Provider ID (use this when creating payment intents) */
3103
3215
  id: string;
@@ -3113,8 +3225,26 @@ interface PaymentProviderConfig {
3113
3225
  supportedMethods: string[];
3114
3226
  /** Whether this is test/sandbox mode */
3115
3227
  testMode: boolean;
3116
- /** Whether this is the default provider */
3228
+ /**
3229
+ * Whether this is the store's default *settling* provider. Only a primary
3230
+ * (`methodType: 'CREDIT_CARD'`) provider is ever the default — an additive
3231
+ * wallet never becomes the default while a card processor is installed.
3232
+ */
3117
3233
  isDefault: boolean;
3234
+ /**
3235
+ * Payment-method taxonomy — primary card processor vs additive wallet/alt.
3236
+ * Use it to place the method: primary → the main card form; additive → an
3237
+ * express button. See `presentation`.
3238
+ */
3239
+ methodType: PaymentMethodType;
3240
+ /** Rendering hint derived from `methodType` (card_form | express_button | …). */
3241
+ presentation: PaymentPresentation;
3242
+ /**
3243
+ * True for wallet/alternative methods (e.g. PayPal) that are shown *alongside*
3244
+ * the primary card processor rather than replacing it. Render these as
3245
+ * accelerated-checkout express buttons above the card form.
3246
+ */
3247
+ isAdditive: boolean;
3118
3248
  /** Client-side SDK configuration for providers that render a widget */
3119
3249
  clientSdk?: PaymentClientSdk;
3120
3250
  }
@@ -4773,7 +4903,13 @@ interface CheckoutCustomFieldDefinition {
4773
4903
  key: string;
4774
4904
  name: string;
4775
4905
  description?: string | null;
4776
- type: 'TEXT' | 'TEXTAREA' | 'NUMBER' | 'BOOLEAN' | 'SELECT' | 'DATE';
4906
+ /**
4907
+ * `IMAGE` renders a file-upload control; its value is the uploaded file URL
4908
+ * (validated server-side to be a store-hosted upload). `GALLERY` and
4909
+ * `MULTI_SELECT` are NOT supported for checkout fields — those are
4910
+ * product-metafield-only (`ProductCustomizationField` / `MetafieldType`).
4911
+ */
4912
+ type: 'TEXT' | 'TEXTAREA' | 'NUMBER' | 'BOOLEAN' | 'SELECT' | 'DATE' | 'IMAGE';
4777
4913
  required: boolean;
4778
4914
  position: number;
4779
4915
  visibility: CheckoutFieldVisibility;
@@ -5427,6 +5563,8 @@ declare class BrainerceClient {
5427
5563
  private readonly storeId?;
5428
5564
  private readonly connectionId?;
5429
5565
  private readonly baseUrl;
5566
+ /** Direct API base for analytics beacons — bypasses any same-origin BFF proxy so the visitor's real IP (hence country) reaches the backend. */
5567
+ private readonly analyticsBaseUrl;
5430
5568
  private readonly timeout;
5431
5569
  private customerToken;
5432
5570
  private customerCartId;
@@ -5596,6 +5734,20 @@ declare class BrainerceClient {
5596
5734
  * ```
5597
5735
  */
5598
5736
  trackEvent(payload?: TrackEventPayload): Promise<void>;
5737
+ /**
5738
+ * Resolve the base URL for analytics beacons. Analytics must go DIRECTLY to the
5739
+ * Brainerce API (never through a same-origin BFF proxy) so the visitor's real IP —
5740
+ * hence country — reaches the backend. Explicit `analyticsBaseUrl` wins; otherwise
5741
+ * use the direct API when `baseUrl` is a same-origin proxy, else the (already-direct)
5742
+ * `baseUrl` (which may be a custom / self-hosted Brainerce API).
5743
+ */
5744
+ private resolveAnalyticsBaseUrl;
5745
+ /**
5746
+ * Fire-and-forget analytics beacon sent directly to `analyticsBaseUrl`. Uses
5747
+ * `keepalive` so it survives page unload (engagement events fired on pagehide),
5748
+ * omits credentials (cookieless), and never throws.
5749
+ */
5750
+ private sendAnalyticsBeacon;
5599
5751
  /**
5600
5752
  * Get a list of products with pagination and filtering
5601
5753
  * Works in vibe-coded, storefront (public), and admin mode
@@ -7930,6 +8082,14 @@ declare class BrainerceClient {
7930
8082
  *
7931
8083
  * @returns Payment providers config with hasPayments flag and provider list
7932
8084
  *
8085
+ * Each provider carries a `methodType` (Shopify-parity taxonomy) and a derived
8086
+ * `isAdditive` / `presentation`. There is at most ONE primary card processor
8087
+ * (`methodType: 'CREDIT_CARD'`, the `defaultProvider`) that settles the order;
8088
+ * additive methods (`isAdditive: true`, e.g. PayPal as a `'WALLET'`) are shown
8089
+ * *alongside* it as accelerated-checkout express buttons — they never replace
8090
+ * the card form. A wallet-only store is the one exception: with no card
8091
+ * processor installed, the wallet becomes the `defaultProvider` and stands alone.
8092
+ *
7933
8093
  * @example
7934
8094
  * ```typescript
7935
8095
  * const { providers, hasPayments, defaultProvider } = await client.getPaymentProviders();
@@ -7939,27 +8099,21 @@ declare class BrainerceClient {
7939
8099
  * return;
7940
8100
  * }
7941
8101
  *
7942
- * // Find specific providers
7943
- * const stripeProvider = providers.find(p => p.provider === 'stripe');
7944
- * const paypalProvider = providers.find(p => p.provider === 'paypal');
7945
- *
7946
- * // Initialize Stripe if available (with Connect account support)
7947
- * if (stripeProvider) {
7948
- * const stripe = await loadStripe(stripeProvider.publicKey, {
7949
- * stripeAccount: stripeProvider.stripeAccountId, // For Stripe Connect
7950
- * });
7951
- * // Show Stripe payment form
7952
- * }
7953
- *
7954
- * // Initialize PayPal if available
7955
- * if (paypalProvider) {
7956
- * // Load PayPal SDK with paypalProvider.publicKey as client-id
7957
- * // Show PayPal buttons
8102
+ * // Render additive methods (wallets) as express buttons ABOVE the card form.
8103
+ * const expressMethods = providers.filter(p => p.isAdditive); // e.g. PayPal
8104
+ * for (const m of expressMethods) {
8105
+ * // m.presentation === 'express_button' — render an express/accelerated button
8106
+ * // and call createPaymentIntent({ providerId: m.id }) when the buyer taps it.
7958
8107
  * }
7959
8108
  *
7960
- * // Or use the default provider for a simpler single-provider flow
7961
- * if (defaultProvider) {
7962
- * console.log(`Using default: ${defaultProvider.name} (${defaultProvider.provider})`);
8109
+ * // Render the primary card processor (the settling default) as the main form.
8110
+ * if (defaultProvider && !defaultProvider.isAdditive) {
8111
+ * if (defaultProvider.provider === 'stripe') {
8112
+ * const stripe = await loadStripe(defaultProvider.publicKey, {
8113
+ * stripeAccount: defaultProvider.stripeAccountId, // For Stripe Connect
8114
+ * });
8115
+ * // Show the Stripe card form
8116
+ * }
7963
8117
  * }
7964
8118
  * ```
7965
8119
  */
@@ -8000,6 +8154,16 @@ declare class BrainerceClient {
8000
8154
  * ```
8001
8155
  */
8002
8156
  createPaymentIntent(checkoutId: string, options?: {
8157
+ /**
8158
+ * Route the charge to a specific installed provider — pass the `id` from a
8159
+ * `getPaymentProviders()` entry. This is how you wire an additive express
8160
+ * button (e.g. PayPal as a `WALLET`): when the buyer taps it, call
8161
+ * `createPaymentIntent(checkoutId, { providerId: m.id })`. Omit to settle
8162
+ * through the store's primary card processor (`defaultProvider`). The
8163
+ * platform scopes this to the store, so only that store's own installed
8164
+ * providers are selectable.
8165
+ */
8166
+ providerId?: string;
8003
8167
  successUrl?: string;
8004
8168
  cancelUrl?: string;
8005
8169
  /**
@@ -8450,6 +8614,54 @@ declare class BrainerceClient {
8450
8614
  phone?: string;
8451
8615
  acceptsMarketing?: boolean;
8452
8616
  }): Promise<CustomerProfile>;
8617
+ /**
8618
+ * Get the logged-in customer's loyalty status: enrollment, points balance,
8619
+ * lifetime earned, and the program's display config (requires customerToken).
8620
+ * Only available in storefront mode. `program` is null when the store has no
8621
+ * loyalty program.
8622
+ *
8623
+ * @example
8624
+ * ```typescript
8625
+ * client.setCustomerToken(auth.token);
8626
+ * const status = await client.getLoyaltyStatus();
8627
+ * if (status.enrolled) console.log(`${status.pointsBalance} ${status.program?.pointsName}`);
8628
+ * ```
8629
+ */
8630
+ getLoyaltyStatus(): Promise<LoyaltyStatus>;
8631
+ /**
8632
+ * Enroll the logged-in customer in the store's loyalty program (requires
8633
+ * customerToken). Idempotent — returns the same status shape as
8634
+ * getLoyaltyStatus(). Only available in storefront mode.
8635
+ *
8636
+ * @example
8637
+ * ```typescript
8638
+ * const status = await client.enrollInLoyalty();
8639
+ * ```
8640
+ */
8641
+ enrollInLoyalty(): Promise<LoyaltyStatus>;
8642
+ /**
8643
+ * List the rewards the customer can redeem points for (active rewards, cheapest
8644
+ * first). Requires customerToken. Only available in storefront mode.
8645
+ *
8646
+ * @example
8647
+ * ```typescript
8648
+ * client.setCustomerToken(auth.token);
8649
+ * const rewards = await client.getAvailableRewards();
8650
+ * ```
8651
+ */
8652
+ getAvailableRewards(): Promise<LoyaltyReward[]>;
8653
+ /**
8654
+ * Redeem a reward: spends the customer's points and mints a one-time coupon
8655
+ * that applies at checkout (requires customerToken). Only available in
8656
+ * storefront mode.
8657
+ *
8658
+ * @example
8659
+ * ```typescript
8660
+ * const { couponCode, pointsBalance } = await client.redeemLoyaltyReward('rw_123');
8661
+ * // apply couponCode to the cart at checkout
8662
+ * ```
8663
+ */
8664
+ redeemLoyaltyReward(rewardId: string): Promise<RedeemRewardResult>;
8453
8665
  /**
8454
8666
  * Get the current customer's orders (requires customerToken)
8455
8667
  * Works in vibe-coded and storefront modes
@@ -9614,7 +9826,7 @@ declare class BrainerceError extends Error {
9614
9826
  constructor(message: string, statusCode: number, details?: unknown);
9615
9827
  }
9616
9828
 
9617
- declare const SDK_VERSION = "1.36.1";
9829
+ declare const SDK_VERSION = "1.42.0";
9618
9830
 
9619
9831
  /**
9620
9832
  * Verify a webhook signature from Brainerce
@@ -9754,4 +9966,4 @@ declare function formatVariantPrice(variant: Pick<ProductVariant, 'price' | 'sal
9754
9966
  /** Format any numeric amount as currency. Useful for cart totals, fees, etc. */
9755
9967
  declare function formatMoney(amount: number, currency: string, locale?: string): string;
9756
9968
 
9757
- export { type AddToCartDto, type AnnouncementContent, type AnnouncementSeverity, type AppliedDiscount, type ApplyCouponDto, type AttachModifierGroupInput, type Attribute, type AttributeOption, type AttributeSource, type BrainerceApiError, BrainerceClient, type BrainerceClientOptions, BrainerceError, type Brand, type BulkInventoryResponse, type BulkSaveVariantsDto, type BulkSaveVariantsResponse, type BulkVariantInput, type Cart, type CartAppliedDiscount, type CartBundleOffer, type CartBundlesResponse, type CartIncludeOption, type CartIncludeOptions, type CartItem, type CartItemModifierLine, type CartNudge, type CartRecommendationsResponse, type CartStatus, type CartUpgradeSuggestion, type CartUpgradesResponse, type CartWithIncludes, type Category, type CategoryNode, type CategorySuggestion, type Checkout, type CheckoutAddress, type CheckoutBumpsResponse, type CheckoutCustomFieldDefinition, type CheckoutFieldPricing, type CheckoutFieldVisibility, type CheckoutLineItem, type CheckoutPrefillData, type CheckoutStatus, type CompleteCheckoutResponse, type CompleteDraftDto, type ConfigureOAuthProviderDto as ConfigureOAuthProviderInput, type ConflictStatus, type ConnectorPlatform, type ContactFormFieldType, type ContactFormFieldValidation, type ContactFormPublic, type ContactFormPublicField, type ContactFormSummary, type Content, type ContentDataMap, type ContentStatus, type ContentSummary, type ContentType, type Coupon, type CouponCreateResponse, type CouponQueryParams, type CouponStatus, type CouponType, type CouponValidationWarning, type CreateAddressDto, type CreateAttributeDto as CreateAttributeInput, type CreateAttributeOptionDto as CreateAttributeOptionInput, type CreateBrandDto as CreateBrandInput, type CreateCategoryDto as CreateCategoryInput, type CreateCheckoutDto, type CreateContentInput, type CreateCouponDto, type CreateCustomApiDto, type CreateCustomerDto, type CreateEmailTemplateDto as CreateEmailTemplateInput, type CreateGuestOrderDto, type CreateInquiryInput, type CreateInquiryResponse, type CreateMetafieldDefinitionDto as CreateMetafieldDefinitionInput, type CreateModifierGroupInput, type CreateModifierInput, type CreateOrderDto, type CreateProductDto, type CreateRefundDto, type CreateShippingRateDto as CreateShippingRateInput, type CreateShippingZoneDto as CreateShippingZoneInput, type CreateTagDto as CreateTagInput, type CreateTaxRateDto as CreateTaxRateInput, type CreateVariantDto, type CustomApiAuthType, type CustomApiConnectionStatus, type CustomApiCredentials, type CustomApiIntegration, type CustomApiSyncConfig, type CustomApiSyncDirection, type CustomApiTestResult, type Customer, type CustomerAddress, type CustomerAuthResponse, type CustomerOAuthProvider, type CustomerProfile, type CustomerQueryParams, type DeleteProductResponse, type DiscountBanner, type DiscountRuleType, type DownloadFile, type DraftLineItem, type EditInventoryDto, type EmailDomain, type EmailEventSettings, type EmailEventType, type EmailSettings, type EmailTemplate, type EmailTemplatePreview, type EmailTemplatesResponse, type EmailVerificationResponse, type ExtendReservationResponse, type FaqContent, type FaqItem, type FooterColumn, type FooterContent, type FooterLink, type FooterSocialLink, type FormatPriceOptions, type FormatProductPriceOptions, type FreeAllocationPolicy, type FulfillOrderDto, type GuestCheckoutStartResponse, type GuestOrderResponse, type HeaderContent, type HeaderCta, type HeaderLogo, type HeaderNavItem, type InsufficientStockError, type InventoryInfo, type InventoryReservationStrategy, type InventorySyncStatus, type InventoryTrackingMode, type InvitationStatus, type InviteMemberDto as InviteMemberInput, type InviteStoreMemberDto as InviteStoreMemberInput, type ListModifierGroupsParams, type LocalCart, type LocalCartItem, type LockedVariant, type MergeCartsDto, type MetafieldConflict, type MetafieldConflictResolution, type MetafieldDefinition, type MetafieldType, type Modifier, type ModifierGroup, type ModifierSelection, type ModifierSelectionType, type ModifierValidationCode, type ModifierValidationError, type OAuthAuthorizeResponse, type OAuthCallbackResponse, type OAuthConnection, type OAuthConnectionsResponse, type OAuthProviderConfig, type OAuthProviderType, type OAuthProvidersResponse, type Order, type OrderAddress, type OrderBump, type OrderCustomer, type OrderDownloadLink, type OrderItem, type OrderQueryParams, type OrderStatus, type OrderStatusChange, type PageContent, type PageSeo, type PaginatedResponse, type PaymentClientSdk, type PaymentConfig, type PaymentIntent, type PaymentProvider, type PaymentProviderConfig, type PaymentProvidersConfig, type PaymentStatus, type PaymentUrlOptions, type PickupLocation, type PlatformCouponCapabilities, type PlatformMetafieldMetadata, type PreviewEmailTemplateDto as PreviewEmailTemplateInput, type Product, type ProductAttributeInput, type ProductAvailability, type ProductCustomizationField, type ProductDiscount, type ProductDiscountBadge, type ProductImage, type ProductMetafield, type ProductMetafieldValue, type ProductModifierGroupAttachment, type ProductQueryParams, type ProductRecommendation, type ProductRecommendationsResponse, type ProductRelationType, type ProductSuggestion, type ProductVariant, type PublicMetafieldDefinition, type PublishProductResponse, RTL_LOCALES, type RecommendationVariant, type ReconcileInventoryResponse, type Refund, type RefundLineItem, type RefundLineItemResponse, type RefundType, type RegisterCustomerDto, type ReservationInfo, type ResolveMetafieldConflictDto as ResolveMetafieldConflictInput, type ResolveSyncConflictDto as ResolveSyncConflictInput, type RichTextContent, SDK_VERSION, type SearchSuggestions, type SelectPickupLocationDto, type SelectShippingMethodDto, type SendInvoiceDto, type SessionCartRef, type SetBillingAddressDto, type SetCheckoutCustomFieldsDto, type SetCheckoutCustomerDto, type SetDefinitionProductsDto as SetDefinitionProductsInput, type SetMetafieldPlatformsDto as SetMetafieldPlatformsInput, type SetShippingAddressDto, type SetShippingAddressResponse, type ShippingDestinations, type ShippingLine, type ShippingRate, type ShippingRateConfig, type ShippingRateType, type ShippingZone, type ShippingZoneQueryParams, type StockAvailabilityRequest, type StockAvailabilityResponse, type StockAvailabilityResult, type StoreInfo, type StoreInvitation, type StoreInvitationDetails, type StoreMember, type StorePermission, type StoreRole, type StoreTeamResponse, type SupportedLocaleObject, type SyncConflict, type SyncConflictResolution, type SyncJob, type Tag, type TaxBreakdown, type TaxBreakdownItem, type TaxRate, type TaxonomyQueryParams, type TeamInvitation, type TeamInvitationsResponse, type TeamMember, type TeamMembersResponse, type TeamRole, type UpdateAddressDto, type UpdateAttachmentInput, type UpdateAttributeDto as UpdateAttributeInput, type UpdateAttributeOptionDto as UpdateAttributeOptionInput, type UpdateBrandDto as UpdateBrandInput, type UpdateCartItemDto, type UpdateCategoryDto as UpdateCategoryInput, type UpdateContentInput, type UpdateCouponDto, type UpdateCustomApiDto, type UpdateCustomerDto, type UpdateDraftDto, type UpdateEmailSettingsDto as UpdateEmailSettingsInput, type UpdateEmailTemplateDto as UpdateEmailTemplateInput, type UpdateInventoryDto, type UpdateMemberRoleDto as UpdateMemberRoleInput, type UpdateMetafieldDefinitionDto as UpdateMetafieldDefinitionInput, type UpdateModifierGroupInput, type UpdateModifierInput, type UpdateOAuthProviderDto as UpdateOAuthProviderInput, type UpdateOrderDto, type UpdateOrderShippingDto, type UpdateProductDto, type UpdateShippingRateDto as UpdateShippingRateInput, type UpdateShippingZoneDto as UpdateShippingZoneInput, type UpdateStoreMemberDto as UpdateStoreMemberInput, type UpdateTagDto as UpdateTagInput, type UpdateTaxRateDto as UpdateTaxRateInput, type UpdateVariantDto, type UpdateVariantInventoryDto, type UpsertProductMetafieldDto as UpsertProductMetafieldInput, type UserStore, type UserStorePermissions, type VariantInventoryResponse, type VariantPlatformOverlay, type VariantStatus, type WaitForOrderOptions, type WaitForOrderResult, type WebhookEvent, type WebhookEventType, createWebhookHandler, deriveSeoDescription, enableDevGuards, formatMoney, formatPrice, formatProductPrice, formatVariantPrice, getCartItemImage, getCartItemName, getCartTotals, getDescriptionContent, getDirectionForLocale, formatPrice as getPriceDisplay, getProductCustomizationFields, getProductMetafield, getProductMetafieldValue, getProductMetafieldsByType, getProductPrice, getProductPriceInfo, getProductSwatches, getStockStatus, getVariantOptions, getVariantPrice, isAllowedPaymentUrl, isCouponApplicableToProduct, isHtmlDescription, isWebhookEventType, parseWebhookEvent, safePaymentRedirect, stripHtml, verifyWebhook };
9969
+ export { type AddToCartDto, type AnnouncementContent, type AnnouncementSeverity, type AppliedDiscount, type ApplyCouponDto, type AttachModifierGroupInput, type Attribute, type AttributeOption, type AttributeSource, type BrainerceApiError, BrainerceClient, type BrainerceClientOptions, BrainerceError, type Brand, type BulkInventoryResponse, type BulkSaveVariantsDto, type BulkSaveVariantsResponse, type BulkVariantInput, type Cart, type CartAppliedDiscount, type CartBundleOffer, type CartBundlesResponse, type CartIncludeOption, type CartIncludeOptions, type CartItem, type CartItemModifierLine, type CartNudge, type CartRecommendationsResponse, type CartStatus, type CartUpgradeSuggestion, type CartUpgradesResponse, type CartWithIncludes, type Category, type CategoryNode, type CategorySuggestion, type Checkout, type CheckoutAddress, type CheckoutBumpsResponse, type CheckoutCustomFieldDefinition, type CheckoutFieldPricing, type CheckoutFieldVisibility, type CheckoutLineItem, type CheckoutPrefillData, type CheckoutStatus, type CompleteCheckoutResponse, type CompleteDraftDto, type ConfigureOAuthProviderDto as ConfigureOAuthProviderInput, type ConflictStatus, type ConnectorPlatform, type ContactFormFieldType, type ContactFormFieldValidation, type ContactFormPublic, type ContactFormPublicField, type ContactFormSummary, type Content, type ContentDataMap, type ContentStatus, type ContentSummary, type ContentType, type Coupon, type CouponCreateResponse, type CouponQueryParams, type CouponStatus, type CouponType, type CouponValidationWarning, type CreateAddressDto, type CreateAttributeDto as CreateAttributeInput, type CreateAttributeOptionDto as CreateAttributeOptionInput, type CreateBrandDto as CreateBrandInput, type CreateCategoryDto as CreateCategoryInput, type CreateCheckoutDto, type CreateContentInput, type CreateCouponDto, type CreateCustomApiDto, type CreateCustomerDto, type CreateEmailTemplateDto as CreateEmailTemplateInput, type CreateGuestOrderDto, type CreateInquiryInput, type CreateInquiryResponse, type CreateMetafieldDefinitionDto as CreateMetafieldDefinitionInput, type CreateModifierGroupInput, type CreateModifierInput, type CreateOrderDto, type CreateProductDto, type CreateRefundDto, type CreateShippingRateDto as CreateShippingRateInput, type CreateShippingZoneDto as CreateShippingZoneInput, type CreateTagDto as CreateTagInput, type CreateTaxRateDto as CreateTaxRateInput, type CreateVariantDto, type CustomApiAuthType, type CustomApiConnectionStatus, type CustomApiCredentials, type CustomApiIntegration, type CustomApiSyncConfig, type CustomApiSyncDirection, type CustomApiTestResult, type Customer, type CustomerAddress, type CustomerAuthResponse, type CustomerOAuthProvider, type CustomerProfile, type CustomerQueryParams, type DeleteProductResponse, type DiscountBanner, type DiscountRuleType, type DownloadFile, type DraftLineItem, type EditInventoryDto, type EmailDomain, type EmailEventSettings, type EmailEventType, type EmailSettings, type EmailTemplate, type EmailTemplatePreview, type EmailTemplatesResponse, type EmailVerificationResponse, type ExtendReservationResponse, type FaqContent, type FaqItem, type FooterColumn, type FooterContent, type FooterLink, type FooterSocialLink, type FormatPriceOptions, type FormatProductPriceOptions, type FreeAllocationPolicy, type FulfillOrderDto, type GuestCheckoutStartResponse, type GuestOrderResponse, type HeaderContent, type HeaderCta, type HeaderLogo, type HeaderNavItem, type InsufficientStockError, type InventoryInfo, type InventoryReservationStrategy, type InventorySyncStatus, type InventoryTrackingMode, type InvitationStatus, type InviteMemberDto as InviteMemberInput, type InviteStoreMemberDto as InviteStoreMemberInput, type ListModifierGroupsParams, type LocalCart, type LocalCartItem, type LockedVariant, type MergeCartsDto, type MetafieldConflict, type MetafieldConflictResolution, type MetafieldDefinition, type MetafieldType, type Modifier, type ModifierGroup, type ModifierSelection, type ModifierSelectionType, type ModifierValidationCode, type ModifierValidationError, type MyProductReview, type OAuthAuthorizeResponse, type OAuthCallbackResponse, type OAuthConnection, type OAuthConnectionsResponse, type OAuthProviderConfig, type OAuthProviderType, type OAuthProvidersResponse, type Order, type OrderAddress, type OrderBump, type OrderCustomer, type OrderDownloadLink, type OrderItem, type OrderQueryParams, type OrderStatus, type OrderStatusChange, type PageContent, type PageSeo, type PaginatedResponse, type PaymentClientSdk, type PaymentConfig, type PaymentIntent, type PaymentProvider, type PaymentProviderConfig, type PaymentProvidersConfig, type PaymentStatus, type PaymentUrlOptions, type PickupLocation, type PlatformCouponCapabilities, type PlatformMetafieldMetadata, type PreviewEmailTemplateDto as PreviewEmailTemplateInput, type Product, type ProductAttributeInput, type ProductAvailability, type ProductCustomizationField, type ProductDiscount, type ProductDiscountBadge, type ProductImage, type ProductMetafield, type ProductMetafieldValue, type ProductModifierGroupAttachment, type ProductQueryParams, type ProductRecommendation, type ProductRecommendationsResponse, type ProductRelationType, type ProductReview, type ProductReviewAdmin, type ProductSuggestion, type ProductVariant, type PublicMetafieldDefinition, type PublishProductResponse, RTL_LOCALES, type RecommendationVariant, type ReconcileInventoryResponse, type Refund, type RefundLineItem, type RefundLineItemResponse, type RefundType, type RegisterCustomerDto, type ReservationInfo, type ResolveMetafieldConflictDto as ResolveMetafieldConflictInput, type ResolveSyncConflictDto as ResolveSyncConflictInput, type RichTextContent, SDK_VERSION, type SearchSuggestions, type SelectPickupLocationDto, type SelectShippingMethodDto, type SendInvoiceDto, type SessionCartRef, type SetBillingAddressDto, type SetCheckoutCustomFieldsDto, type SetCheckoutCustomerDto, type SetDefinitionProductsDto as SetDefinitionProductsInput, type SetMetafieldPlatformsDto as SetMetafieldPlatformsInput, type SetShippingAddressDto, type SetShippingAddressResponse, type ShippingDestinations, type ShippingLine, type ShippingRate, type ShippingRateConfig, type ShippingRateType, type ShippingZone, type ShippingZoneQueryParams, type StockAvailabilityRequest, type StockAvailabilityResponse, type StockAvailabilityResult, type StoreInfo, type StoreInvitation, type StoreInvitationDetails, type StoreMember, type StorePermission, type StoreRole, type StoreTeamResponse, type SubmitProductReviewInput, type SupportedLocaleObject, type SyncConflict, type SyncConflictResolution, type SyncJob, type Tag, type TaxBreakdown, type TaxBreakdownItem, type TaxRate, type TaxonomyQueryParams, type TeamInvitation, type TeamInvitationsResponse, type TeamMember, type TeamMembersResponse, type TeamRole, type UpdateAddressDto, type UpdateAttachmentInput, type UpdateAttributeDto as UpdateAttributeInput, type UpdateAttributeOptionDto as UpdateAttributeOptionInput, type UpdateBrandDto as UpdateBrandInput, type UpdateCartItemDto, type UpdateCategoryDto as UpdateCategoryInput, type UpdateContentInput, type UpdateCouponDto, type UpdateCustomApiDto, type UpdateCustomerDto, type UpdateDraftDto, type UpdateEmailSettingsDto as UpdateEmailSettingsInput, type UpdateEmailTemplateDto as UpdateEmailTemplateInput, type UpdateInventoryDto, type UpdateMemberRoleDto as UpdateMemberRoleInput, type UpdateMetafieldDefinitionDto as UpdateMetafieldDefinitionInput, type UpdateModifierGroupInput, type UpdateModifierInput, type UpdateOAuthProviderDto as UpdateOAuthProviderInput, type UpdateOrderDto, type UpdateOrderShippingDto, type UpdateProductDto, type UpdateShippingRateDto as UpdateShippingRateInput, type UpdateShippingZoneDto as UpdateShippingZoneInput, type UpdateStoreMemberDto as UpdateStoreMemberInput, type UpdateTagDto as UpdateTagInput, type UpdateTaxRateDto as UpdateTaxRateInput, type UpdateVariantDto, type UpdateVariantInventoryDto, type UpsertProductMetafieldDto as UpsertProductMetafieldInput, type UserStore, type UserStorePermissions, type VariantInventoryResponse, type VariantPlatformOverlay, type VariantStatus, type WaitForOrderOptions, type WaitForOrderResult, type WebhookEvent, type WebhookEventType, type WriteProductReviewInput, createWebhookHandler, deriveSeoDescription, enableDevGuards, formatMoney, formatPrice, formatProductPrice, formatVariantPrice, getCartItemImage, getCartItemName, getCartTotals, getDescriptionContent, getDirectionForLocale, formatPrice as getPriceDisplay, getProductCustomizationFields, getProductMetafield, getProductMetafieldValue, getProductMetafieldsByType, getProductPrice, getProductPriceInfo, getProductSwatches, getStockStatus, getVariantOptions, getVariantPrice, isAllowedPaymentUrl, isCouponApplicableToProduct, isHtmlDescription, isWebhookEventType, parseWebhookEvent, safePaymentRedirect, stripHtml, verifyWebhook };