Skip to main content
The @kelviq/react-sdk provides a seamless way to integrate kelviq entitlement management into your React applications.

Overview

  • A React Context Provider (KelviqProvider) to initialize and configure the SDK.
  • Hooks to easily access entitlement status and data within your components.
  • Conditional rendering components to show or hide UI elements based on feature access.
  • Automatic and manual data fetching and caching mechanisms.
The SDK fetches all entitlements for a given organization and customer, caches them, and makes them available throughout your application via React Context and custom hooks.

2. Installation

Install the SDK using npm or yarn:
npm install @kelviq/react-sdk
# or
yarn add @kelviq/react-sdk

You will also need react as a peer dependency.

3. Setup & Configuration

KelviqProvider

The core of the SDK is the KelviqProvider. You need to wrap your application (or the relevant part of it) with this provider. It initializes the SDK and makes entitlement data available to its children components via context.
// In your App.tsx or main application entry point
import React from 'react';
import { KelviqProvider } from '@kelviq/react-sdk';

const App = () => {
  return (
    <KelviqProvider
      customerId="your-customer-id"
      accessToken="your-access-token"
    >
      <MyAppContent />
    </KelviqProvider>
  );
};

const MyAppContent = () => {

  return (
    <div>
      <h1>My Application</h1>
    </div>
  );

};

export default App;

Required Props for KelviqProvider

  • customerId: string
    • The ID of the customer for whom entitlements are being fetched. This will be sent as a query parameter (customer_id).
  • accessToken: string | null
    • Your Client API Key for authenticating requests to the Kelviq API. This key is safe to expose in client-side code. You can find it in the Developers section of your Kelviq dashboard. Never use your Server API Key in client-side code.

Optional Props for KelviqProvider

4. Fetching Entitlements

Automatic Fetching on Mount

By default (fetchEntitlementsOnMount: true in the config prop, or if config or this specific option is omitted), the SDK will attempt to fetch all entitlements for the specified customerId as soon as the KelviqProvider is mounted. The isLoading state from useKelviq() will be true during this initial fetch.

Manual Fetching

If fetchEntitlementsOnMount is set to false, or if you need to re-fetch entitlements at any point (e.g., after a user action that might change their entitlements), you can use the refreshAllEntitlements function.

5. Accessing Entitlement Data (Hooks)

The SDK provides several hooks to access entitlement data and SDK state.

useKelviq()

This is the primary hook to access the SDK’s context.
  • Returns: KelviqContextValue object containing:
    • allEntitlements: AsyncState<EntitlementMap | null>: The state object for all fetched entitlements.
      • data: An EntitlementMap (a Record<string, Entitlement>) where keys are featureIds, or null if not loaded or error.
      • isLoading: Boolean indicating if the allEntitlements data is currently being fetched/refreshed.
      • error: An Error object if the last fetch failed, otherwise null.
    • refreshAllEntitlements: () => Promise<void>: Function to manually trigger a re-fetch of all entitlements.
    • getEntitlements: () => EntitlementMap: Returns all aggregated entitlements as a Record<string, Entitlement> keyed by featureId. Returns an empty object if data has not been fetched yet.
    • getEntitlement: (featureId: string) => Entitlement | null: Returns the aggregated entitlement for a given featureId, or null if not found or not yet loaded.
    • getRawEntitlements: () => EntitlementsResponse | null: Returns the raw API response with customerId and the un-aggregated entitlements array (duplicate featureId entries are preserved). Returns null if data has not been fetched yet.
    • getRawEntitlement: (featureId: string) => EntitlementsResponse | null: Returns the raw API response filtered to a specific featureId, with customerId and only the matching entries.
    • hasAccess: (featureId: string) => boolean: A utility function to quickly check access for a feature. Returns true if access is granted, false if denied, feature not found, or data is not yet loaded.
    • updateEntitlement: (featureId: string, data: Partial<...>) => void: Updates a cached entitlement in-place. Accepts partial data (excluding featureId, featureType, and items). Automatically recalculates remaining when usageLimit or currentUsage are updated.
    • subscriptions: AsyncState<RawSubscriptionData[] | null>: The state object for the customer’s subscriptions. Only populated when fetchSubscriptionsOnMount is true or after calling refreshSubscriptions().
    • refreshSubscriptions: () => Promise<void>: Function to manually trigger a re-fetch of the customer’s subscriptions.
    • customer: AsyncState<RawCustomerApiResponse | null>: The state object for customer data. Only populated when fetchCustomerOnMount is true or after calling refreshCustomer().
    • refreshCustomer: () => Promise<void>: Function to manually trigger a re-fetch of the customer data.
    • isLoading: boolean: A global loading state indicating if the SDK is performing its initial configured fetch or a refresh operation.
    • error: Error | null: A global error state reflecting any error from the last fetch operation initiated by the provider.
    • customerId: string: The customer ID passed to the provider.
    • environment: string: The environment ('production' or 'sandbox') passed to the provider.
    • apiUrl: string: The resolved API URL used by the provider.
    • entitlementsPath: string: The entitlements path passed to the provider.

hasAccess(featureId)

Quickly check if a customer has access to a feature.
const { hasAccess } = useKelviq();
const canUse = hasAccess("premium-reporting");
true

getEntitlement(featureId)

Returns the aggregated entitlement for a given feature. When the API returns multiple entries for the same featureId (e.g. from different subscriptions), the SDK groups them and exposes aggregated totals at the top level.
const { getEntitlement } = useKelviq();
const entitlement = getEntitlement("api-calls-quota");
{
  "featureId": "api-calls-quota",
  "featureType": "METER",
  "hasAccess": true,
  "currentUsage": 150,
  "usageLimit": 1000,
  "remaining": 850,
  "hardLimit": true,
  "items": [
    {
      "featureId": "api-calls-quota",
      "featureType": "METER",
      "hasAccess": true,
      "resetAt": "2025-06-01T00:00:00Z",
      "hardLimit": false,
      "usageLimit": 500,
      "currentUsage": 100,
      "remaining": 400
    },
    {
      "featureId": "api-calls-quota",
      "featureType": "METER",
      "hasAccess": true,
      "resetAt": "2025-07-01T00:00:00Z",
      "hardLimit": true,
      "usageLimit": 500,
      "currentUsage": 50,
      "remaining": 450
    }
  ]
}
{
  "featureId": "enable-dark-mode",
  "featureType": "BOOLEAN",
  "hasAccess": true,
  "currentUsage": 0,
  "usageLimit": null,
  "remaining": null,
  "hardLimit": false,
  "items": [
    {
      "featureId": "enable-dark-mode",
      "featureType": "BOOLEAN",
      "hasAccess": true
    }
  ]
}
{
  "featureId": "max-items-per-page",
  "featureType": "CUSTOMIZABLE",
  "hasAccess": true,
  "currentUsage": 0,
  "usageLimit": 50,
  "remaining": 50,
  "hardLimit": false,
  "items": [
    {
      "featureId": "max-items-per-page",
      "featureType": "CUSTOMIZABLE",
      "hasAccess": true,
      "usageLimit": 50,
      "currentUsage": 0,
      "remaining": 50
    }
  ]
}

getEntitlements()

Returns all aggregated entitlements as a Record<string, Entitlement> keyed by featureId.
const { getEntitlements } = useKelviq();
const entitlements = getEntitlements();
{
  "api-calls-quota": {
    "featureId": "api-calls-quota",
    "featureType": "METER",
    "hasAccess": true,
    "currentUsage": 150,
    "usageLimit": 1000,
    "remaining": 850,
    "hardLimit": true,
    "items": [
      {
        "featureId": "api-calls-quota",
        "featureType": "METER",
        "hasAccess": true,
        "resetAt": "2025-06-01T00:00:00Z",
        "hardLimit": false,
        "usageLimit": 500,
        "currentUsage": 100,
        "remaining": 400
      },
      {
        "featureId": "api-calls-quota",
        "featureType": "METER",
        "hasAccess": true,
        "resetAt": "2025-07-01T00:00:00Z",
        "hardLimit": true,
        "usageLimit": 500,
        "currentUsage": 50,
        "remaining": 450
      }
    ]
  },
  "enable-dark-mode": {
    "featureId": "enable-dark-mode",
    "featureType": "BOOLEAN",
    "hasAccess": true,
    "currentUsage": 0,
    "usageLimit": null,
    "remaining": null,
    "hardLimit": false,
    "items": [
      {
        "featureId": "enable-dark-mode",
        "featureType": "BOOLEAN",
        "hasAccess": true
      }
    ]
  }
}

getRawEntitlements()

Returns the raw, un-aggregated API response with customerId. Duplicate featureId entries from multiple subscriptions are preserved as-is.
const { getRawEntitlements } = useKelviq();
const raw = getRawEntitlements();
{
  "customerId": "cust_456",
  "entitlements": [
    {
      "featureId": "api-calls-quota",
      "featureType": "METER",
      "hasAccess": true,
      "resetAt": "2025-06-01T00:00:00Z",
      "hardLimit": false,
      "usageLimit": 500,
      "currentUsage": 100,
      "remaining": 400
    },
    {
      "featureId": "api-calls-quota",
      "featureType": "METER",
      "hasAccess": true,
      "resetAt": "2025-07-01T00:00:00Z",
      "hardLimit": true,
      "usageLimit": 500,
      "currentUsage": 50,
      "remaining": 450
    },
    {
      "featureId": "enable-dark-mode",
      "featureType": "BOOLEAN",
      "hasAccess": true
    }
  ]
}

getRawEntitlement(featureId)

Returns the raw API response filtered to a specific featureId. Useful for accessing per-subscription data for a single feature.
const { getRawEntitlement } = useKelviq();
const raw = getRawEntitlement("api-calls-quota");
{
  "customerId": "cust_456",
  "entitlements": [
    {
      "featureId": "api-calls-quota",
      "featureType": "METER",
      "hasAccess": true,
      "resetAt": "2025-06-01T00:00:00Z",
      "hardLimit": false,
      "usageLimit": 500,
      "currentUsage": 100,
      "remaining": 400
    },
    {
      "featureId": "api-calls-quota",
      "featureType": "METER",
      "hasAccess": true,
      "resetAt": "2025-07-01T00:00:00Z",
      "hardLimit": true,
      "usageLimit": 500,
      "currentUsage": 50,
      "remaining": 450
    }
  ]
}

updateEntitlement(featureId, data)

Updates a cached entitlement in-place. Useful for optimistically updating the UI after a usage increment without waiting for a full refresh. The remaining field is automatically recalculated when usageLimit or currentUsage are updated.
const { updateEntitlement } = useKelviq();

// After the user performs an action that consumes usage
updateEntitlement("api-calls-quota", { currentUsage: 151 });
{
  "featureId": "api-calls-quota",
  "featureType": "METER",
  "hasAccess": true,
  "currentUsage": 151,
  "usageLimit": 1000,
  "remaining": 849,
  "hardLimit": true,
  "items": [...]
}
Accepts Partial<Omit<Entitlement, 'featureId' | 'featureType' | 'items'>>. You can update any combination of hasAccess, currentUsage, usageLimit, and remaining.

useAllEntitlements()

A convenience hook that directly returns the allEntitlements state object.
  • Returns: AsyncState<EntitlementMap | null>
import { useAllEntitlements } from '@kelviq/react-sdk';

function EntitlementsList() {
  const { data: entitlementsMap, isLoading, error } = useAllEntitlements();

  if (isLoading) return <p>Loading all entitlements...</p>;
  if (error) return <p>Error loading entitlements: {error.message}</p>;
  if (!entitlementsMap) return <p>No entitlements data.</p>;

  return (
    <ul>
      {Object.values(entitlementsMap).map(ent => (
        <li key={ent.featureId}>
          {ent.featureId}: {ent.hasAccess ? 'Enabled' : 'Disabled'} ({ent.featureType})
        </li>
      ))}
    </ul>
  );
}

{
  "api-calls-quota": {
    "featureId": "api-calls-quota",
    "featureType": "METER",
    "hasAccess": true,
    "currentUsage": 150,
    "usageLimit": 1000,
    "remaining": 850,
    "hardLimit": true,
    "items": [...]
  },
  "enable-dark-mode": {
    "featureId": "enable-dark-mode",
    "featureType": "BOOLEAN",
    "hasAccess": true,
    "currentUsage": 0,
    "usageLimit": null,
    "remaining": null,
    "hardLimit": false,
    "items": [...]
  },
  "max-items-per-page": {
    "featureId": "max-items-per-page",
    "featureType": "CUSTOMIZABLE",
    "hasAccess": true,
    "currentUsage": 0,
    "usageLimit": 50,
    "remaining": 50,
    "hardLimit": false,
    "items": [...]
  }
}

useBooleanEntitlement(featureId: string)

Returns the aggregated entitlement for a specific boolean feature from the cache.
  • Arguments:
    • featureId: string: The identifier of the boolean feature.
  • Returns: Entitlement | null
import { useBooleanEntitlement } from '@kelviq/react-sdk';

const entitlement = useBooleanEntitlement("enable-dark-mode");
{
  "featureId": "enable-dark-mode",
  "featureType": "BOOLEAN",
  "hasAccess": true,
  "currentUsage": 0,
  "usageLimit": null,
  "remaining": null,
  "hardLimit": false,
  "items": [
    {
      "featureId": "enable-dark-mode",
      "featureType": "BOOLEAN",
      "hasAccess": true
    }
  ]
}

useCustomizableEntitlement(featureId: string)

Returns the aggregated entitlement for a specific customizable feature from the cache.
  • Arguments:
    • featureId: string: The identifier of the customizable feature.
  • Returns: Entitlement | null
import { useCustomizableEntitlement } from '@kelviq/react-sdk';

const entitlement = useCustomizableEntitlement("max-items-per-page");
{
  "featureId": "max-items-per-page",
  "featureType": "CUSTOMIZABLE",
  "hasAccess": true,
  "currentUsage": 0,
  "usageLimit": 50,
  "remaining": 50,
  "hardLimit": false,
  "items": [
    {
      "featureId": "max-items-per-page",
      "featureType": "CUSTOMIZABLE",
      "hasAccess": true,
      "usageLimit": 50,
      "currentUsage": 0,
      "remaining": 50
    }
  ]
}

useMeteredEntitlement(featureId: string)

Returns the aggregated entitlement for a specific metered feature from the cache.
  • Arguments:
    • featureId: string: The identifier of the metered feature.
  • Returns: Entitlement | null
import { useMeteredEntitlement } from '@kelviq/react-sdk';

const entitlement = useMeteredEntitlement("api-calls-quota");
{
  "featureId": "api-calls-quota",
  "featureType": "METER",
  "hasAccess": true,
  "currentUsage": 150,
  "usageLimit": 1000,
  "remaining": 850,
  "hardLimit": true,
  "items": [
    {
      "featureId": "api-calls-quota",
      "featureType": "METER",
      "hasAccess": true,
      "resetAt": "2025-06-01T00:00:00Z",
      "hardLimit": false,
      "usageLimit": 500,
      "currentUsage": 100,
      "remaining": 400
    },
    {
      "featureId": "api-calls-quota",
      "featureType": "METER",
      "hasAccess": true,
      "resetAt": "2025-07-01T00:00:00Z",
      "hardLimit": true,
      "usageLimit": 500,
      "currentUsage": 50,
      "remaining": 450
    }
  ]
}

useSubscriptions()

Returns the customer’s subscription data. Only populated when fetchSubscriptionsOnMount is enabled in the provider config, or after calling refreshSubscriptions() from useKelviq().
  • Returns: AsyncState<RawSubscriptionData[] | null>
import { useSubscriptions } from '@kelviq/react-sdk';

function SubscriptionInfo() {
  const { data: subscriptions, isLoading, error } = useSubscriptions();

  if (isLoading) return <p>Loading subscriptions...</p>;
  if (error) return <p>Error: {error.message}</p>;
  if (!subscriptions) return <p>No subscriptions found.</p>;

  return (
    <ul>
      {subscriptions.map(sub => (
        <li key={sub.id}>
          {sub.plan.name}{sub.status} ({sub.recurrence})
        </li>
      ))}
    </ul>
  );
}
[
  {
    "id": "sub-uuid-1",
    "externalSubscriptionId": "ext-sub-123",
    "startDate": "2025-01-01T00:00:00Z",
    "endDate": null,
    "billingPeriodStartTime": "2025-06-01T00:00:00Z",
    "billingPeriodEndTime": "2025-07-01T00:00:00Z",
    "amount": "49.99",
    "recurrence": "monthly",
    "currency": "USD",
    "status": "active",
    "product": {
      "name": "Pro Plan",
      "identifier": "pro-plan"
    },
    "plan": {
      "name": "Pro Monthly",
      "identifier": "pro-monthly"
    },
    "features": [
      {
        "featureId": "api-calls-quota",
        "featureType": "METER",
        "hasAccess": true,
        "usageLimit": 1000,
        "currentUsage": 150,
        "remaining": 850
      }
    ],
    "trialDaysRemaining": null,
    "customerId": "cust_456"
  }
]
You must enable fetchSubscriptionsOnMount: true in the provider’s config prop, or call refreshSubscriptions() manually, for this hook to return data.

useCustomer()

Returns the customer data. Only populated when fetchCustomerOnMount is enabled in the provider config, or after calling refreshCustomer() from useKelviq().
  • Returns: AsyncState<RawCustomerApiResponse | null>
import { useCustomer } from '@kelviq/react-sdk';

function CustomerProfile() {
  const { data: customer, isLoading, error } = useCustomer();

  if (isLoading) return <p>Loading customer...</p>;
  if (error) return <p>Error: {error.message}</p>;
  if (!customer) return <p>No customer data.</p>;

  return (
    <div>
      <h2>{customer.name}</h2>
      <p>{customer.email}</p>
      {customer.billingAddress && (
        <p>{customer.billingAddress.city}, {customer.billingAddress.state}</p>
      )}
    </div>
  );
}
{
  "id": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
  "customerId": "unique-customer-id-123",
  "name": "John Doe",
  "email": "customer@example.com",
  "details": {},
  "metadata": {
    "source": "sdk_import",
    "priority": "high"
  },
  "billingAddress": {
    "country": "IN",
    "line1": "123 Main Street",
    "line2": "Apt 4B",
    "postalCode": "560001",
    "city": "Bangalore",
    "state": "Karnataka"
  },
  "createdOn": "2025-06-04T06:03:30.195790Z",
  "modifiedOn": "2025-06-04T06:03:30.195831Z"
}
You must enable fetchCustomerOnMount: true in the provider’s config prop, or call refreshCustomer() manually, for this hook to return data.
Example using a specific entitlement hook:
import { useBooleanEntitlement, useKelviq } from '@kelviq/react-sdk';

function FeatureSpecificComponent({ featureId }: { featureId: string }) {
  const { isLoading, error } = useKelviq();
  const entitlement = useBooleanEntitlement(featureId);

  if (isLoading) return <p>Loading feature {featureId}...</p>;
  if (error) return <p>Error loading feature {featureId}: {error.message}</p>;

  if (entitlement && entitlement.hasAccess) {
    return <p>You have access to {featureId}!</p>;
  } else {
    return <p>You do not have access to {featureId}.</p>;
  }
}

6. Conditional Rendering Components

These components provide a declarative way to render UI based on entitlement status. They internally use the respective hooks. Common Props:
  • featureId: string: The unique identifier of the feature to check.
  • children: ReactNode | ((data: Entitlement) => ReactNode):
    • If a ReactNode, it’s rendered when the user is entitled and conditions are met.
    • If a function (render prop), it’s called with the aggregated Entitlement data and its return value is rendered.
  • fallback?: ReactNode: Content to render if the user is not entitled, or if data is loading (and no loadingComponent is provided), or if an error occurs. Defaults to null.
  • loadingComponent?: ReactNode: Specific content to render while the entitlement data is loading. Overrides fallback during loading.

ShowWhenBooleanEntitled

Renders children if the boolean feature is enabled (hasAccess: true).
import { ShowWhenBooleanEntitled } from '@kelviq/react-sdk';

<ShowWhenBooleanEntitled
  featureId="enable-dark-mode"
  loadingComponent={<p>Checking theme settings...</p>}
  fallback={<p>Dark mode is not available.</p>}
>
  <button>Toggle Dark Mode</button>
</ShowWhenBooleanEntitled>

<ShowWhenBooleanEntitled featureId="show-advanced-settings">
  {(entitlementData) => (
    <div>Advanced settings for {entitlementData.featureId} are visible!</div>
  )}
</ShowWhenBooleanEntitled>

{
  "featureId": "show-advanced-settings",
  "featureType": "BOOLEAN",
  "hasAccess": true,
  "currentUsage": 0,
  "usageLimit": null,
  "remaining": null,
  "hardLimit": false,
  "items": [
    {
      "featureId": "show-advanced-settings",
      "featureType": "BOOLEAN",
      "hasAccess": true
    }
  ]
}

ShowWhenCustomizableEntitled

Renders children if the customizable feature is enabled (hasAccess: true).
import { ShowWhenCustomizableEntitled } from '@kelviq/react-sdk';

<ShowWhenCustomizableEntitled
  featureId="max-items-per-page"
  loadingComponent={<p>Loading display settings...</p>}
  fallback={<p>Default item limit applies.</p>}
>
  {(entitlementData) => (
    <p>You have access to {entitlementData.featureId}.</p>
  )}
</ShowWhenCustomizableEntitled>

{
  "featureId": "max-items-per-page",
  "featureType": "CUSTOMIZABLE",
  "hasAccess": true,
  "currentUsage": 0,
  "usageLimit": 50,
  "remaining": 50,
  "hardLimit": false,
  "items": [
    {
      "featureId": "max-items-per-page",
      "featureType": "CUSTOMIZABLE",
      "hasAccess": true,
      "usageLimit": 50,
      "currentUsage": 0,
      "remaining": 50
    }
  ]
}

ShowWhenMeteredEntitled

Renders children if the metered feature is enabled and, by default, if remaining usage is greater than 0 or unlimited (usageLimit is null).
  • Optional Prop:
    • condition?: (data: Entitlement) => boolean: A custom function to further determine if children should render based on the entitlement data.
  • Children Prop: Can be ReactNode or (data: Entitlement) => ReactNode.
import { ShowWhenMeteredEntitled } from '@kelviq/react-sdk';

<ShowWhenMeteredEntitled
  featureId="api-calls-quota"
  loadingComponent={<p>Loading API quota...</p>}
  fallback={<p>API call limit reached or feature not available.</p>}
>
  {(meterData) => (
    <div>
      <p>API Calls Used: {meterData.currentUsage} / {meterData.usageLimit === null ? 'Unlimited' : meterData.usageLimit}</p>
      <p>Remaining: {meterData.remaining === null ? 'Unlimited' : meterData.remaining}</p>
    </div>
  )}
</ShowWhenMeteredEntitled>

{
  "featureId": "api-calls-quota",
  "featureType": "METER",
  "hasAccess": true,
  "currentUsage": 150,
  "usageLimit": 1000,
  "remaining": 850,
  "hardLimit": true,
  "items": [
    {
      "featureId": "api-calls-quota",
      "featureType": "METER",
      "hasAccess": true,
      "resetAt": "2025-06-01T00:00:00Z",
      "hardLimit": false,
      "usageLimit": 500,
      "currentUsage": 100,
      "remaining": 400
    },
    {
      "featureId": "api-calls-quota",
      "featureType": "METER",
      "hasAccess": true,
      "resetAt": "2025-07-01T00:00:00Z",
      "hardLimit": true,
      "usageLimit": 500,
      "currentUsage": 50,
      "remaining": 450
    }
  ]
}

7. Key Types

The SDK exports several types for better integration with TypeScript. Some key ones include:
  • KelviqContextValue: The shape of the object returned by useKelviq().
  • KelviqApiBehaviorOptions: Configuration options for the config prop.
  • AsyncState<T>: Generic type for asynchronous data states ({ data, isLoading, error }).
  • Entitlement: The unified entitlement type with aggregated data and an items array containing the raw API objects.
  • EntitlementMap: The structure of the cached entitlements (Record<string, Entitlement>), keyed by featureId.
  • EntitlementsResponse: The raw API response shape ({ customerId, entitlements }) returned by getRawEntitlements() and getRawEntitlement().
  • RawEntitlementsApiResponse and related Raw... types: Represent the structure of the direct API response.
  • RawSubscriptionData: A single subscription object as returned by the subscriptions API, including plan, product, features, status, amount, recurrence, etc.
  • RawCustomerApiResponse: Customer data as returned by the customer API, including id, customerId, name, email, billingAddress, details, metadata, createdOn, and modifiedOn.
  • RawBillingAddress: The billing address object (country, line1, line2, postalCode, city, state).
You can import these types directly from the main SDK entry:
import type {
  Entitlement,
  EntitlementMap,
  EntitlementsResponse,
  RawSubscriptionData,
  RawCustomerApiResponse,
  RawBillingAddress,
} from '@kelviq/react-sdk';

8. Error Handling

  • Provider Level: The onError callback in config (KelviqApiBehaviorOptions) can be used to globally handle errors that occur during the entitlement fetching process initiated by the provider.
  • Context Level: useKelviq() returns a global isLoading: boolean and error: Error | null state, reflecting the provider’s most recent fetch operation. Use these for loading/error UI in your components.
  • allEntitlements Level: The allEntitlements object from useKelviq() or useAllEntitlements() also carries its own isLoading and error fields within the AsyncState wrapper.

9. Example Usage

A comprehensive example is provided within the comments of the SDK code, demonstrating provider setup and component usage. The core setup involves:
  1. Wrapping your application with KelviqProvider and providing the required props (customerId, accessToken)
  2. Using hooks like useBooleanEntitlement or conditional components like ShowWhenBooleanEntitled in your components to control UI and behavior based on entitlements.

10. API Request Service

The SDK relies on an apiRequest function for making HTTP requests. The SDK’s KelviqProvider passes configuration like timeout, maxRetries, backoffBaseDelay, and accessToken to this function.
  • Your Responsibility: You need to ensure that your project includes an implementation of this apiRequest service (e.g., in src/services/makeRequest.service.ts) that matches the ApiRequestConfig and ApiResponse interfaces used by the SDK. This service should handle actual HTTP communication, including appending query parameters passed via ApiRequestConfig.queryParams and using the accessToken to set the Authorization header.
  • The placeholder apiRequest function included in the SDK’s source code is for demonstration and type-checking purposes only and will not make real API calls.

11. Project Structure (for contributors/reference)

The SDK source code (lib/) is organized as follows:
  • components/: Contains conditional rendering React components.
    • ShowWhenBooleanEntitled.tsx
    • ShowWhenCustomizableEntitled.tsx
    • ShowWhenMeteredEntitled.tsx
    • ShowWhenEntitledInternal.tsx (Internal helper, not typically exported)
  • contexts/: Defines the React Context and Provider.
    • KelviqContext.ts
    • KelviqProvider.tsx
  • hooks/: Contains all custom React Hooks.
    • useKelviq.ts
    • useAllEntitlements.ts
    • useBooleanEntitlement.ts
    • useCustomizableEntitlement.ts
    • useMeteredEntitlement.ts
    • useSubscriptions.ts
    • useCustomer.ts
    • index.ts (Exports all hooks)
  • types/: Contains all TypeScript definitions.
    • api.types.ts (Raw types from API)
    • sdk.types.ts (Processed types for SDK and public use)
    • index.ts (Re-exports all types)
  • utils/: Contains utility functions.
    • transformations.ts (For transformApiEntitlements)
    • index.ts (Exports utilities)
  • index.ts: The main entry point of the SDK, re-exporting all public APIs (provider, hooks, components, types).

Using the Sandbox

If you want to use the sandbox, you need to set the environment option to sandbox in the KelviqProvider.
<KelviqProvider 
  customerId="YOUR_CUSTOMER_ID"
  accessToken="YOUR_ACCESS_TOKEN"
  environment="sandbox">
      {/* Your app components */}
</KelviqProvider>