> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stigg.io/llms.txt
> Use this file to discover all available pages before exploring further.

# JavaScript

# Overview

The JavaScript SDK allows you access customer data from Stigg, and leverage it to implement mind-blowing customer experiences.

<Note>
  Stigg also offers plug-and-play customizable widgets for [React](/api-and-sdks/integration/frontend/react), [Vue.js](/api-and-sdks/integration/frontend/vuejs), [Webflow, Wordpress, and plain HTML](/api-and-sdks/integration/frontend/html).
</Note>

# Installing the SDK

The first step is to install the Stigg SDK as a dependency in your application using your application's dependency manager:

<CodeGroup>
  ```shell shell theme={null}
  npm install @stigg/js-client-sdk
  ```
</CodeGroup>

# Retrieving the publishable key

In the Stigg app, go to **Integrations > API keys**.

Copy the **Publishable key** of the relevant environment.

# Initializing the SDK

Initializing client instance with the publishable key. You can either pass the customer ID when initializing the client instance or using `setCustomerId` function as shown below.

<CodeGroup>
  ```javascript JavaScript theme={null}
  import Stigg from '@stigg/js-client-sdk';

  const stiggClient = Stigg.initialize({  
      apiKey: 'YOUR_PUBLISHABLE_KEY',
      customerId: '41XTDbE'
  });

  export default stiggClient;
  ```
</CodeGroup>

To find out when the client is ready, you can use `waitForInitialization` which return a promise that resolves when the client is ready to use, or rejects when the initialization failed.

<CodeGroup>
  ```javascript Javascript theme={null}
  try {
    await stiggClient.waitForInitialization();
    // initialization succeeded, entitlements values are now available
  } catch (err) {
    // initialization failed
  }
  ```
</CodeGroup>

# Setting the customer context

Set the customer ID of the user that's accessing your app, usually after the customer signs in or restores a session:

<CodeGroup>
  ```javascript JavaScript theme={null}
  stiggClient.setCustomerId('customer-demo-01');
  ```
</CodeGroup>

# Setting the customer resource context

For [Multi-instance products](/guides/i-want-to/add-multiple-subscriptions), set the customer resource ID of the user that's accessing your app, usually after the customer enters into a resource context:

<CodeGroup>
  ```javascript JavaScript theme={null}
  stiggClient.setResource('resource-01');
  ```
</CodeGroup>

# Getting all of the entitlements of a specific customer

<CodeGroup>
  ```javascript JavaScript theme={null}
  const entitlements = await stiggClient.getEntitlements();

  // all the entitlements the customer is entitled to  
  entitlements.forEach((entitlement) => {  
    console.log(JSON.stringify(entitlement));  
  });
  ```
</CodeGroup>

<Expandable title="Result">
  <CodeGroup>
    ```json JSON theme={null}
    [
      {
        "isFallback": false,
        "hasAccess": true,
        "isUnlimited": false,
        "value": 100,
        "feature": {
          "id": "feature-demo-01",
          "featureType": "Numeric",
          "meterType": "None",
          "units": "request",
          "unitsPlural": "requests",
          "displayName": "Feature #1",
          "description": "",
          "isMetered": false
        }
      },
      {
        "isFallback": false,
        "hasAccess": true,
        "feature": {
          "id": "feature-demo-02",
          "featureType": "Boolean",
          "meterType": "None",
          "displayName": "Feature #2",
          "description": "",
          "isMetered": false
        }
      }
    ]
    ```
  </CodeGroup>
</Expandable>

# Getting the entitlement of a customer to a specific feature

### Checking the entitlement for a boolean feature

<CodeGroup>
  ```javascript JavaScript theme={null}
  const entitlement = stiggClient.getBooleanEntitlement({  
    featureId: 'feature-demo-02'  
  });

  if (entitlement.hasAccess) {  
    // customer has access to the feature  
  } else {  
    // no access, offer an upsell  
  }
  ```
</CodeGroup>

<Expandable title="Result - has access">
  <CodeGroup>
    ```json JSON theme={null}
    {
      "isFallback": false,
      "hasAccess": true,
      "feature": {
        "id": "feature-demo-02",
        "featureType": "Boolean",
        "meterType": "None",
        "displayName": "Feature #2",
        "description": "",
        "isMetered": false
      }
    }
    ```
  </CodeGroup>
</Expandable>

<Expandable title="Result - no access">
  <CodeGroup>
    ```json JSON theme={null}
    {
      "hasAccess": false,
      "accessDeniedReason": "CustomerNotEntitledForFeature",
      "isFallback": false
    }
    ```
  </CodeGroup>
</Expandable>

### Checking the entitlement for a numeric configuration feature

<Note>
  `getNumericEntitlement` is for **non-metered numeric features** (`meterType: "None"`). Calling it on a metered feature returns a `FeatureTypeMismatch` fallback (v4.0.0+). Use [`getMeteredEntitlement`](#checking-if-a-customer-has-access-to-a-metered-feature) for metered features.
</Note>

<CodeGroup>
  ```javascript JavaScript theme={null}
  const entitlement = stiggClient.getNumericEntitlement({
    featureId: 'feature-demo-01'
  });

  if (entitlement.hasAccess) {  
    // get the entitlement numeric value that is defined for the feature  
    console.log(entitlement.value);  
  }
  ```
</CodeGroup>

<Expandable title="Result - has access">
  <CodeGroup>
    ```json JSON theme={null}
    {
      "isFallback": false,
      "hasAccess": true,
      "isUnlimited": false,
      "value": 100,
      "feature": {
        "id": "feature-demo-01",
        "featureType": "Numeric",
        "meterType": "None",
        "units": "request",
        "unitsPlural": "requests",
        "displayName": "Feature #1",
        "description": "",
        "isMetered": false
      }
    }
    ```
  </CodeGroup>
</Expandable>

<Expandable title="Result - no access">
  <CodeGroup>
    ```json JSON theme={null}
    {
      "hasAccess": false,
      "accessDeniedReason": "CustomerNotEntitledForFeature",
      "isFallback": false,
      "isUnlimited": false
    }
    ```
  </CodeGroup>
</Expandable>

### Checking if a customer has access to a metered feature

<CodeGroup>
  ```javascript JavaScript theme={null}
  const entitlement = stiggClient.getMeteredEntitlement({  
    featureId: 'feature-demo-03'
  });

  if (entitlement.hasAccess) {  
    // has access and the requested usage is within the allowed quota  
  } else {  
    // the customer has exceeded his quota for this feature  
  }
  ```
</CodeGroup>

<Expandable title="Result - has access">
  <CodeGroup>
    ```json JSON theme={null}
    {
      "isFallback": false,
      "hasAccess": true,
      "isUnlimited": false,
      "usageLimit": 2,
      "currentUsage": 0,
      "requestedUsage": 0,
      "resetPeriod": "Monthly",
      "usagePeriodAnchor": "2022-04-01T00:00:00.000Z",
      "usagePeriodStart": "2022-09-01T00:00:00.000Z",
      "usagePeriodEnd": "2022-10-01T00:00:00.000Z",
      "feature": {
        "id": "feature-demo-03",
        "featureType": "Numeric",
        "meterType": "Incremental",
        "units": "request",
        "unitsPlural": "requests",
        "displayName": "Feature #3",
        "description": "",
        "isMetered": true
      }
    }
    ```
  </CodeGroup>
</Expandable>

<Expandable title="Result - no access">
  <CodeGroup>
    ```json JSON theme={null}
    {
      "isFallback": false,
      "hasAccess": true,
      "isUnlimited": false,
      "usageLimit": 2,
      "currentUsage": 0,
      "requestedUsage": 0,
      "resetPeriod": "Monthly",
      "usagePeriodAnchor": "2022-04-01T00:00:00.000Z",
      "usagePeriodStart": "2022-09-01T00:00:00.000Z",
      "usagePeriodEnd": "2022-10-01T00:00:00.000Z",
      "feature": {
        "id": "feature-demo-03",
        "featureType": "Numeric",
        "meterType": "Incremental",
        "units": "request",
        "unitsPlural": "requests",
        "displayName": "Feature #3",
        "description": "",
        "isMetered": true
      }
    }
    ```
  </CodeGroup>
</Expandable>

### Proactively checking if a customer will have access to X units of a metered feature

<CodeGroup>
  ```javascript JavaScript theme={null}
  const requestedUsage = 10;

  const entitlement = stiggClient.getMeteredEntitlement({  
    featureId: 'feature-demo-03',  
    options: {  
      requestedUsage
    }  
  });

  if (entitlement.hasAccess) {  
    // has access and the requested usage is within the allowed quota  
  } else {  
    // the customer has exceeded his quota for this feature  
  }
  ```
</CodeGroup>

<Expandable title="Result - has access">
  <CodeGroup>
    ```json JSON theme={null}
    {
      "isFallback": false,
      "hasAccess": true,
      "isUnlimited": false,
      "usageLimit": 2,
      "currentUsage": 0,
      "requestedUsage": 10,
      "resetPeriod": "Monthly",
      "usagePeriodAnchor": "2022-04-01T00:00:00.000Z",
      "usagePeriodStart": "2022-09-01T00:00:00.000Z",
      "usagePeriodEnd": "2022-10-01T00:00:00.000Z",
      "feature": {
        "id": "feature-demo-03",
        "featureType": "Numeric",
        "meterType": "Incremental",
        "units": "request",
        "unitsPlural": "requests",
        "displayName": "Feature #3",
        "description": "",
        "isMetered": true
      }
    }
    ```
  </CodeGroup>
</Expandable>

<Expandable title="Result - no access">
  <CodeGroup>
    ```json JSON theme={null}
    {
      "isFallback": false,
      "hasAccess": true,
      "isUnlimited": false,
      "usageLimit": 2,
      "currentUsage": 0,
      "requestedUsage": 10,
      "resetPeriod": "Monthly",
      "usagePeriodAnchor": "2022-04-01T00:00:00.000Z",
      "usagePeriodStart": "2022-09-01T00:00:00.000Z",
      "usagePeriodEnd": "2022-10-01T00:00:00.000Z",
      "feature": {
        "id": "feature-demo-03",
        "featureType": "Numeric",
        "meterType": "Incremental",
        "units": "request",
        "unitsPlural": "requests",
        "displayName": "Feature #3",
        "description": "",
        "isMetered": true
      }
    }
    ```
  </CodeGroup>
</Expandable>

# Getting paywall data

Useful for rendering the public pricing page or customer paywall.

<CodeGroup>
  ```javascript JavaScript theme={null}
  const paywallData = await stiggClient.getPaywall();
  ```
</CodeGroup>

<Expandable title="Result">
  <CodeGroup>
    ```json JSON theme={null}
    {
      "plans": [
        {
          "id": "plan-stigg-starter",
          "order": 0,
          "displayName": "Starter",
          "description": "For getting started",
          "entitlements": [
            {
              "usageLimit": 100,
              "feature": {
                "id": "feature-demo-01",
                "featureType": "Numeric",
                "description": "",
                "meterType": "None",
                "units": "request",
                "unitsPlural": "requests",
                "displayName": "Feature #1",
                "isMetered": false,
                "metadata": {
                  "key": "value"
                }
              },
              "hasUnlimitedUsage": false,
              "displayNameOverride": "Awesome feature #1",
              "hiddenFromWidgets": []
            },
            {
              "usageLimit": 0,
              "feature": {
                "id": "feature-demo-02",
                "featureType": "Boolean",
                "description": "",
                "meterType": "None",
                "displayName": "Feature #2",
                "isMetered": false
              },
              "hasUnlimitedUsage": false,
              "displayNameOverride": null,
              "hiddenFromWidgets": ["PAYWALL"]
            }
          ],
          "inheritedEntitlements": [],
          "pricePoints": [],
          "pricingType": "FREE",
          "defaultTrialConfig": null,
          "compatibleAddons": [],
          "product": {
            "id": "product-stigg",
            "displayName": "Stigg",
            "description": null,
            "metadata": null
          },
          "metadata": null
        }
      ]
    }
    ```
  </CodeGroup>
</Expandable>

# Getting customer portal data

Useful for rendering the public pricing page or customer paywall.

<CodeGroup>
  ```javascript JavaScript theme={null}
  const customerPortalData = await stiggClient.getCustomerPortal();
  ```
</CodeGroup>

<Expandable title="Result">
  <CodeGroup>
    ```json JSON theme={null}
    {
      "data": {
        "customerPortal": {
          "subscriptions": [
            {
              "subscriptionId": "subscription-plan-revvenu-basic-ecb700",
              "planName": "Basic",
              "pricing": {
                "unitQuantity": null,
                "billingPeriod": null,
                "billingModel": null,
                "pricingType": "FREE",
                "usageBasedEstimatedBill": null,
                "price": null,
                "feature": null,
              },
              "status": "ACTIVE",
              "trialRemainingDays": null,
              "billingPeriodRange": {
                "start": "2022-11-22T08:35:05.000Z",
                "end": "2022-12-22T08:35:05.000Z",
              },
              "totalPrice": null,
              "addons": [],
            }
          ],
          "entitlements": [
            {
              "isGranted": true,
              "usageLimit": 4,
              "currentUsage": 44,
              "hasUnlimitedUsage": false,
              "usagePeriodAnchor": "2022-04-01T00:00:00.000Z",
              "usagePeriodStart": "2022-09-01T00:00:00.000Z",
              "usagePeriodEnd": "2022-10-01T00:00:00.000Z",
              "resetPeriod": "MONTH",
              "resetPeriodConfiguration": {
                "monthlyAccordingTo": "SubscriptionStart"
              },
              "feature": {
                "featureType": "NUMBER",
                "meterType": "Incremental",
                "featureUnits": "campaign",
                "featureUnitsPlural": "campaigns",
                "description": null,
                "displayName": "Campaigns",
                "refId": "feature-02-campaigns",
              },
            },
            {
              "isGranted": true,
              "usageLimit": 3,
              "currentUsage": 0,
              "hasUnlimitedUsage": false,
              "usagePeriodAnchor": null,
              "usagePeriodStart": null,
              "usagePeriodEnd": null,
              "resetPeriod": null,
              "resetPeriodConfiguration": null,
              "feature": {
                "featureType": "NUMBER",
                "meterType": "Fluctuating",
                "featureUnits": "template",
                "featureUnitsPlural": "templates",
                "description": null,
                "displayName": "Templates",
                "refId": "feature-01-templates",
              },
            }
          ],
          "promotionalEntitlements": [],
          "billingInformation": {
            "email": "",
            "name": "Demo 02",
            "defaultPaymentMethodLast4Digits": "4242",
            "defaultPaymentMethodId": "pm_1M6s1BAnAO1PFouUrBBdYaVK",
            "defaultPaymentExpirationMonth": 2,
            "defaultPaymentExpirationYear": 2026,
          },
          "showWatermark": true,
          "billingPortalUrl": "https://billing./documentation/native-integrations/billing/stripe/integration-when-using-stripe-elements-for-checkout.com/p/session/test_YWNjdF8xS3hETXRBbkFPMVBGb3VVLF9NcVpOcEkwZzVwU05mZnc4dmxJTmNoTXdqOUx1Z2JH0100BnXkQsyV",
          "canUpgradeSubscription": true,
        }
      }
    }
    ```
  </CodeGroup>
</Expandable>

# Getting customer data

Useful for rendering a customer portal.

<CodeGroup>
  ```javascript JavaScript theme={null}
  const customer = await stiggClient.getCustomer();
  ```
</CodeGroup>

<Expandable title="Result">
  <CodeGroup>
    ```json JSON theme={null}
    {
      "id": "customer-demo-01",
      "name": "First customer",
      "email": "john@example.com",
      "createdAt": "2022-09-20T08:44:23.311Z",
      "updatedAt": "2022-09-20T08:44:23.311Z",
      "hasPaymentMethod": false,
      "promotionalEntitlements": [],
      "metadata": {
        "example": "test"
      },
      "experimentInfo": {
          "name": "should we use freemium?",
          "id": "should-we-use-freemium",
          "groupName": "Variant group",
          "groupType": "VARIANT",
      }
    }
    ```
  </CodeGroup>
</Expandable>

# Listing customers active subscriptions

The `getActiveSubscriptionsList` method returns a list of slim subscription data, for extended data for a specific subscription use `getSubscription` method.

<CodeGroup>
  ```javascript JavaScript theme={null}
  const subscriptions = await stiggClient.getActiveSubscriptionsList({
    resourceId: 'resource-01',  // optional, pass it to get subscription of specific resource
  });
  ```
</CodeGroup>

In addition, there's an option to pass a list of resource Ids

<CodeGroup>
  ```javascript JavaScript theme={null}
  const subscriptions = await stiggClient.getActiveSubscriptionsList({
    resourceIds: ['resource-01', 'resource-02', 'resource-03' ],  // optional, pass it to get list of resources
  });
  ```
</CodeGroup>

<Expandable title="Result">
  <CodeGroup>
    ```json JSON theme={null}
    [
      {
        "subscriptionId": "subscription-plan-stigg-pro-28a241",
        "status": "ACTIVE",
        "currentBillingPeriodEnd": "2023-09-20T09:00:14.000Z",
        "startDate": "2022-09-20T09:00:14.000Z",
        "pricingType": "PAID",
        "customer": {
          "customerId": "customer-demo-01"
        },
        "plan": {
          "planId": "plan-stigg-pro",
          "displayName": "Pro"
        },
        "addons": [
          {
            "quantity": 3,
            "addon": {
              "addonId": "addon-stigg-1"
            }
          }
        ],
      }
    ]
    ```
  </CodeGroup>
</Expandable>

# Getting a subscription

Useful for rendering a customer portal.

To retrieve extended subscription:

<CodeGroup>
  ```javascript JavaScript theme={null}
  const subscriptions = await stiggClient.getSubscription({
    subscriptionId: 'subscriptions-01'
  });
  ```
</CodeGroup>

<Expandable title="Result">
  <CodeGroup>
    ```json JSON theme={null}
    {
      "id": "subscription-plan-stigg-pro-28a241",
      "status": "ACTIVE",
      "currentBillingPeriodEnd": "2023-09-20T09:00:14.000Z",
      "plan": {
        "id": "plan-stigg-pro",
        "order": 0,
        "displayName": "Pro",
        "description": "For teams or individuals who need video capture and collaboration capabilities",
        "entitlements": [
          {
            "usageLimit": 0,
            "feature": {
              "id": "feature-demo-01",
              "featureType": "Boolean",
              "description": "",
              "meterType": "None",
              "displayName": "Feature #1",
              "isMetered": false
            },
            "hasUnlimitedUsage": false
          }
        ],
        "inheritedEntitlements": [
          {
            "usageLimit": 100,
            "feature": {
              "id": "feature-demo-02",
              "featureType": "Numeric",
              "description": "",
              "meterType": "None",
              "units": "request",
              "unitsPlural": "requests",
              "displayName": "Feature #2",
              "isMetered": false
            },
            "hasUnlimitedUsage": false
          },
          {
            "usageLimit": 0,
            "feature": {
              "id": "feature-demo-03",
              "featureType": "Boolean",
              "description": "",
              "meterType": "None",
              "displayName": "Feature #3",
              "isMetered": false
            },
            "hasUnlimitedUsage": false
          }
        ],
        "pricePoints": [
          {
            "pricingModel": "FLAT_FEE",
            "billingPeriod": "MONTHLY",
            "amount": 12,
            "currency": "USD"
          },
          {
            "pricingModel": "FLAT_FEE",
            "billingPeriod": "ANNUALLY",
            "amount": 120,
            "currency": "USD"
          }
        ],
        "compatibleAddons": [],
        "product": {
          "id": "product-stigg",
          "displayName": "Stigg"
        },
        "metadata": null
      },
      "price": {
        "pricingModel": "FLAT_FEE",
        "billingPeriod": "ANNUALLY",
        "amount": 120,
        "currency": "USD"
      },
      "pricingType": "PAID",
      "addons": [],
      "startDate": "2022-09-20T09:00:14.000Z",
      "metadata": {
        "lorem": "ipsum"
      },
      "experimentInfo": {
        "name": "should we use freemium?",
        "id": "should-we-use-freemium",
        "groupName": "Variant group",
        "groupType": "VARIANT",
      },
      "paymentCollection": "NOT_REQUIRED", // status of the payment collection of the subscription - can be either 'NOT_REQUIRED', 'FAILED', 'ACTION_REQUIRED' or 'PROCESSING'
      "latestInvoice": {
        "billingId": "invoice-01", // ID of the invoice of the billing provider
        "status": "PAID", // can be either 'OPEN', 'CANCELED' or 'PAID'
        "createdAt": "2023-08-22T11:27:41.000Z",
        "updatedAt": "2023-08-22T11:27:44.608Z",
        "requiresAction": false, // indicate of the payment requires action to complete the payment
        "paymentUrl": "https://...", // payment url that can be sent to the customer to complete the payment
        "paymentSecret": "secret-01", // secret to be used to initiate next action with billing provider
        "errorMessage": "", // optinal error message, if the status is FAILED
      },
    }
    ```
  </CodeGroup>
</Expandable>

# Getting all available coupons

Useful for rendering a paywall or promotions.

<CodeGroup>
  ```javascript JavaScript theme={null}
  const coupons = await stiggClient.getCoupons();
  ```
</CodeGroup>

# Estimate subscription cost

You can estimate the subscription cost using the `estimateSubscription` method. This can help the customer to understand the costs before paying.

<CodeGroup>
  ```javascript JavaScript theme={null}
  // increment usage of a metered feature  
  await stiggClient.estimateSubscription({  
  	customerId: "customer-demo-01",
    planId: "plan-revvenu-growth",
    billableFeatures: [{ 						// optional, required for plans with per-unit pricing
      featureId:'feature-01-templates',
      quantity: 2
    }],
    billingPeriod: "MONTHLY",
    addons: [{  								// optional
    	addonId: 'addon-10-campaigns',  
      quantity: 1  
    }], 
    promotionCode: "STIGG50", 	// optional
    startDate: new Date(),			// optional
    billingCountryCode: 'US',		// optional, required for price localization, must be in the ISO-3166-1 format
  	billingInformation: {
        taxPercentage: 17 // optional. taxRate will be created if not exists
    }
  });
  ```
</CodeGroup>

**Return fields**

<CodeGroup>
  ```javascript JavaScript theme={null}
  {
    total: 'Total after discounts and taxes.',
    totalExcludingTax: 'Total including discounts but excluding tax.',
    subTotal: 'Total before any discount or exclusive tax is applied.',
    tax: 'Tax amount',
    taxDetails: {
      displayName: 'Tax display name.',
      inclusive: 'Specifies if the tax rate is inclusive or exclusive.',
      percentage: 'Tax rate percentage out of 100.',
    },
    discount: {
      type: 'Discount type - `PERCENTAGE` / `FIXED`.',
      value: 'Discount value out of 100.',
      durationType:
        'The duration of the discount - `FOREVER` / `REPEATING` / `ONCE`',
      durationInMonths: 'The duration of the discount in months',
    },
    billingPeriodRange: {
      start: 'Billing period start date',
      end: 'Billing period end date',
    },
    proration: {
      prorationDate: 'The date when the proration occurred',
      credit:
        'The prorated amount of credits to refund the customer in the upcoming invoice',
      debit:
        'The prorated amount of debit to charge the customer in the upcoming invoice',
      netAmount: 'The sum of `debit` and `credit`',
    },
    // Not prorated subscription prices
    subscription: {
      total: 'Total after discounts and taxes.',
      totalExcludingTax: 'Total including discounts but excluding tax.',
      subTotal: 'Total before any discount or exclusive tax is applied.',
      tax: 'Tax amount',
    },
  };
  ```
</CodeGroup>

<Expandable title="Result">
  <CodeGroup>
    ```json JSON theme={null}

    {
      "total": {
        "amount": 10,
        "currency": "USD"
      },
      "subTotal": {
        "amount": 10,
        "currency": "USD"
      },
      "billingPeriodRange": {
        "start": "2022-10-26T00:00:00.000Z",
        "end": "2022-11-26T00:00:00.000Z"
      },
      "discount": {
        "type": "PERCENTAGE",
        "value": 50,
        "durationType": "REPEATING",
        "durationInMonths": 3
      },
      "proration": {
        "credit": {
          "amount": 0,
          "currency": "USD"
        },
        "debit": {
          "amount": 10,
          "currency": "USD"
        },
        "netAmount": {
          "amount": 10,
          "currency": "USD"
        },
        "prorationDate": "2022-10-26T00:00:00.000Z"
      },
      "subscription": {
        "total": {
          "amount": 10,
          "currency": "USD"
        },
        "subTotal": {
          "amount": 20,
          "currency": "USD"
        }
      }
    }
    ```
  </CodeGroup>
</Expandable>

You can also estimate the cost of updating an existing subscription using the `updateSubscription` method, which also returns a breakdown of the proration amounts:

<CodeGroup>
  ```javascript Node.js theme={null}
  await stiggClient.estimateSubscriptionUpdate({  
    subscriptionId: "subscription-plan-revvenu-growth-da6324",
    // optional parameters:
    billableFeatures: [{ 						// optional, required for subscriptions with per-unit pricing
      featureId:'feature-01-templates',
      quantity: 2
    }],
    promotionCode: "STIGG50",
    addons: [{  
      addonId: 'addon-10-campaigns',  
      quantity: 1  
    }]
  });
  ```
</CodeGroup>

**Return fields**

<CodeGroup>
  ```javascript JavaScript theme={null}
  {
    total: 'Total after discounts and taxes.',
    totalExcludingTax: 'Total including discounts but excluding tax.',
    subTotal: 'Total before any discount or exclusive tax is applied.',
    tax: 'Tax amount',
    taxDetails: {
      displayName: 'Tax display name.',
      inclusive: 'Specifies if the tax rate is inclusive or exclusive.',
      percentage: 'Tax rate percentage out of 100.',
    },
    discount: {
      type: 'Discount type - `PERCENTAGE` / `FIXED`.',
      value: 'Discount value out of 100.',
      durationType:
        'The duration of the discount - `FOREVER` / `REPEATING` / `ONCE`',
      durationInMonths: 'The duration of the discount in months',
    },
    billingPeriodRange: {
      start: 'Billing period start date',
      end: 'Billing period end date',
    },
    proration: {
      prorationDate: 'The date when the proration occurred',
      credit:
        'The prorated amount of credits to refund the customer in the upcoming invoice',
      debit:
        'The prorated amount of debit to charge the customer in the upcoming invoice',
      netAmount: 'The sum of `debit` and `credit`',
    },
    // Not prorated subscription prices
    subscription: {
      total: 'Total after discounts and taxes.',
      totalExcludingTax: 'Total including discounts but excluding tax.',
      subTotal: 'Total before any discount or exclusive tax is applied.',
      tax: 'Tax amount',
    },
  };
  ```
</CodeGroup>

<Expandable title="Result">
  <CodeGroup>
    ```json JSON theme={null}
    {
      "total": {
        "amount": 2.5,
        "currency": "USD"
      },
      "subTotal": {
        "amount": 5,
        "currency": "USD"
      },
      "billingPeriodRange": {
        "start": "2022-10-26T00:00:00.000Z",
        "end": "2022-11-26T00:00:00.000Z"
      },
      "discount": {
        "type": "PERCENTAGE",
        "value": 50,
        "durationType": "REPEATING",
        "durationInMonths": 3
      },
      "proration": {
        "credit": {
          "amount": -9.99,
          "currency": "USD"
        },
        "debit": {
          "amount": 14.99,
          "currency": "USD"
        },
        "netAmount": {
          "amount": 5,
          "currency": "USD"
        },
        "prorationDate": "2022-10-26T00:00:00.000Z"
      },
      "subscription": {
        "total": {
          "amount": 2.5,
          "currency": "USD"
        },
        "subTotal": {
          "amount": 5,
          "currency": "USD"
        }
      }
    }
    ```
  </CodeGroup>
</Expandable>

<Warning>
  1. Passing of promo codes requires an integration with a billing solution, such as: [Stripe](/documentation/native-integrations/billing/stripe/integration-when-using-stripe-elements-for-checkout).
  2. Promo codes should be generated in the integrated billing solution.
  3. When providing the optional `promotionCode` parameter, the promo code and associated coupon will validated against the defined restrictions to ensure that they're applicable for the subscription. If validation fails, a [relevant error code](https://node-sdk-docs.stigg.io/enums/errorcode) would be returned; otherwise, the subscription will include the discounted price.
</Warning>

# Handling a successful checkout

When initiating checkout using Stigg, the user is expected to be redirected and land on the `successUrl` destination page in the case of a successful payment.

Due to the async nature of webhooks from Stripe, the subscription might not be yet provisioned in your Stigg account. To make sure that the new subscription has been activated in this scenario, you can utilize the `waitForCheckoutCompleted` method to have an indication if the checkout is still in progress or not. Once the promise resolves, the subscription has been successfully activated and new entitlements were granted. If there's a timeout or a network error during that time, the promise is rejected with the error.

For example, you can present a loading animation until the promise returned from the method is resolved.

<CodeGroup>
  ```javascript JavaScript theme={null}
  // in the context of the `successUrl` page,  
  // wait for the subscription to become active and entitlements to be updated

  async function onPageLoad(){  
    showLoadingIndicator();
    
    try {
      await stiggClient.waitForCheckoutCompleted();
    } catch (err) {
      // an error occurred while waiting for checkout to complete,
      // can be a network error or a timeout. 
      // inform the customer to try again or contact support.
      showErrorMessage();
    } finally {
      hideLoadingIndicator();
    }
  }

  window.addEventListener('load', (event) => {  
    onPageLoad();  
  });
  ```
</CodeGroup>

# Clearing the customer context

Clear the customer ID of the user that's accessing your app, usually after the customer signs out:

<CodeGroup>
  ```javascript JavaScript theme={null}
  stiggClient.clearCustomer();
  ```
</CodeGroup>

# Clearing the customer resource context

For [Multi-instance products](/guides/i-want-to/add-multiple-subscriptions), clear the customer ID of the user that's accessing your app, usually after the customer exit the context of specific resource:

<CodeGroup>
  ```javascript JavaScript theme={null}
  stiggClient.clearResource();
  ```
</CodeGroup>

# Refresh the cache

Stigg's SDK refreshes its cache of customer entitlements and usage data upon initialization (for example: when a page is refreshed), as well as periodically every 30 seconds.

After performing an operation on the backend that can modify the customer entitlements or the usage of a feature (for example: updating subscriptions or reporting usage), it's useful to immediately refresh the cache.

To do so, call the below method:

<CodeGroup>
  ```javascript JavaScript theme={null}
  await stiggClient.refresh();
  ```
</CodeGroup>

# Listening for entitlement updates

Subscribe to real-time updates whenever a customer's entitlements change. The callback receives a `CustomerEntitlementsResultV2` object with an `entitlements` array (`EntitlementV2[]`).

<CodeGroup>
  ```javascript JavaScript theme={null}
  stiggClient.addListener('entitlementsUpdated', (result) => {
    result.entitlements.forEach((entitlement) => {
      console.log(entitlement.feature?.id, entitlement.hasAccess);
    });
  });
  ```
</CodeGroup>

To unsubscribe, pass the same function reference to `removeListener`:

<CodeGroup>
  ```javascript JavaScript theme={null}
  stiggClient.removeListener('entitlementsUpdated', myListener);
  ```
</CodeGroup>

# Offline mode

During local development or testing, you might want to avoid making network requests to the Stigg API. To do this, you can run the JS SDK in offline mode by enabling the offline option. When enabled, API key validation will always succeed, regardless of the key provided.

<CodeGroup>
  ```typescript TypeScript theme={null}
  const stiggClient = Stigg.initialize({
    apiKey: 'local',
    customerId: '41XTDbE'
    offline: true
  });
  ```
</CodeGroup>

In offline mode, the JS SDK respects the [global fallback strategy](/documentation/high-availability-and-scale/local-caching-and-fallback-strategy#global-fallback-configuration), and entitlement evaluations are limited to the values defined as fallback entitlements.

<CodeGroup>
  ```typescript TypeScript theme={null}
  const stiggClient = Stigg.initialize({
    apiKey: 'local',
    customerId: '41XTDbE'
    offline: true,
    entitlementsFallback: {
      'feature-number-of-seats': {
       	hasAccess: true,
      },
      'feature-templates': {
        hasAccess: true,
        usageLimit: 10
      }
    }
  });
  ```
</CodeGroup>

# Credit auto-recharge

<CodeGroup>
  ```typescript TypeScript theme={null}
  // Get automatic recharge configuration
  await stiggClient.getAutomaticRechargeConfiguration({
    customerId: 'customer-123',
    currencyId: 'tokens'
  });

  // Save/update automatic recharge configuration
  await stiggClient.saveAutomaticRechargeConfiguration(
    customerId: 'customer-123',
    currencyId: 'tokens',
    isEnabled: true,
    thresholdValue: 50,
    targetBalance: 100,
    maxSpendLimit: 250  // optional
  });
  ```
</CodeGroup>

# Migrating to v4.0.0

| Change                                                                                                              | Migration                                                                                    |
| ------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
| `entitlementsUpdated` event payload changed from `Map<string, CachedEntitlement>` to `CustomerEntitlementsResultV2` | Update listeners to iterate `.entitlements` (an `EntitlementV2[]` array) instead of a `Map`. |
| `EntitlementsState` type removed                                                                                    | Replace imports with `CustomerEntitlementsResult` from `@stigg/js-client-sdk`.               |
| `resetSettings` on `MeteredEntitlement` removed (was `@deprecated`)                                                 | Use the top-level `resetPeriod` and `usagePeriodEnd` fields directly on the entitlement.     |
| `getNumericEntitlement()` on a metered feature now returns a `FeatureTypeMismatch` fallback                         | Use `getMeteredEntitlement()` for metered features.                                          |
| `isGranted` on credit entitlements removed                                                                          | Use `hasAccess` — same semantics.                                                            |
| `Logger` interface second parameter widened to `LoggerExtra` (`Record<string, any> \| Error \| Error['stack']`)     | Update any custom `Logger` implementation to accept `LoggerExtra` as the second parameter.   |
| `Entitlement` union type now includes `EnumEntitlement`                                                             | Add an `EnumEntitlement` branch to any exhaustive `switch`/`case` on `Entitlement`.          |
| `CreditEntitlementCurrency` named export removed                                                                    | Use `CreditEntitlement['currency']` inline type instead.                                     |

# Full SDK reference

<Card title="JavaScript SDK reference" icon="code" href="https://js-sdk-docs.stigg.io/classes/stigg" horizontal arrow />

# SDK changelog

<Card title="JavaScript SDK changelog" icon="list-timeline" href="/api-and-sdks/changelog/frontend/javascript" horizontal />
