Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.loyalty.lt/llms.txt

Use this file to discover all available pages before exploring further.

Examples

Complete working examples demonstrating various SDK features.

Live Examples

The SDK includes several HTML examples you can run locally:
ExampleDescriptionFile
QR LoginCustomer authentication via QRexamples/qr-login-example.html
QR Card ScanPOS customer identificationexamples/qr-card-scan-example.html
Full POS SystemComplete POS simulationexamples/pos-full-example.html

Running Examples

# Clone the repository
git clone https://github.com/Loyalty-lt/sdk-javascript.git
cd sdk-javascript

# Install dependencies & build
yarn install
yarn build

# Open examples in browser
open examples/qr-login-example.html

POS System Example

A complete Point of Sale implementation with customer identification, cart management, and points processing.

Features

  • Split-screen layout (Customer Display + POS Interface)
  • QR code customer identification
  • Real-time Ably updates
  • Product catalog
  • Cart with points earning preview
  • Points redemption
  • Manual card lookup
  • Send app download link

Key Code

import { LoyaltySDK } from '@loyaltylt/sdk';

class POSSystem {
  private sdk: LoyaltySDK;
  private currentCustomer: Customer | null = null;
  private cart: CartItem[] = [];
  
  constructor(apiKey: string, apiSecret: string) {
    this.sdk = new LoyaltySDK({
      apiKey,
      apiSecret,
      environment: 'production'
    });
  }
  
  // Start customer identification
  async startIdentification() {
    const session = await this.sdk.generateQrCardSession('POS');
    this.displayQR(session.qr_code);
    
    // Get Ably options with automatic token renewal
    const ablyOptions = await this.sdk.createAblyClientOptions(session.session_id);
    const tokenResponse = await this.sdk.getAblyToken(session.session_id);
    
    // Connect to Ably (token auto-renews)
    const ably = new Ably.Realtime(ablyOptions);
    const channel = ably.channels.get(tokenResponse.channel);
    
    channel.subscribe('card_identified', (message) => {
      this.handleCustomerIdentified(message.data.card_data);
    });
  }
  
  // Process checkout
  async checkout() {
    const total = this.calculateTotal();
    const pointsToEarn = Math.floor(total * 10);
    
    await this.sdk.createTransaction({
      card_id: this.currentCustomer.cardId,
      amount: total,
      points: pointsToEarn,
      type: 'earn',
      description: 'Purchase',
      reference: `POS-${Date.now()}`
    });
    
    this.showSuccess(`+${pointsToEarn} points earned!`);
    this.clearCart();
    this.clearCustomer();
  }
}

Points Calculation

Use the SDK’s built-in calculation functions for accurate points math:
import { 
  calculateAmountFromPoints,
  calculatePointsFromAmount,
  calculateFinalAmount 
} from '@loyaltylt/sdk';

// Points rules from card_identified event
const pointsRules = cardData.redemption;

// Calculate discount value
const discount = calculateAmountFromPoints(500, pointsRules);
// 500 points = 5.00 EUR

// Calculate points to earn
const pointsToEarn = calculatePointsFromAmount(cartTotal, pointsRules);
// 25.00 EUR = 250 points

// Calculate final amount after discount
const finalAmount = calculateFinalAmount(cartTotal, pointsToRedeem, pointsRules);
// 50.00 EUR - 5.00 EUR = 45.00 EUR
Always use the pointsRules from the backend instead of hardcoding values. Rules can vary per partner and may change.

React Integration

Next.js App Router

// app/loyalty/page.tsx
'use client';

import { useState, useEffect } from 'react';
import { QRLogin, QRCardDisplay } from '@loyaltylt/sdk/react';
import '@loyaltylt/sdk/styles';

export default function LoyaltyPage() {
  const [isLoggedIn, setIsLoggedIn] = useState(false);
  const [userToken, setUserToken] = useState<string | null>(null);
  
  useEffect(() => {
    const token = localStorage.getItem('loyalty_token');
    if (token) {
      setUserToken(token);
      setIsLoggedIn(true);
    }
  }, []);
  
  if (!isLoggedIn) {
    return (
      <div className="flex min-h-screen items-center justify-center">
        <QRLogin
          apiKey={process.env.NEXT_PUBLIC_LOYALTY_API_KEY!}
          apiSecret={process.env.NEXT_PUBLIC_LOYALTY_API_SECRET!}
          onAuthenticated={(user, token) => {
            localStorage.setItem('loyalty_token', token);
            setUserToken(token);
            setIsLoggedIn(true);
          }}
        />
      </div>
    );
  }
  
  return (
    <div className="container mx-auto p-8">
      <h1 className="text-2xl font-bold mb-6">Your Loyalty Card</h1>
      <QRCardDisplay
        apiKey={process.env.NEXT_PUBLIC_LOYALTY_API_KEY!}
        apiSecret={process.env.NEXT_PUBLIC_LOYALTY_API_SECRET!}
        userToken={userToken!}
        showPoints
        showUserInfo
      />
    </div>
  );
}

Environment Variables

# .env.local
NEXT_PUBLIC_LOYALTY_API_KEY=lty_your_api_key
NEXT_PUBLIC_LOYALTY_API_SECRET=your_api_secret

Node.js Backend

Express.js Integration

// server.ts
import express from 'express';
import { LoyaltySDK } from '@loyaltylt/sdk';

const app = express();
app.use(express.json());

const sdk = new LoyaltySDK({
  apiKey: process.env.LOYALTY_API_KEY!,
  apiSecret: process.env.LOYALTY_API_SECRET!,
  environment: 'production'
});

// Award points after purchase
app.post('/api/orders/complete', async (req, res) => {
  const { orderId, cardNumber, amount } = req.body;
  
  try {
    // Find customer's card
    const cards = await sdk.getLoyaltyCards({ card_number: cardNumber });
    
    if (!cards.data.length) {
      return res.status(404).json({ error: 'Card not found' });
    }
    
    const card = cards.data[0];
    const pointsToAward = Math.floor(amount * 10);
    
    // Award points
    const transaction = await sdk.createTransaction({
      card_id: card.id,
      amount,
      points: pointsToAward,
      type: 'earn',
      description: `Order #${orderId}`,
      reference: orderId
    });
    
    res.json({
      success: true,
      points_awarded: pointsToAward,
      new_balance: card.points_balance + pointsToAward
    });
    
  } catch (error) {
    console.error('Error awarding points:', error);
    res.status(500).json({ error: 'Failed to award points' });
  }
});

// Get customer info by card number
app.get('/api/customers/lookup', async (req, res) => {
  const { card_number } = req.query;
  
  try {
    const cards = await sdk.getLoyaltyCards({ card_number: String(card_number) });
    
    if (!cards.data.length) {
      return res.status(404).json({ error: 'Card not found' });
    }
    
    const card = cards.data[0];
    res.json({
      name: card.user?.name,
      card_number: card.card_number,
      points: card.points_balance,
      status: card.status
    });
    
  } catch (error) {
    res.status(500).json({ error: 'Lookup failed' });
  }
});

app.listen(3000, () => {
  console.log('Server running on port 3000');
});

Webhooks Integration

// Handle loyalty webhooks
app.post('/api/webhooks/loyalty', async (req, res) => {
  const { event, data } = req.body;
  
  switch (event) {
    case 'points.awarded':
      console.log(`Customer ${data.customer_id} earned ${data.points} points`);
      // Update your database, send notification, etc.
      break;
      
    case 'points.redeemed':
      console.log(`Customer ${data.customer_id} redeemed ${data.points} points`);
      break;
      
    case 'offer.claimed':
      console.log(`Customer claimed offer: ${data.offer_id}`);
      break;
  }
  
  res.json({ received: true });
});

GitHub Repository

All examples are available in the SDK repository:

GitHub Repository

View complete source code and examples

Next Steps

API Reference

Complete SDK API documentation

Shop API Docs

Backend API documentation