SDK — client & server

@entitlehub/sdk is a zero-dependency TypeScript SDK: a client class for reads (browsers, React Native, Expo) and a server class for writes. Every method maps to a REST endpoint.

Install

bash
npm install @entitlehub/sdk

Zero dependencies; uses the global fetch (Node 18+, modern browsers, React Native, Expo). Prefer no dependency at all? Every method below maps 1:1 to a plain REST endpoint you can call with fetch.

Client — reads (publishable key)

Construct once with your publishablekey and the acting user, then ask what they're entitled to. CustomerInfo is cached (default 5 min) and refreshed on demand.

typescript
import { EntitleHub } from "@entitlehub/sdk";

const eh = new EntitleHub({
  apiKey: "pk_live_…",        // publishable key — client-safe
  appUserId: user.id,          // your own stable user id
});

const info = await eh.getCustomerInfo();
if (info.isActive("pro")) unlockPro();

// convenience: single check
if (await eh.isEntitled("premium")) showPremium();

// authoritative check (always hits the server, includes a reason when inactive)
const res = await eh.checkEntitlement("pro");
// res => { active, status, expires_at, will_renew, reason? }

// paywall data
const offerings = await eh.getOfferings();

// react to changes (e.g. after a purchase re-fetches)
const off = eh.addCustomerInfoUpdateListener((info) => render(info));

Switching users

typescript
await eh.logIn(newUser.id);   // switch acting user, clears cache, re-fetches
eh.logOut();                   // back to anonymous

The CustomerInfo object

typescript
info.isActive("pro")            // boolean
info.active["pro"]              // full detail: { status, store, product, expires_at, will_renew, since }
info.activeEntitlementIds      // ["pro", "premium"]
info.expirationDate("pro")     // Date | null (null = lifetime) | undefined (not active)

Server — writes (secret key)

Keep this on your backend; it uses your secret key. Report validated purchases and grant entitlements.

typescript
import { EntitleHubServer } from "@entitlehub/sdk";

const eh = new EntitleHubServer({ apiKey: process.env.ENTITLEHUB_SECRET_KEY! });

// Google Play — validated: EntitleHub verifies the token with your Play service account
await eh.reportPurchase(userId, {
  store: "play",
  storeProductId: "app_pro_monthly",
  purchaseToken: playToken,
  isSubscription: true,
});

// Apple StoreKit 2 — validated: product/environment read from the signed JWS
await eh.reportPurchase(userId, { store: "app_store", storeProductId: "", signedTransaction: jws });

// Grant directly (promo / comp / code redemption) — no store purchase
await eh.grantEntitlement(userId, "premium", { durationDays: 0 }); // 0 = lifetime

// Read / check from the server too
const info = await eh.getCustomerInfo(userId);
const res  = await eh.check(userId, "pro");
Error handling

Failed calls throw EntitleHubError with a status and a code (auth, config, …). Catch it to, e.g., force a re-login on auth.