Use cases

Checkout redemption

There are three ways to integrate Bubblehouse into a cart or checkout flow:

  1. Use our first-party widget with a first-party ecommerce integration such as Shopify, BigCommerce, or Magento.
  2. Use our first-party widget and do a custom integration with your system.
  3. Build Bubblehouse redemption into your own cart or checkout via our API.

1. Bubblehouse widget on a supported ecommerce platform

On a first-party ecommerce integration, the widget is added through that platform’s extension API, or by putting a custom HTML tag into the layout. It works out of the box: we load the cart, apply coupon codes, and show redemption in the widget.

We have implememnted the widget for most ecommerce platforms we have first-party support for. Talk to us for exact details and capabilities of yours.

2. Bubblehouse widget on a custom store

Keep our widget, and connect it to your cart. You implement the cart side. This is unofficial, customized per client, and not a public schema. Enough to know what the integration looks like. Talk to us for the copy that matches your store.

There are two approaches here:

  • frontend: our in-page widget calls your JavaScript to apply a coupon
  • backend: our server talks to your storefront server-to-server

Custom frontend integration

This is not an iframe and not Block Client postMessage (ApplyDiscountCode1, AddProductToCart1, Resize1). Those are rewards-page iframe calls.

Two in-page shapes exist. We pick one per client.

custom-widget.js (generic custom storefronts): load https://app.bubblehouse.com/static/js/custom-widget.js. Magento, WooCommerce, and BigCommerce use platform-specific bundles built around the same embed shape and platform callbacks. After the script loads it calls Bubblehouse_OnLoad or a function whose name starts with Bubblehouse_OnLoad_. Then:

window.Bubblehouse.Widgets.embed(
  "#bubblehouse-widget",
  "checkout-widget-composable",
  { slug: "example-store", token },
  {},
  {
    input: {
      cart_subtotal: "12.345670",
      line_items: [{ product_id: "SKU-1", qty: 2, price: "4.500000" }],
      site: "checkout",
      discountCodesKnown: true,
      discountCodes: []
    },
    sideEffects: {
      OnStylesheetLoad: [(url, nonce) => window.Bubblehouse.Widgets.importStylesheet(url, nonce)],
      OnPointsRedeemed: [async (result) => {
        await removeCouponCodesFromCheckout(result.removeCodes)
        await applyCouponCodeToCheckout(result.discount.code)
        window.location.reload()
      }]
    }
  }
)

Issue the customer JWT on your server. host is optional (hostname, or a full origin with ://). OnPointsRedeemed gets { amount: { monetary, apiAmount, pts }, couponAmount, discount: { code, type }, removeCodes }. Remove removeCodes, then apply discount.code at the total couponAmount with your cart API. amount.monetary is display-formatted; amount.apiAmount, couponAmount, cart_subtotal, and line-item prices are strings with six decimal places. When replacing an applied provisional coupon, amount.apiAmount is the requested increment and couponAmount is the replacement coupon’s whole value.

bubblehouse-redeem-panel (Shopify cart): an in-page custom element. It calls private CheckoutStatus1 then RedeemCheckoutReward1 (camelCase; cartSubtotal is a six-decimal string). Apply the returned coupon and removeCodes with Shopify Ajax addDiscountCode / cartDiscountCodesUpdate, or navigate to ?discount=CODE. useAdvancedIntegration skips navigation. It expects Shopify.country / Shopify.currency and a Shopify cart.js cart. Event bubblehouse:cart-updated. Coupled to that Shopify cart, not a generic public widget API.

Custom backend integration

The storefront passes a cart ID to the widget (an IFRAME URL parameter or a JavaScript call). Bubblehouse then calls your storefront:

Subscribe to both from Hello1.

3. Your own cart or checkout

Build redemption into your checkout experience and call our APIs.

Cart2

Cart2 is the API for building your own widget. Send the current cart as an Order2. Use preset cart for a custom checkout, pdp or readonly for display-only estimates. The result includes spendable balance, redemption constraints, an after-checkout estimate, and (when mutating) coupon effects to apply.

You can also apply other rewards to the cart before the order is placed. You do not have to support every effect; implement the subset your program uses.

curl -X POST https://app.bubblehouse.com/api/v2023061/<shop>/Cart2 \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "preset": "cart",
    "customer": {"email": "customer@example.com"},
    "cart": {
      "amount_subtotal": "20.00",
      "amount_spent": "20.00",
      "items": [{"id": "line-1", "quantity": 1, "amount_spent": "20.00"}],
      "discount_codes": []
    },
    "desired_redemption_pts": 50,
    "can_apply_cart_effects": true
  }'

Apply cart_changes_to_apply.add_coupons and remove remove_coupon_codes on your cart.

desired_redemption_pts is the whole total, including a Bubblehouse coupon already on the cart. It is not extra points on top of that coupon. After you apply the returned code, call Cart2 again with the same total. No coupon changes.

At the default 1 point = 10 cents, 50 points is \(5 off. After applying the returned coupon (CART-A here), send the remaining \)15 with the same 50-point total:

curl -X POST https://app.bubblehouse.com/api/v2023061/<shop>/Cart2 \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "preset": "cart",
    "customer": {"email": "customer@example.com"},
    "cart": {
      "amount_subtotal": "15.00",
      "amount_spent": "15.00",
      "items": [{"id": "line-1", "quantity": 1, "amount_spent": "15.00"}],
      "discount_codes": ["CART-A"]
    },
    "desired_redemption_pts": 50,
    "can_apply_cart_effects": true
  }'

cart_changes_to_apply is empty. Pending stays 50 points on CART-A. Sending 100 would mean you want 100 points in total, not 50 extra.

Send desired_redemption_pts: 0 to clear. Echo our coupon code on UpdateOrders4 so the provisional redemption is consumed.

See Cart2 for the full contract. Query spendable points with Cart2 or CustomerBalance3.

Direct redemption with the order

Track the points during checkout on your side, and tell us about the redemption as part of the order. No coupon codes from Bubblehouse.

curl -X POST https://app.bubblehouse.com/api/v2023061/<shop>/UpdateOrders4 \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "orders": [{
      "id": "ORDER-789",
      "status": "confirmed",
      "customer": {
        "id": "CUSTOMER-123",
        "email": "customer@example.com"
      },
      "pts_redeemed_at_checkout": 500
    }]
  }'

We subtract those points when we see the order. A later refund adds them back.

Query spendable points with Cart2 or CustomerBalance3 before you place the order.

If the order redeems more points than the customer has, the balance goes negative. We can display negative balances as zero if that is less confusing for shoppers.

RedeemPoints1

RedeemPoints1 creates a coupon in one call, provisional or not. That is often more convenient for customer-support one-shot redemptions than a cart widget. For a cart widget, prefer Cart2. Cart2 can cover these one-shot cases too.

curl -X POST https://app.bubblehouse.com/api/v2023061/<shop>/RedeemPoints1 \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "customer": {
      "email": "customer@example.com"
    },
    "pts": 500,
    "applied_coupon_codes": ["COUPON1", "COUPON2"],
    "cart_subtotal": "99.99"
  }'

See RedeemPoints1 for parameters and the response. Use the returned coupon in checkout, and remove any codes listed in remove_coupon_codes. After the order is placed, send that coupon on the order as usual.

Previous
Custom shops