Miniwall Docs
Web SDK

Purchases and prices

Pass prices to the SDK by package ID, run your own checkout, and report purchases that finish elsewhere.

Miniwall renders; it does not charge. Prices and payment come from your site, matched to the screen by package ID. The SDK never sees card data or amounts you charge.

Package IDs

Each package card in the editor has an ID, such as monthly or annual (see Packages and pricing). Your site gives each ID a price. getPackageIds(paywallJson) lists the IDs a screen uses. The Install SDK page also lists them.

const paywall = await UIKit.loadPaywall({ placement: 'upgrade_button' });
UIKit.getPackageIds(paywall); // ['annual', 'monthly']

If a screen uses an ID with no price, the SDK logs [UIKit] No price for package(s) ... Pass them in products and that card shows without a price.

products

interface ProductInfo {
  price: number;           // major units: 9.99, not 999
  currency: string;        // 'USD'
  period?: Period;         // billing period
  title?: string;          // shown by {{ product.store_product_name }}
  offer?: { price: number; period: Period }; // intro or trial offer; a free trial is price 0
}
type Period = 'day' | 'week' | 'month' | 'year' | 'lifetime' | { unit: 'day' | 'week' | 'month' | 'year'; count: number };
products: {
  monthly: { price: 9.99, currency: 'USD', period: 'month' },
  annual: { price: 59.99, currency: 'USD', period: 'year', offer: { price: 0, period: { unit: 'day', count: 7 } } },
  lifetime: { price: 199, currency: 'USD', period: 'lifetime' },
}

Text variables the SDK fills

Screen text can use these (the editor lists them under Price and plan; see Variables). Prices are formatted for the screen's language.

VariableValue
product.price$9.99
product.currency_code, product.currency_symbolUSD, $
product.periodmonth, 2 weeks, lifetime
product.period_abbreviatedmo, 2 wk
product.period_with_unit1 month, 2 weeks
product.period_in_days, _weeks, _months, _yearsRounded counts (years round down)
product.periodlymonthly, every 2 weeks
product.price_per_day, _week, _month, _yearThe price converted to that unit
product.price_per_period$9.99/month
product.price_per_period_abbreviated$9.99/mo
product.store_product_nametitle
product.relative_discount33%. Compares each recurring package's monthly price with the most expensive one. Only for cheaper packages, and only when at least two recurring packages exist.
product.offer_price, product.offer_period and the other offer_ formsFrom offer
custom.NAMEFrom customVariables

Period variables need a period. price_per_* is not set for lifetime. Use variablesPerPackage to override any value as text, per package. buildProductVariables(products, locale?) returns the computed values if you want to inspect them.

Stripe prices

productsFromStripe turns Stripe Price objects, fetched by your server, into products. It handles zero-decimal currencies and skips prices with no unit_amount.

// server
const prices = {
  monthly: await stripe.prices.retrieve('price_...', { expand: ['product'] }),
  annual: await stripe.prices.retrieve('price_...', { expand: ['product'] }),
};
res.json(productsFromStripe(prices));

Checkout

Run it in onPurchase. See Callbacks. Redirecting away is fine, see below.

reportPurchase

If checkout leaves the page (for example Stripe Checkout), the visitor lands on your success page and the SDK has not heard of the purchase. Call reportPurchase there:

function reportPurchase(details?: { packageId?: string; paywallId?: string }): void;
UIKit.configure({ apiKey: 'pk_...' });
UIKit.reportPurchase({ packageId: 'annual' });
  • It credits the screen where the visitor last tapped buy (remembered in localStorage as uikit:pending-purchase).
  • Without a recent buy tap, it credits the last placement the visitor met (shown or held out) in the last 30 days. If they were held out it records a holdout purchase.
  • Pass paywallId to name the screen yourself.
  • It sends at once. It does nothing when analytics are off or there is nothing to credit.
  • With a holdout, call it after every purchase so the groups compare fairly.

On this page