Milly Software
InsightsEngagementBack-in-Stock Notifications from Shopify Chat: Maestra + Klaviyo
Engagement··9 min read

Back-in-Stock Notifications from Shopify Chat: Maestra + Klaviyo

How an AI chat widget routes back-in-stock subscriptions through your existing email infrastructure — Maestra and Klaviyo implementations, the variant-ID format problem, and why upstream validation matters.

V
Viet Le
co-founder · Milly Software

A shopper asks the chat widget about a product, the AI surfaces the right one, and the variant they actually want is sold out. That's the highest-intent moment in any chat conversation. The shopper isn't browsing — they've narrowed down to one product, one color, one size. The only thing standing between them and the sale is timing.

Most chat widgets miss this moment entirely. The AI says "sorry, that's out of stock" and the shopper leaves. A chat widget that catches this moment with a back-in-stock subscription routes that intent into the merchant's existing email infrastructure — Maestra for loyalty-driven brands, Klaviyo for the Shopify mainstream — and the merchant's ESP takes care of the actual notification when restock happens.

The reframe: chat is a BIS funnel

BIS forms on a PDP catch one type of shopper: the kind who scrolls down to the variant picker, sees "Out of Stock," and notices the small "Notify me" link. That's a committed shopper — they've already navigated to the product page, already engaged with the variant grid. The widget catches a wider funnel: shoppers asking "do you have this in blue?" who hadn't yet visited the PDP, shoppers comparing options across multiple products, shoppers using natural language ("the iPhone case in cloud blue") instead of clicking through SKU grids.

From the merchant's perspective, this is incremental coverage. The PDP form keeps catching its committed shoppers; the chat widget catches the conversational ones. Same email list, more entrants.

The widget exposes a subscribe_oos_notification tool to the chat model. When a shopper expresses BIS intent — explicit ("notify me when this is back") or implicit ("when's this back in stock?") — the model collects email + variant and dispatches the subscription through whichever adapter the merchant has configured.

Maestra: async OutofStockNotification

Merchants on Maestra (loyalty + lifecycle marketing) can route BIS subscriptions through Maestra's async OutofStockNotification operation. The widget POSTs to https://api.maestra.io/v3/operations/async with the merchant's endpoint ID and the customer + product payload:

{
  "addProductToList": {
    "product": { "ids": { "shopifyID": "41834101211224" } }
  },
  "customer": {
    "email": "[email protected]",
    "subscriptions": [{ "pointOfContact": "email" }]
  }
}

Maestra accepts the async request, returns a 202, and adds the customer to the product's waiting list. When inventory comes back into Shopify, Maestra's own restock listener fires the notification email — the merchant doesn't need to wire any restock-detection logic on our side. Maestra's existing infrastructure handles delivery.

The variant ID is the bare numeric Shopify variant ID. The adapter strips the GID prefix (gid://shopify/ProductVariant/) before sending — Maestra wants just the integer. Whatever format the AI passes in, the adapter normalizes.

Klaviyo: native /client/back-in-stock-subscriptions

Klaviyo is the dominant ESP on Shopify, so the natural choice was to route BIS through their first-party endpoint — /client/back-in-stock-subscriptions/, the same public endpoint Klaviyo's onsite signup forms use:

POST https://a.klaviyo.com/client/back-in-stock-subscriptions/
     ?company_id=PUBLIC_COMPANY_ID&revamp=true

{
  "data": {
    "type": "back-in-stock-subscription",
    "attributes": {
      "channels": ["EMAIL"],
      "profile": {
        "data": {
          "type": "profile",
          "attributes": { "email": "[email protected]" }
        }
      }
    },
    "relationships": {
      "variant": {
        "data": {
          "type": "catalog-variant",
          "id": "$shopify:::$default:::41834101211224"
        }
      }
    }
  }
}

This endpoint is public — it authenticates with the merchant's Company ID, no private API key required. The same endpoint Klaviyo's embedded forms use. Klaviyo's Shopify catalog sync hydrates the rest of the product context (name, price, SKU, categories) automatically; we don't send any of it. The native "Subscribed to Back in Stock" event fires in the merchant's Klaviyo account with full product details, ready to power flows the merchant already has set up.

Optionally, when the merchant supplies a list ID + a private API key alongside the public Company ID, the adapter also subscribes the BIS submitter to that list with email-marketing consent — mirroring Klaviyo's onsite-form pattern of feeding BIS into the main marketing list.

The variant-ID format problem

Both platforms want a Shopify variant ID. Neither wants it in the same format:

  • Shopify itself uses gid://shopify/ProductVariant/41834101211224 (the GID form) in its GraphQL APIs and 41834101211224 (bare numeric) in its REST APIs. Both formats are common in the wild.
  • Maestra wants 41834101211224 — bare numeric, GID prefix stripped.
  • Klaviyo wants $shopify:::$default:::41834101211224 — the Shopify Catalog Item ID format that ties the variant back into Klaviyo's catalog sync.

The widget always passes the AI a normalized form (the bare numeric — extracted from product context, regardless of where it came from). Each adapter wraps it in the format the upstream API expects. The model never has to know the per-platform idiom.

Permissive vs strict upstreams

Maestra is permissive. The async operation accepts any string as shopifyID, returns 202, and creates a waiting list entry — even if the variant doesn't exist in the merchant's catalog. A subscription that points at a phantom variant lives in the system but never triggers.

Klaviyo is strict. The BIS endpoint validates the variant against Klaviyo's Shopify catalog sync; an unknown variant ID returns a 404 with variant_not_found.

Both behaviors are reasonable defaults for the respective platforms. But running the same widget through both surfaces the difference: a latent bug in our variant-ID extraction — fallbacks to placeholder values, missed edge cases on JSON-feed-style stores where the variant map is keyed by SKU — is invisible against Maestra (silently corrupts the waitlist) and screams against Klaviyo (404 on the first test).

We learned this the loud way after Klaviyo started failing loud and Maestra didn't. The fix on our end is a catalog cross-check at the OOS-subscribe route: before forwarding to either platform, the route validates the variant against the merchant's products table. A bad variant ID returns a 400 at our boundary instead of being passed up — Klaviyo's validation no longer carries the load alone, and Maestra stops accepting phantoms it can't deliver on.

Which platform fits which merchant

Both adapters do the same thing from the chat-widget's perspective: collect email + variant, dispatch upstream, return success. The choice is about which infrastructure the merchant already runs.

  • Klaviyo — the obvious default for most Shopify merchants. Already running their email marketing here. Already has "Subscribed to Back in Stock" flows configured (or can copy a template). The catalog sync handles product hydration, so the BIS subscription immediately benefits from the rest of the merchant's Klaviyo investment.
  • Maestra — for loyalty-first brands where Maestra is already the customer-data hub. Async operation fits Maestra's broader event-driven infrastructure. Restock detection rides on Maestra's own Shopify listeners.

We don't recommend running both. The adapters don't deduplicate across platforms, so a single OOS subscription would send two notification emails when restock happens — once from Klaviyo, once from Maestra. Pick the merchant's primary ESP and route through it.

For everything else — merchants on a different ESP entirely (Mailchimp, Omnisend, Klaviyo's smaller competitors), or merchants with a custom restock pipeline — the BIS data flows through the standard custom-webhook path. Same subscribe_oos_notification tool call, just routed to the merchant's endpoint instead of one of these first-party adapters.

Try Milly Chat

Want to see how this fits your store?
We'll set up a working session.

Get it on ShopifyTalk to sales →