Skip to content
Last updated

The PERS SDK is a platform-agnostic TypeScript library that provides a clean, modern interface for integrating with the PERS (Phygital Experience Rewards System) platform. Built with a Manager-Service architecture, it offers consistent APIs for loyalty and tokenization applications across web, mobile, and server environments.

What is PERS?

PERS is a SaaS tokenization and loyalty infrastructure. The SDK provides access to:

  • Token Operations - Balance queries, transfers, minting
  • Campaign Management - Campaign discovery, claims, triggers
  • User Management - Authentication, profiles, wallets
  • Business Operations - Merchant and partner integrations
  • Transactions - History, analytics, reporting
  • File Management - Secure upload/download with signed URLs

Installation

# Core SDK + required peer dependencies
npm install @explorins/pers-sdk @explorins/pers-shared ethers@^6.15.0

Quick Start

Basic Setup

import { PersSDK } from "@explorins/pers-sdk";
import { BrowserFetchClientAdapter } from "@explorins/pers-sdk/platform-adapters";

const sdk = new PersSDK(new BrowserFetchClientAdapter(), {
  environment: "production",
  // API Project Key is used to identify the Tenant Context.
  // It does NOT authenticate the user or admin.
  apiProjectKey: "your-project-key"
});

Authentication Flow

// Login with external JWT (Firebase, Auth0, etc.)
// This wraps the /auth/token endpoint using SessionAuthRequestDTO
await sdk.auth.loginWithToken(firebaseJWT, "user");

// Alternative: Login with raw user data (guest/anonymous users)
await sdk.auth.loginWithRawData({
  externalId: "guest-123",
  email: "guest@example.com",
  firstName: "Guest"
});

// Check authentication status
if (await sdk.auth.isAuthenticated()) {
  const user = await sdk.auth.getCurrentUser();
  console.log("Welcome,", user.name);
}

Core Operations

// Business operations
const businesses = await sdk.businesses.getActiveBusinesses();
const business = await sdk.businesses.getBusinessById("business-123");

// Campaign management
const campaigns = await sdk.campaigns.getActiveCampaigns();
const claim = await sdk.campaigns.claimCampaign({
  campaignId: "campaign-123",
  businessId: "business-456"  // Optional business context
});

// Token operations - get available tokens
const tokens = await sdk.tokens.getTokens();
const creditToken = await sdk.tokens.getActiveCreditToken();

// Transaction history
const transactions = await sdk.transactions.getUserTransactionHistory('ALL');

// File operations
const uploadUrl = await sdk.files.getSignedPutUrl("entity-123", "profile-image", "jpg");
const downloadUrl = await sdk.files.getSignedGetUrl("entity-123", "profile-image");

Platform Integration

Angular

import { Injectable } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { PersSDK } from "@explorins/pers-sdk";
import { AngularHttpClientAdapter } from "@explorins/pers-sdk/platform-adapters";

@Injectable({ providedIn: "root" })
export class PersSDKService {
  private sdk: PersSDK;

  constructor(httpClient: HttpClient) {
    this.sdk = new PersSDK(new AngularHttpClientAdapter(httpClient), {
      environment: "production",
      apiProjectKey: "your-project-key" // Tenant Context ID
    });
  }

  getSDK(): PersSDK {
    return this.sdk;
  }
}

React/Browser

import { PersSDK } from "@explorins/pers-sdk";
import { BrowserFetchClientAdapter } from "@explorins/pers-sdk/platform-adapters";

const sdk = new PersSDK(new BrowserFetchClientAdapter(), {
  environment: "production",
  apiProjectKey: "your-project-key"
});

// React Hook example
export function usePersSDK() {
  return sdk;
}

Node.js

import { PersSDK } from "@explorins/pers-sdk";
import { NodeHttpClientAdapter } from "@explorins/pers-sdk/platform-adapters";

const sdk = new PersSDK(new NodeHttpClientAdapter(), {
  environment: "production",
  apiProjectKey: "your-project-key"
});

Architecture Overview

The SDK follows a clean Manager-Service pattern:

Manager Layer (Primary Interface)

  • sdk.auth - Authentication and user sessions
  • sdk.users - User profile management
  • sdk.userStatus - User status/tier management
  • sdk.tokens - Token operations and balances
  • sdk.businesses - Business operations
  • sdk.campaigns - Marketing campaigns
  • sdk.redemptions - Reward redemptions
  • sdk.transactions - Transaction history
  • sdk.purchases - Purchase and payment processing
  • sdk.files - File upload and management
  • sdk.analytics - Reporting and insights
  • sdk.tenants - Multi-tenant configuration
  • sdk.apiKeys - API key management (admin)
  • sdk.donations - Charitable giving and donations
  • sdk.web3 - Blockchain operations and token balances

Service Layer (Advanced Access)

For advanced operations, you can access services directly:

const userService = sdk.users.getUserService();
const campaignService = sdk.campaigns.getCampaignService();
const fileService = sdk.files.getFileService();

Core Features

Authentication System

  • External JWT integration (Firebase, Auth0, custom providers)
  • Native token validation and refresh
  • Support for both user and admin authentication flows
  • Automatic token management and renewal

Business Management

  • Business registration and profile management
  • Business type categorization
  • Public business discovery
  • Admin tools for business operations

Campaign System

  • Create and manage marketing campaigns
  • User participation and claim tracking
  • Advanced campaign triggers and automation
  • Analytics and performance metrics

Token Economy

  • Multi-token support (credit, reward, utility tokens)
  • Balance management and transfers
  • Transaction history and analytics
  • Integration with external payment systems

User Token Balances (On-Chain)

Important: User token balances are queried directly from the blockchain via sdk.web3.* methods, not stored in the PERS backend. See the npm package README for detailed examples.

File Management

  • Secure file upload and download
  • Signed URL generation for direct browser access
  • Media optimization and processing
  • Cloud storage integration

Reward Redemptions

  • Flexible redemption offer system
  • User redemption tracking
  • Multiple redemption types (discounts, products, experiences)
  • Inventory management

Configuration

interface PersConfig {
  environment?: "production";  // Currently only production is available
  apiProjectKey: string; // Tenant Context Identifier (NOT for Auth)
  authStorage?: TokenStorage;  // Default: LocalStorage, recommend IndexedDB
  dpop?: { enabled?: boolean }; // Default: true (security feature)
  timeout?: number;
  retries?: number;
}

Environment Configuration

  • production - Live environment (https://api.pers.ninja/v2)

Authentication Options

You can provide a custom authentication provider or let the SDK create one automatically:

// Auto-created provider (recommended)
const sdk = new PersSDK(httpClient, {
  environment: "production",
  apiProjectKey: "your-key"
});

// Custom provider
const sdk = new PersSDK(httpClient, {
  environment: "production",
  apiProjectKey: "your-key",
  authProvider: customAuthProvider
});

Error Handling

import { PersApiError, AuthenticationError } from "@explorins/pers-sdk/core";

try {
  const user = await sdk.auth.getCurrentUser();
} catch (error) {
  if (error instanceof AuthenticationError) {
    // Handle 401 - redirect to login
  } else if (error instanceof PersApiError) {
    console.error("API Error:", error.message, error.status);
  }
}

Performance Features

  • Bundle Size: ~85 KB minified
  • Tree-shaking: Import only what you need
  • Zero External Auth Dependencies: Native browser APIs
  • Intelligent Token Refresh: Background refresh with race condition protection
  • Request Optimization: Automatic retry and timeout handling

TypeScript Support

The SDK provides full TypeScript support with type inference. All domain types are exported from @explorins/pers-shared:

import type { CampaignDTO, BusinessDTO, TokenDTO } from '@explorins/pers-shared';

const campaigns = await sdk.campaigns.getActiveCampaigns(); // CampaignDTO[]

Advanced Usage

Direct API Access

For operations not covered by managers:

const apiClient = sdk.api();
const customData = await apiClient.get("/custom-endpoint");
await apiClient.post("/custom-endpoint", data);

Custom HTTP Client

Implement your own HTTP client for specific requirements:

import { HttpClient, RequestOptions } from "@explorins/pers-sdk/core";

class CustomHttpClient implements HttpClient {
  async get<T>(url: string, options?: RequestOptions): Promise<T> {
    // Your implementation
  }
  // ... other methods
}

const sdk = new PersSDK(new CustomHttpClient(), config);

Web3 / Blockchain Operations

Query token balances and owned NFTs directly from the blockchain:

// Get reward tokens configuration
const rewardTokens = await sdk.tokens.getRewardTokens();

// Query owned tokens for any wallet address
const result = await sdk.web3.getAccountOwnedTokensFromContract(
  walletAddress,
  rewardTokens[0]
);

console.log(`Wallet owns ${result.totalOwned} tokens`);
result.ownedTokens.forEach(token => {
  console.log(`- ${token.metadata?.name}: ${token.balance}`);
});

// Get blockchain explorer URL
const explorerUrl = await sdk.web3.getExplorerUrl(
  chainId,
  transactionHash,
  'tx'
);
  • @explorins/pers-sdk-react-native - React Native integration with passkey support, secure storage, and DPoP. Use this for React Native apps instead of the core SDK.
  • @explorins/pers-shared - Shared types, interfaces, and DTOs used across PERS ecosystem (required peer dependency)

Support and Resources

License

MIT License - See package for full license details.