Improvements
KelviqProvider — customerId and plansEnabled Props for Pricing
The pricing request now forwards two additional optional props to the product offerings API.customerId — when provided, the pricing response is personalized to that customer (e.g. reflecting their existing subscription state):plansEnabled — a comma-separated list of plan identifiers to include in the response. When omitted, all active plans are returned:New Features
Product Offerings — Pricing & Feature Components
The SDK now supports fetching and displaying product pricing and plan features, with localized currency based on user location.Setup
PassproductId and enable fetchPricingOnMount in your provider config:usePricing() — Pricing Data Hook
Returns the full pricing API response as an AsyncState. Only populated when fetchPricingOnMount is enabled, or after calling refreshPricing() from useKelviq().<KQPrice /> — Render-Prop Price Component
Displays localized pricing for a plan and billing period:| Field | Type | Description |
|---|---|---|
plan | RawPricingPlan | Full plan object |
charge | RawPricingCharge | null | Charge for the requested billing period |
amount | number | Raw numeric amount |
formattedPrice | string | Localized price string (e.g. $9.99) or "Free" |
currencySymbol | string | e.g. $ |
currencyCode | string | e.g. USD |
pricingLocale | string | e.g. en-US |
isFree | boolean | true when priceType === 'FREE' |
hasFreeTrial | boolean | Whether a free trial is available |
trialPeriod | number | Trial length in days |
<KQFeatureList /> — Render-Prop Feature Component
Iterates over enabled features for a plan. Supports optional filtering by feature type:| Prop | Type | Description |
|---|---|---|
planIdentifier | string | The plan to list features for |
featureType | 'BOOLEAN' | 'METER' | Optional filter by feature type |
loadingComponent | ReactNode | Shown while data loads |
fallback | ReactNode | Shown when plan not found or no features match |
children | (data) => ReactNode | Render prop called for each enabled feature |
kqFormatPrice() — Price Formatter Utility
Standalone utility for formatting a numeric amount with a currency symbol:| Option | Type | Default | Description |
|---|---|---|---|
compact | boolean | false | Use compact notation (e.g. 1.2K) |
locale | string | pricingLocale | Override locale for number formatting |
pricingLocale | string | 'en-US' | Locale from the pricing API |
includeCurrencySymbol | boolean | true | Prepend the currency symbol |
New Types
New Exports
New Features
Duplicate featureId Aggregation
The SDK now handles customers with multiple subscriptions that grant entitlements to the same feature. Raw entries are grouped by featureId and aggregated automatically:- METER:
usageLimitandcurrentUsageare summed across entries;remainingis recalculated - BOOLEAN / CUSTOMIZABLE:
hasAccessis OR’d across entries (anytrue→true) The raw un-aggregated entries are preserved in theitemsarray on eachEntitlement.
getEntitlements() — Convenience Accessor
Returns the aggregated entitlements map directly, without the AsyncState wrapper:getRawEntitlements() — Raw API Response
Access the un-aggregated API response with the customerId wrapper:getRawEntitlement(featureId) — Raw Data for a Single Feature
Returns the raw API response filtered to a specific featureId:updateEntitlement() — Client-Side Entitlement Mutation
Update an entitlement in-place, for example after recording a usage increment on the client side. The remaining field is automatically recalculated.Partial<Omit<Entitlement, 'featureId' | 'featureType' | 'items'>>.environment Prop on KelviqProvider
Supports 'production' (default) and 'sandbox', which selects the appropriate default API URL:Breaking Changes
Unified Entitlement Type
The three separate entitlement interfaces and their union type have been replaced by a single unified Entitlement interface:featureKey Renamed to featureId
All props, parameters, and type fields now use featureId to match the backend API naming:Config Renamed to Customizable
| Before | After |
|---|---|
useConfigEntitlement | useCustomizableEntitlement |
ShowWhenConfigEntitled | ShowWhenCustomizableEntitled |
ConfigEntitlement type | Unified Entitlement |
type Field Renamed to featureType with Uppercase Values
| Before | After |
|---|---|
type: 'boolean' | featureType: 'BOOLEAN' |
type: 'customizable' | featureType: 'CUSTOMIZABLE' |
type: 'metered' | featureType: 'METER' |
configuration Field Removed
ConfigEntitlement.configuration has been removed. Customizable entitlements now use the same usageLimit, currentUsage, and remaining fields as metered entitlements.Hooks Return Entitlement | null Directly
All entitlement hooks now return the entitlement object directly (or null) instead of an AsyncState wrapper. Use the top-level isLoading and error from useKelviq() for loading/error states.getEntitlement() Simplified
The generic type parameter and second argument have been removed:hasAccess() Returns boolean (Never undefined)
hasAccess(featureId) now returns false when data is unavailable instead of undefined. No need for nullish checks.Metered Field Renames
| Before | After | Notes |
|---|---|---|
limit | usageLimit | Aligned with the API |
used | currentUsage | Aligned with the API |
resetAt | (removed) | Now per-item: entitlement.items[].resetAt |
hardLimit | hardLimit | Now aggregated: true if any item sets it |
allEntitlements.data Shape Changed
The map is now keyed by featureId (previously featureKey) and contains unified Entitlement objects. Use the new getEntitlements() convenience method:Migration Checklist
- Replace all
featureKeyprops/params withfeatureId - Replace
entitlement.typewithentitlement.featureTypeand update values to uppercase - Replace
useConfigEntitlementwithuseCustomizableEntitlement - Replace
ShowWhenConfigEntitledwithShowWhenCustomizableEntitled - Replace
ConfigEntitlement.configurationwithusageLimit/currentUsage/remaining - Update hook consumers: hooks now return
Entitlement | nulldirectly (notAsyncState) - Remove type parameters from
getEntitlement()calls - Replace
limit→usageLimit,used→currentUsage - Replace
entitlement.resetAtwithentitlement.items[].resetAt - Use
getEntitlements()instead ofallEntitlements.data - Use
getRawEntitlements()for un-aggregated API data
New Features
Duplicate featureId Aggregation
The SDK now handles customers with multiple subscriptions that grant entitlements to the same feature. Raw entries are grouped by featureId and aggregated automatically:- METER:
usageLimitandcurrentUsageare summed across entries;remainingis recalculated - BOOLEAN / CUSTOMIZABLE:
hasAccessis OR’d across entries (anytrue→true)
items array on each Entitlement.getEntitlements() — Convenience Accessor
Returns the aggregated entitlements map directly, without the AsyncState wrapper:getRawEntitlements() — Raw API Response
Access the un-aggregated API response with the customerId wrapper:getRawEntitlement(featureId) — Raw Data for a Single Feature
Returns the raw API response filtered to a specific featureId:updateEntitlement() — Client-Side Entitlement Mutation
Update an entitlement in-place, for example after recording a usage increment on the client side. The remaining field is automatically recalculated.Partial<Omit<Entitlement, 'featureId' | 'featureType' | 'items'>>.environment Prop on KelviqProvider
Supports 'production' (default) and 'sandbox', which selects the appropriate default API URL:Breaking Changes
Unified Entitlement Type
The three separate entitlement interfaces and their union type have been replaced by a single unified Entitlement interface:featureKey Renamed to featureId
All props, parameters, and type fields now use featureId to match the backend API naming:Config Renamed to Customizable
| Before | After |
|---|---|
useConfigEntitlement | useCustomizableEntitlement |
ShowWhenConfigEntitled | ShowWhenCustomizableEntitled |
ConfigEntitlement type | Unified Entitlement |
type Field Renamed to featureType with Uppercase Values
| Before | After |
|---|---|
type: 'boolean' | featureType: 'BOOLEAN' |
type: 'customizable' | featureType: 'CUSTOMIZABLE' |
type: 'metered' | featureType: 'METER' |
configuration Field Removed
ConfigEntitlement.configuration has been removed. Customizable entitlements now use the same usageLimit, currentUsage, and remaining fields as metered entitlements.Hooks Return Entitlement | null Directly
All entitlement hooks now return the entitlement object directly (or null) instead of an AsyncState wrapper. Use the top-level isLoading and error from useKelviq() for loading/error states.getEntitlement() Simplified
The generic type parameter and second argument have been removed:hasAccess() Returns boolean (Never undefined)
hasAccess(featureId) now returns false when data is unavailable instead of undefined. No need for nullish checks.Metered Field Renames
| Before | After | Notes |
|---|---|---|
limit | usageLimit | Aligned with the API |
used | currentUsage | Aligned with the API |
resetAt | (removed) | Now per-item: entitlement.items[].resetAt |
hardLimit | hardLimit | Now aggregated: true if any item sets it |
allEntitlements.data Shape Changed
The map is now keyed by featureId (previously featureKey) and contains unified Entitlement objects. Use the new getEntitlements() convenience method:Migration Checklist
- Replace all
featureKeyprops/params withfeatureId - Replace
entitlement.typewithentitlement.featureTypeand update values to uppercase - Replace
useConfigEntitlementwithuseCustomizableEntitlement - Replace
ShowWhenConfigEntitledwithShowWhenCustomizableEntitled - Replace
ConfigEntitlement.configurationwithusageLimit/currentUsage/remaining - Update hook consumers: hooks now return
Entitlement | nulldirectly (notAsyncState) - Remove type parameters from
getEntitlement()calls - Replace
limit→usageLimit,used→currentUsage - Replace
entitlement.resetAtwithentitlement.items[].resetAt - Use
getEntitlements()instead ofallEntitlements.data - Use
getRawEntitlements()for un-aggregated API data