npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

self-serve-integration-service

v1.0.0

Published

Self-Serve Integration Service for managing multiple funder integrations including REST APIs, SOAP APIs, and UI automation

Downloads

13

Readme

Self-Serve Integration Service

A comprehensive integration service that provides a unified API for multiple vehicle finance funders including LEX, ALPHABET, and future funders.

🚀 Features

  • Multi-Funder Support: Unified API for LEX, ALPHABET, and extensible for additional funders
  • Environment Support: Both SANDBOX and LIVE environments for each funder
  • Common Request Structure: Standardized request/response format across all funders
  • 🔁 Dynamic Retry Mechanism: Configurable retry logic with exponential backoff for all funder API calls
  • Comprehensive Logging: Full integration logging and monitoring
  • Database Persistence: Complete quote and proposal data storage
  • Customer Management: Automatic customer and vehicle data management
  • Proposal Generation: Convert quotes to proposals with additional customer details
  • JWT Authentication: Secure API access with RS256 token verification

🏗️ Architecture

Database Schema

The service uses a well-designed database schema that supports:

  • Multiple Funders: Each funder has its own configuration and credentials
  • Customer Management: Centralized customer data with flexible address/employment info
  • Vehicle Management: Comprehensive vehicle data with funder-specific identifiers
  • Quote Lifecycle: Complete quote generation, storage, and status tracking
  • Proposal Management: Proposal generation and decision tracking
  • Integration Logging: Full audit trail of all API interactions

Service Architecture

┌─────────────────────────────────────────────────────────────┐
│                    Integration Service                      │
├─────────────────────────────────────────────────────────────┤
│  ┌─────────────────┐  ┌─────────────────┐  ┌─────────────┐ │
│  │   LEX Service   │  │ Alphabet Service │  │ Future...   │ │
│  │   (SANDBOX)     │  │   (SANDBOX)     │  │             │ │
│  │   (LIVE)        │  │   (LIVE)        │  │             │ │
│  └─────────────────┘  └─────────────────┘  └─────────────┘ │
├─────────────────────────────────────────────────────────────┤
│                    Base Funder Service                      │
│              (Common functionality & logging)              │
├─────────────────────────────────────────────────────────────┤
│                    Database Layer (Prisma)                 │
│              (PostgreSQL with full schema)                  │
└─────────────────────────────────────────────────────────────┘

📋 API Endpoints

Main Integration API

All endpoints are prefixed with /api/integration

Quote Generation

POST /api/integration/quotes/generate

Request Body:

{
  "customerDetails": {
    "firstName": "John",
    "lastName": "Doe",
    "email": "[email protected]",
    "phone": "+44 7700 900001",
    "dateOfBirth": "1985-06-20",
    "address": {
      "line1": "123 Main Street",
      "line2": "Apartment 4B",
      "city": "London",
      "postcode": "SW1A 1AA",
      "country": "UK"
    },
    "employment": {
      "employerName": "Tech Solutions Ltd",
      "jobTitle": "Software Engineer",
      "employmentType": "FULL_TIME",
      "monthlyIncome": 4500
    }
  },
  "vehicleDetails": {
    "make": "BMW",
    "model": "3 Series",
    "variant": "320d M Sport",
    "year": 2024,
    "price": 38000,
    "mileage": 0,
    "fuelType": "DIESEL",
    "transmission": "AUTOMATIC",
    "capId": "12345",
    "capCode": "BMW320DMS"
  },
  "contractDetails": {
    "term": 36,
    "deposit": 2500,
    "annualMileage": 12000,
    "quoteType": "PERSONAL_CONTRACT_HIRE",
    "balloonPayment": 8000,
    "maintenanceIncluded": true
  },
  "funderName": "LEX",
  "environment": "SANDBOX",
  "source": "SELF_SERVE_APP"
}

Response:

{
  "success": true,
  "data": {
    "id": "123e4567-e89b-12d3-a456-426614174000",
    "funderName": "LEX",
    "status": "GENERATED",
    "monthlyPayment": 450.00,
    "totalAmount": 16200.00,
    "apr": 4.9,
    "balloonPayment": 8000.00,
    "externalQuoteId": "Q12345",
    "externalReference": "LEX-2024-001",
    "validUntil": "2024-12-31T23:59:59Z",
    "createdAt": "2024-08-26T10:20:54.000Z",
    "updatedAt": "2024-08-26T10:20:54.000Z"
  },
  "message": "Quote generated successfully with LEX"
}

Quote Status

GET /api/integration/quotes/{quoteId}/status

Proposal Generation

POST /api/integration/proposals/generate

Request Body:

{
  "quoteId": "123e4567-e89b-12d3-a456-426614174000",
  "additionalCustomerDetails": {
    "address": {
      "line1": "123 Main Street",
      "city": "London",
      "postcode": "SW1A 1AA"
    },
    "employment": {
      "employerName": "Tech Solutions Ltd",
      "jobTitle": "Software Engineer",
      "employmentType": "FULL_TIME",
      "monthlyIncome": 4500
    }
  },
  "additionalDocuments": {
    "drivingLicense": "base64-encoded-data",
    "proofOfAddress": "base64-encoded-data"
  }
}

Proposal Status

GET /api/integration/proposals/{proposalId}/status

Available Funders

GET /api/integration/funders

Test Funder Connection

POST /api/integration/funders/{funderName}/test

Customer Quotes

GET /api/integration/customers/{email}/quotes

Customer Proposals

GET /api/integration/customers/{email}/proposals

🔐 Authentication

The Integration Service uses JWT (JSON Web Token) authentication with RS256 algorithm for secure API access.

Authentication Flow

  1. Obtain JWT token from Auth Service
  2. Include token in Authorization header: Authorization: Bearer <token>
  3. Integration Service verifies token using public key
  4. User context is extracted and available in route handlers

Protected Routes

The following routes require authentication:

  • All /api/integration/* endpoints
  • All /api/vehicles endpoints
  • All /api/customers endpoints
  • All /api/quotes endpoints
  • All /api/proposals endpoints
  • All /api/funders endpoints

Public Routes

The following routes do NOT require authentication:

  • /health - Health check
  • /webhooks/* - Webhook endpoints (validated via signatures)
  • /api-docs - API documentation

Usage Example

# Get token from Auth Service (example)
TOKEN="eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."

# Make authenticated request
curl -X POST http://localhost:3003/api/integration/quotes/generate \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "customerDetails": {...},
    "vehicleDetails": {...},
    "contractDetails": {...}
  }'

JWT Configuration

Required environment variables:

# JWT Configuration (RS256 public key)
JWT_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----\n"
JWT_ISSUER=self-serve-platform
JWT_AUDIENCE=self-serve-users

For detailed authentication documentation, see JWT_AUTHENTICATION.md

🔁 Retry Mechanism

The Integration Service includes a robust retry mechanism for all funder API calls to handle transient failures automatically.

Features

  • Exponential Backoff: Intelligent delay strategy to avoid overwhelming failing services
  • Configurable: Fully customizable via environment variables
  • Funder-Specific: Different retry settings per funder (LEX, Alphabet, etc.)
  • Global Control: Enable/disable retries with a single flag
  • Comprehensive Logging: All retry attempts tracked in IntegrationLog table

Configuration

# Global retry configuration
API_RETRY_ENABLED=true              # Enable/disable retries
API_MAX_RETRIES=3                   # Maximum retry attempts
API_RETRY_BASE_DELAY=1000           # Base delay in milliseconds
API_RETRY_MAX_DELAY=10000           # Maximum delay cap
API_RETRY_BACKOFF_MULTIPLIER=2      # Exponential multiplier

# Funder-specific overrides (optional)
LEX_MAX_RETRIES=3
LEX_RETRY_BASE_DELAY=1000

ALPHABET_MAX_RETRIES=5
ALPHABET_RETRY_BASE_DELAY=2000

How It Works

Delay = min(BASE_DELAY × MULTIPLIER^(attempt-1), MAX_DELAY)

Example with default settings (3 retries):

  • Attempt 1: Immediate (0ms delay)
  • Attempt 2: 1000ms delay
  • Attempt 3: 2000ms delay
  • Attempt 4: 4000ms delay

Total maximum time: ~7 seconds for 3 retries

Monitoring

All retry attempts are logged in the IntegrationLog table:

SELECT 
  operation,
  status,
  "retryCount",
  "responseTime"
FROM "IntegrationLog"
WHERE status IN ('RETRY', 'FAILED')
ORDER BY "createdAt" DESC;

For complete documentation, see:

🔧 Configuration

Environment Variables

Copy env.example to .env and configure:

# Database
DATABASE_URL="postgresql://username:password@localhost:5432/self_serve_integration"

# LEX Configuration
LEX_APP_ID=6B7b5D1GnPG
LEX_SHARED_SECRET=5bxZBDwTQpYXIuKNzZKAZFGXQGRdtHRqOkf8Dg==
LEX_DEALER_ID_MAJOR=514244
LEX_DEALER_ID_MINOR=FLCSW7X4
LEX_JWT_EXPIRY_HOURS=24

# ALPHABET Configuration
ALPHABET_API_KEY=Egyml2M52BTKw72hB0
ALPHABET_SANDBOX_URL=https://demoservices.codeweavers.net
ALPHABET_LIVE_URL=https://services.codeweavers.net

Database Setup

  1. Create Database:
createdb self_serve_integration
  1. Run Migrations:
npx prisma migrate dev
  1. Seed Database:
npx prisma db seed

🚀 Getting Started

Prerequisites

  • Node.js 18+
  • PostgreSQL 13+
  • npm or yarn

Installation

  1. Install Dependencies:
npm install
  1. Setup Environment:
cp env.example .env
# Edit .env with your configuration
  1. Setup Database:
npx prisma migrate dev
npx prisma db seed
  1. Start Development Server:
npm run dev

The service will be available at http://localhost:3003

Production Deployment

  1. Build Application:
npm run build
  1. Run Production Server:
npm start

🔌 Funder Integrations

LEX Integration

  • Authentication: JWT tokens with HS256 algorithm
  • Environments: SANDBOX and LIVE
  • API Flow: Single API call for quote generation
  • Features: Quote generation, proposal submission, status tracking

ALPHABET Integration

  • Authentication: API Key (X-CW-ApiKey header)
  • Environments: SANDBOX and LIVE
  • API Flow: 3-step process (Vehicle Details → Finance Defaults → Calculate Quote)
  • Features: Quote generation, proposal submission, status tracking

Adding New Funders

To add a new funder:

  1. Create Service Class:
export class NewFunderService extends BaseFunderService {
  readonly funderName = 'NEW_FUNDER';
  readonly supportedQuoteTypes = ['PERSONAL_CONTRACT_HIRE'];
  readonly supportedProposalTypes = ['PERSONAL_CONTRACT_HIRE'];
  
  async generateQuote(request: QuoteRequest): Promise<QuoteResponse> {
    // Implementation
  }
  
  // ... other methods
}
  1. Add to Integration Service:
// In integrationService.ts
const newFunderSandbox = new NewFunderService('SANDBOX');
const newFunderLive = new NewFunderService('LIVE');
this.funderServices.set('NEW_FUNDER_SANDBOX', newFunderSandbox);
this.funderServices.set('NEW_FUNDER_LIVE', newFunderLive);
  1. Add Database Entry:
// In seed.ts
const newFunder = await prisma.funder.create({
  data: {
    name: 'NEW_FUNDER',
    code: 'NEW_FUNDER',
    displayName: 'New Funder',
    // ... configuration
  }
});

📊 Monitoring & Logging

Integration Logs

All API interactions are logged to the IntegrationLog table with:

  • Request/response data
  • Performance metrics
  • Error details
  • Retry information
  • Correlation IDs

Health Checks

GET /api/health

Returns service health status and funder connectivity.

Metrics

The service provides comprehensive metrics for:

  • Quote generation success rates
  • API response times
  • Error rates by funder
  • Retry statistics

🧪 Testing

Unit Tests

npm test

Integration Tests

npm run test:integration

Test Funder Connections

# Test LEX SANDBOX
curl -X POST http://localhost:3003/api/integration/funders/LEX/test \
  -H "Content-Type: application/json" \
  -d '{"environment": "SANDBOX"}'

# Test ALPHABET SANDBOX
curl -X POST http://localhost:3003/api/integration/funders/ALPHABET/test \
  -H "Content-Type: application/json" \
  -d '{"environment": "SANDBOX"}'

🔒 Security

  • No Credentials in Database: All credentials stored in environment variables
  • JWT Token Management: Automatic token generation and refresh
  • API Key Security: Secure API key handling
  • Request Validation: Comprehensive input validation
  • Error Handling: Secure error responses without sensitive data exposure

📈 Performance

  • Retry Mechanism: Exponential backoff with configurable limits
  • Connection Pooling: Efficient database connections
  • Caching: Optional Redis integration for caching
  • Rate Limiting: Built-in rate limiting per funder
  • Monitoring: Real-time performance metrics

🤝 Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests
  5. Submit a pull request

📄 License

This project is licensed under the MIT License.

🆘 Support

For issues and questions:

  1. Check the logs in the IntegrationLog table
  2. Review the health check endpoint
  3. Test individual funder connections
  4. Contact the development team

Built with ❤️ for the Self-Serve Application