Skip to content

Customize pricing

Use price:resolve to transform already loaded pricing. The callback receives base values, the current resolved price, product context, and customer-facing labels.

Apply a synchronous price table

Load remote pricing before registering the hook, or maintain it in a plugin-owned cache. Price resolution itself must return synchronously.

ts
import { PLUGIN_API_VERSION, definePlugin } from '@iconfigurators/plugin-sdk'

type Options = {
  prices: Record<string, number>
}

export default definePlugin<Options>({
  id: 'customer.pricing',
  version: '1.0.0',
  apiVersion: PLUGIN_API_VERSION,

  setup(api, options) {
    const prices = new Map(Object.entries(options?.prices ?? {}))

    api.hooks.filter('price:resolve', (pricing) => {
      const partNumber = pricing.spec?.partNumber
      if (partNumber == null) return pricing

      const customerPrice = prices.get(String(partNumber))
      if (!Number.isFinite(customerPrice)) return pricing

      return {
        ...pricing,
        price: customerPrice,
        compareAtPrice: pricing.price,
        labels: {
          ...pricing.labels,
          current: 'Your price',
          original: 'Regular price',
        },
      }
    })
  },
})

Refresh after cached data changes

If plugin-owned pricing changes after setup, update the cache and request a new pricing pass:

ts
function updatePrice(partNumber: string, price: number) {
  prices.set(partNumber, price)
  api.commands.refreshPricing()
}

Do not start a network request inside price:resolve. Until the required data is available, return the received value unchanged.

Preserve public context

Return a new pricing record and retain fields such as source, productType, wheel, spec, vehicle, and base. Change only the resolved price, comparison price, or labels needed by the integration.

Icon Visualizer developer documentation