Sesamy SDK
The official TypeScript SDK (@sesamy/sdk) for direct API access to Sesamy services. This is a lower-level SDK that provides direct access to all Sesamy API endpoints with TypeScript support and built-in request deduplication and retry logic.
Difference from Sesamy JS
This is the lower-level API SDK for direct service integration. For browser-based content access control and user experience features, use Sesamy JS instead.
Features
- Full TypeScript support with comprehensive type definitions
- Request deduplication - Automatically deduplicates identical concurrent requests
- Automatic retries - Built-in retry logic for failed requests with exponential backoff
- Direct API access to all Sesamy endpoints including complete management APIs
- Promise-based API with automatic token injection
- Separate client and management APIs for different use cases
- Tree-shaking support for optimal bundle sizes
Installation
npm install @sesamy/sdkyarn add @sesamy/sdkpnpm add @sesamy/sdkRequirements
- Node.js 18+
- TypeScript 5.0+ (recommended for full type support)
Quick Start
Client SDK
For client-side operations (user-facing features):
import { client } from '@sesamy/sdk';
const sdk = client({
baseUrl: 'https://api.sesamy.com',
tokenProvider: async () => {
// Return JWT token for authentication
return await getUserToken();
},
});
// Get user profile
const profile = await sdk.profile.get('user-id');
// List entitlements
const entitlements = await sdk.entitlements.list();
// Check subscription status
const subscriptions = await sdk.subscriptions.list();Management SDK
For server-side operations (admin/management features):
import { management } from '@sesamy/sdk';
const sdk = management({
baseUrl: 'https://api.sesamy.com',
tokenProvider: async () => {
// Return management JWT token
return await getManagementToken();
},
});
// List all users
const users = await sdk.users.list();
// Create a new user
const newUser = await sdk.users.create({
email: 'user@example.com',
name: 'John Doe',
});
// Update user metadata
await sdk.users.metadata.set('user-id', 'preferences', 'theme=dark');API Structure
The SDK is organized into logical domains for better discoverability:
Client API
profile- User profile managemententitlements- Access rights and permissionssubscriptions- Subscription managementproducts- Product information and onboardingcontracts- Contract management and amendmentsuserMetadata- User-specific metadatatallies- Usage tracking and limitstags- User tagging systemcheckouts- Payment processingbills- Billing and invoicesfulfillments- Content deliverypaywalls- Paywall configurationpaymentIssues- Payment problem handlingproxy- Content proxyingtransactions- Transaction historyvendor- Vendor information
Management API
users- User management (CRUD operations, password management, metadata)entitlements- Entitlement management and queryingproducts- Product management (CRUD operations, fulfillments)contracts- Contract management and queryingbills- Billing and invoice managementtransactions- Transaction history and managementvendors- Vendor management (CRUD operations)accessLists- Access list and grant managementcustomers- Customer information retrieval (XML format)
Paywalls
Getting Paywall Configuration
The paywalls.get() method accepts either a paywall ID or a direct URL:
// Using paywall ID
const paywallConfig = await sdk.paywalls.get('paywall-id-123');
// Using direct URL (useful for external paywall services)
const paywallConfig = await sdk.paywalls.get('https://example.com/paywall');The method automatically detects whether the input is a valid URL or a paywall ID:
- If the input is a valid URL, the request is made directly to that URL
- If the input is not a valid URL, it's treated as a paywall ID and the request is made to
/paywalls/{id}
Checking Leaky Paywall Access
The paywalls.checkAccess() method checks whether a user can access content under a leaky (metered) paywall:
const result = await sdk.paywalls.checkAccess('paywall-id-123', {
publisherContentId: 'article-2024-01-15',
url: 'https://example.com/articles/my-article', // optional
});
if (result.status === 'allowed') {
// User has free reads remaining
console.log('Remaining free reads:', result.remaining);
console.log('Signed link:', result.signedLink); // present when url was provided
} else {
// result.status === 'paywall' — free limit reached
console.log('Show paywall:', result.paywall);
}Parameters:
paywallId(string) — the paywall IDbody.publisherContentId(string, required) — unique identifier of the contentbody.url(string, optional) — article URL; when provided, the response includes asignedLinkwith a temporary access token
Executing a Paywall Strategy
The paywalls.executeStrategy() method evaluates a paywall strategy by ID against the visitor's context and returns the resolved paywall plus which node matched. The strategy's rules are evaluated against attribution (UTM tags, referrer) you supply, plus the visitor's device, geo and referral, which are derived server-side from the request — so you do not send user-agent or location:
const result = await sdk.paywalls.executeStrategy('strategy-acme-123', {
attribution: {
source: 'newsletter', // utm_source
medium: 'email', // utm_medium
campaign: 'acme-launch', // utm_campaign
referrer: 'https://referrer.example.com/', // full referrer URL
},
content: { contentId: 'acme-article-001' }, // optional
});
console.log('Resolved paywall:', result.paywall);
console.log('Matched node:', result.matchedNode); // omitted when the fallback matched
// Debug mode: evaluate as if from a specific device and inspect the trace.
// `debugUserAgent` overrides the User-Agent and is honoured only when debug is true.
const debugResult = await sdk.paywalls.executeStrategy('strategy-acme-123', {
attribution: { source: 'newsletter', medium: 'email' },
debug: true,
debugUserAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_2 like Mac OS X)',
});
console.log(debugResult.debug); // requester object, cache, timing, traceParameters:
strategyId(string) — the strategy IDparams.attribution(object, optional) — UTM tags (source,medium,campaign,term,content) and the fullreferrerURLparams.content(object, optional) — metadata about the gated content (contentId,title,type,price,currency,publisherId)params.debug(boolean, optional) — include adebugenvelope (requester object, cache, timing) in the responseparams.debugUserAgent(string, optional) — debug-only override for the User-Agent the strategy is evaluated against (e.g. to test device rules); honoured only whendebugistrue
Returns: Promise<StrategyExecutionResult> — { paywallId, matchedNode?, paywall, debug? }
Configuration
SDK Configuration
interface SDKConfig {
baseUrl: string; // API base URL
tokenProvider: () => Promise<string>; // Function to provide auth tokens
vendorId?: string; // Optional vendor ID for multi-tenant setups
}Token Provider
The tokenProvider function should return a valid JWT token:
const sdk = client({
baseUrl: 'https://api.sesamy.com',
tokenProvider: async () => {
// Implement your token retrieval logic
const token = await fetchTokenFromYourAuthSystem();
return token;
},
});Authentication
The SDK handles authentication automatically through the tokenProvider. Tokens are injected into API requests as Bearer tokens.
Token Management
// For client-side usage with user tokens
const clientSdk = client({
baseUrl: 'https://api.sesamy.com',
tokenProvider: async () => {
return localStorage.getItem('user_token') || (await refreshToken());
},
});
// For server-side usage with service tokens
const managementSdk = management({
baseUrl: 'https://api.sesamy.com',
tokenProvider: async () => {
return await getServiceToken();
},
});HTTP Features
The SDK includes advanced HTTP features for robust and efficient API communication.
Request Deduplication
Identical concurrent requests are automatically deduplicated to prevent unnecessary API calls and improve performance:
// Multiple calls to the same endpoint with same parameters
// will be deduplicated automatically
const [profile1, profile2] = await Promise.all([
sdk.profile.get('user-123'),
sdk.profile.get('user-123'), // This will reuse the first request
]);Automatic Retries
Failed requests are automatically retried with exponential backoff:
// Network errors, 5xx responses, and certain 4xx errors are retried
try {
const data = await sdk.entitlements.list();
} catch (error) {
// Only throws after all retry attempts are exhausted
console.error('Request failed after retries:', error);
}The retry logic includes:
- Exponential backoff with jitter
- Configurable retry attempts
- Smart error classification (retryable vs non-retryable errors)
Error Handling
The SDK throws typed errors for different scenarios:
import { client } from '@sesamy/sdk';
const sdk = client({
/* config */
});
try {
const profile = await sdk.profile.get('user-id');
} catch (error) {
if (error.status === 401) {
// Token expired, refresh and retry
await refreshToken();
} else if (error.status === 403) {
// Insufficient permissions
console.error('Access denied');
} else if (error.status === 404) {
// Resource not found
console.error('User not found');
} else {
// Other errors
console.error('API error:', error.message);
}
}TypeScript Support
Full TypeScript support with comprehensive type definitions:
import { client, type Profile, type Entitlement } from '@sesamy/sdk';
const sdk = client({
/* config */
});
// Fully typed responses
const profile: Profile = await sdk.profile.get('user-id');
const entitlements: Entitlement[] = await sdk.entitlements.list();Examples
Complete User Onboarding Flow
import { client } from '@sesamy/sdk';
const sdk = client({
baseUrl: 'https://api.sesamy.com',
tokenProvider: () => getAuthToken(),
});
async function onboardUser(userId: string, productSku: string) {
try {
// Check if user has access
const entitlements = await sdk.entitlements.list({
sku: productSku,
waitForEntitlementAfter: new Date().toISOString(),
});
if (entitlements.length > 0) {
console.log('User already has access');
return;
}
// Auto-onboard to product
const newEntitlements = await sdk.products.autoOnboard(productSku);
// Update user profile
await sdk.profile.update(userId, {
preferences: { onboarded: true },
});
console.log('User onboarded successfully');
} catch (error) {
console.error('Onboarding failed:', error);
}
}Subscription Management
async function manageSubscription(userId: string) {
// Get user's subscriptions
const subscriptions = await sdk.subscriptions.list();
// Check for active subscriptions
const activeSubscription = subscriptions.find((sub) => sub.status === 'active');
if (activeSubscription) {
// Cancel subscription
await sdk.contracts.cancel(activeSubscription.contractId);
}
}User Management (Management API)
import { management } from '@sesamy/sdk';
const mgmtSdk = management({
baseUrl: 'https://api.sesamy.com',
tokenProvider: () => getManagementToken(),
});
async function createAndSetupUser(email: string, initialMetadata: Record<string, string>) {
// Create user
const user = await mgmtSdk.users.create({
email,
name: email.split('@')[0], // Simple name from email
});
// Set initial metadata
for (const [key, value] of Object.entries(initialMetadata)) {
await mgmtSdk.users.metadata.set(user.id, key, value);
}
return user;
}Product Management (Management API)
// List all products
const products = await mgmtSdk.products.list();
// Get specific product
const product = await mgmtSdk.products.get('premium-article-sku');
// Create new product
const newProduct = await mgmtSdk.products.create({
sku: 'new-product-sku',
name: 'New Premium Product',
price: { amount: 9.99, currency: 'USD' },
});
// Update product
const updatedProduct = await mgmtSdk.products.update('premium-article-sku', {
name: 'Updated Product Name',
});
// Get product fulfillments
const fulfillments = await mgmtSdk.products.getFulfillments('premium-article-sku');Entitlement Management (Management API)
// List entitlements for a specific user
const userEntitlements = await mgmtSdk.entitlements.list({
userId: 'user-123',
type: 'article',
});
// List entitlements by product SKU
const productEntitlements = await mgmtSdk.entitlements.list({
sku: 'premium-article-sku',
});Contract Management (Management API)
// List all contracts
const contracts = await mgmtSdk.contracts.list();
// Get specific contract
const contract = await mgmtSdk.contracts.get('contract-123');Billing and Transaction Management (Management API)
// List all bills
const bills = await mgmtSdk.bills.list();
// Get specific bill
const bill = await mgmtSdk.bills.get('bill-123');
// List transactions
const transactions = await mgmtSdk.transactions.list();Vendor Management (Management API)
// List all vendors
const vendors = await mgmtSdk.vendors.list();
// Create new vendor
const newVendor = await mgmtSdk.vendors.create({
name: 'New Publisher',
contactEmail: 'contact@publisher.com',
});Access Lists and Grants Management (Management API)
Access Lists are sources of purchases/grants that allow you to manage bulk user entitlements:
// List all access lists
const accessLists = await mgmtSdk.accessLists.list();
// Create a new access list
const newAccessList = await mgmtSdk.accessLists.create({
name: 'B2B Integration',
description: 'Bulk purchases from partner system',
type: 'BASIC_API',
status: 'ACTIVE',
});
// Update an access list
const updated = await mgmtSdk.accessLists.update('access_list_123', {
name: 'Updated B2B Integration',
excludeFromStats: false,
});
// Get specific access list
const accessList = await mgmtSdk.accessLists.get('access_list_123');
// Manage grants (purchases) under an access list
const grants = await mgmtSdk.accessLists.grants.list('access_list_123');
// Create a new grant for a user
const grant = await mgmtSdk.accessLists.grants.create('access_list_123', {
email: 'user@example.com',
sku: 'premium-article-123',
poId: 'po_456',
status: 'ACTIVE',
});
// Update a grant
const updatedGrant = await mgmtSdk.accessLists.grants.update('access_list_123', 'grant_456', {
status: 'INACTIVE',
});
// Delete a grant
await mgmtSdk.accessLists.grants.delete('access_list_123', 'grant_456');Customer Information (Management API)
// Get customer information in XML format (for external systems)
const customerXml = await mgmtSdk.customers.get('customer-123');
console.log(customerXml); // XML stringAPI Reference
For complete API documentation, see the API Reference.
Migration from Direct API Calls
If you're currently making direct HTTP requests to Sesamy APIs:
// Before: Direct API calls
const response = await fetch('/api/v1/profile', {
headers: { Authorization: `Bearer ${token}` },
});
const profile = await response.json();
// After: Using SDK
const profile = await sdk.profile.get();Next Steps
- API Reference →
- Authentication Guide →
- Sesamy JS Browser Library → (higher-level browser features)