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

@sablepay/angular-sablepay-js

v1.2.0

Published

SablePay Angular SDK for crypto payment integration with QR codes, polling, and pre-built UI components

Downloads

198

Readme

@sablepay/angular-sablepay-js

The official SablePay Angular SDK for Angular applications.

Accept crypto payments (USDC, USDT, and more) with QR codes, automatic status polling, and pre-built services.


Features

  • Full TypeScript support with complete type definitions
  • Angular ServicesSablePayService, PaymentFlowService
  • QR code generation — Built-in QR code generation (PNG, SVG, Canvas)
  • Automatic polling — Poll payment status with exponential backoff
  • Retry logic — Automatic retry with exponential backoff for network errors
  • Payment flow management — End-to-end payment lifecycle handling
  • Compatible with Angular 14+ — Works with both standalone and NgModule-based apps
  • Tree-shakeable — Import only what you need
  • Zero config — Auto-detects sandbox vs production from API key
  • NPM deployable — Ready to publish to npm

Installation

npm install @sablepay/angular-sablepay-js
# or
yarn add @sablepay/angular-sablepay-js
# or
pnpm add @sablepay/angular-sablepay-js

Quick Start

1. Initialize the SDK

// In app.component.ts or APP_INITIALIZER
import { SablePay } from '@sablepay/angular-sablepay-js';
import { environment } from './environments/environment';

SablePay.initialize({
  apiKey: environment.sablepayApiKey,
  merchantId: environment.sablepayMerchantId,
  enableLogging: !environment.production,
});

2. Create a Payment (Simplest)

import { Component } from '@angular/core';
import { SablePay, QrCodeGenerator } from '@sablepay/angular-sablepay-js';

@Component({
  selector: 'app-checkout',
  template: `
    <button (click)="pay()" [disabled]="loading">Pay $10.50</button>
    <img *ngIf="qrUrl" [src]="qrUrl" alt="Scan to pay" width="300" height="300" />
  `,
})
export class CheckoutComponent {
  loading = false;
  qrUrl = '';

  async pay() {
    this.loading = true;
    const sdk = SablePay.getInstance();
    const response = await sdk.createPayment({ amount: 10.50 });

    const qrGen = new QrCodeGenerator();
    this.qrUrl = (await qrGen.generatePaymentQr(response)) || '';
    this.loading = false;
  }
}

3. Use the PaymentFlowService (Recommended)

import { Component, OnDestroy } from '@angular/core';
import { PaymentFlowService } from '@sablepay/angular-sablepay-js';

@Component({
  selector: 'app-payment',
  template: `
    <div [ngSwitch]="flowService.state.type">
      <button *ngSwitchCase="'idle'" (click)="startPayment()">Pay $10.50</button>
      <p *ngSwitchCase="'creating'">Creating payment...</p>
      <div *ngSwitchCase="'awaiting'">
        <img [src]="flowService.qrDataUrl" alt="Scan to pay" width="300" />
        <p>Scan the QR code with your wallet</p>
        <button (click)="cancel()">Cancel</button>
      </div>
      <p *ngSwitchCase="'processing'">Processing payment...</p>
      <p *ngSwitchCase="'completed'">Payment complete!</p>
      <p *ngSwitchCase="'failed'">Error: {{ flowService.error }}</p>
    </div>
  `,
})
export class PaymentComponent implements OnDestroy {
  flowService = new PaymentFlowService();

  async startPayment() {
    await this.flowService.startPayment(10.50, undefined, {
      onPaymentCompleted: (status) => {
        console.log('Done!', status.transactionId);
      },
      onPaymentFailed: (error) => {
        console.error('Failed:', error.message);
      },
    });
  }

  cancel() {
    this.flowService.cancel();
  }

  ngOnDestroy() {
    this.flowService.release();
  }
}

Using SablePayService

The SablePayService wraps the core SablePay singleton for convenience:

import { Component, OnInit, OnDestroy } from '@angular/core';
import { SablePayService } from '@sablepay/angular-sablepay-js';
import { environment } from '../environments/environment';

@Component({
  selector: 'app-root',
  template: `<router-outlet></router-outlet>`,
})
export class AppComponent implements OnInit, OnDestroy {
  private sablePayService = new SablePayService();

  ngOnInit() {
    this.sablePayService.initialize({
      apiKey: environment.sablepayApiKey,
      merchantId: environment.sablepayMerchantId,
      enableLogging: !environment.production,
    });
  }

  ngOnDestroy() {
    this.sablePayService.release();
  }
}

// In a child component:
import { SablePayService } from '@sablepay/angular-sablepay-js';

@Component({ ... })
export class CheckoutComponent {
  private sablePayService = new SablePayService();

  async checkout() {
    const response = await this.sablePayService.createPayment({ amount: 25.00 });
    console.log('Payment ID:', response.paymentId);
    console.log('Payment Link:', response.paymentLink);
  }
}

API Reference

SablePay (Core)

// Initialize (call once)
SablePay.initialize({
  apiKey: 'sable_sk_sand_...',     // Required
  merchantId: 'uuid-here',         // Required
  baseUrl: '...',                   // Optional (auto-detected)
  enableLogging: true,              // Optional (default: false)
});

// Get instance
const sdk = SablePay.getInstance();

// Create a payment
const response = await sdk.createPayment({
  amount: 10.50,
  metadata: { orderId: 'ORD-123' },
});
// response.paymentId, response.paymentLink, response.status, etc.

// Get payment status
const status = await sdk.getPaymentStatus('payment-id');
// status.status, status.transactionId, status.paidToken, etc.

// List payments
const payments = await sdk.listPayments(20, 0);

// Check environment
sdk.getEnvironment(); // 'sandbox' | 'production'

// Check if configured
sdk.isConfigured(); // boolean

// Create a payment flow
const flow = SablePay.createPaymentFlow();

// Release resources
SablePay.release();

SablePayService

const service = new SablePayService();

service.initialize(config);           // Initialize SDK
service.isInitialized();              // Check if initialized
service.createPayment(request);       // Create a payment
service.getPaymentStatus(paymentId);  // Get payment status
service.listPayments(limit, offset);  // List payments
service.getEnvironment();             // Get environment
service.createPaymentFlow(options);   // Create payment flow
service.release();                    // Release resources

PaymentFlowService

Complete payment lifecycle management with state tracking.

const flowService = new PaymentFlowService();

// Properties
flowService.state;            // PaymentFlowState
flowService.isActive;         // boolean
flowService.qrDataUrl;        // string | null
flowService.paymentResponse;  // CreatePaymentResponse | null
flowService.paymentStatus;    // PaymentStatusResponse | null
flowService.error;            // string | null

// Methods
await flowService.startPayment(amount, metadata?, callbacks?, options?);
flowService.cancel();
flowService.release();        // Call in ngOnDestroy

Callbacks:

await flowService.startPayment(10.50, undefined, {
  onPaymentCreated: (response, qrUrl) => { },
  onStatusUpdate: (status) => { },
  onPaymentCompleted: (status) => { },
  onPaymentFailed: (error) => { },
  onStateChange: (state) => { },
});

Models

interface CreatePaymentRequest {
  amount: number;                         // USD amount (0.01 - 1,000,000)
  items?: PaymentItem[];                  // Optional line items
  metadata?: Record<string, string>;      // Optional metadata
}

interface CreatePaymentResponse {
  paymentId: string;
  status: string;
  amount: number;
  acceptedTokens: string;
  paymentLink: string | null;
  businessName: string;
  expiresAt: string | null;
  createdAt: string;
}

interface PaymentStatusResponse {
  paymentId: string;
  amount: number;
  status: string;             // PENDING | COMPLETED | FAILED | EXPIRED
  transactionId?: string | null;
  paidToken?: string | null;
  paidNetwork?: string | null;
  paidAmount?: number | null;
  metadata?: Record<string, unknown> | null;
  createdAt: string;
  completedAt?: string | null;
  expiresAt?: string | null;
}

Error Handling

import { ApiException } from '@sablepay/angular-sablepay-js';

try {
  await sdk.createPayment({ amount: 10.50 });
} catch (error) {
  if (error instanceof ApiException) {
    console.log(error.statusCode);    // 400, 401, 429, 500, etc.
    console.log(error.message);       // Error message
    console.log(error.requestId);     // For debugging
    console.log(error.isRetryable);   // true for 5xx and 429
    console.log(error.isAuthError);   // true for 401
    console.log(error.retryAfter);    // Seconds to wait (for 429)
  }
}

QR Code Generator (Standalone)

import { QrCodeGenerator } from '@sablepay/angular-sablepay-js';

const generator = new QrCodeGenerator({ width: 400, height: 400 });

// From payment response
const dataUrl = await generator.generatePaymentQr(response);

// From any text
const qr = await generator.generate('https://example.com');

// As SVG
const svg = await generator.generateSvg('https://example.com');

Payment Poller (Standalone)

import { PaymentPoller } from '@sablepay/angular-sablepay-js';

const poller = new PaymentPoller((id) => sdk.getPaymentStatus(id));

// Callback-based
poller.startPolling('payment-id', (result) => {
  if (result.success) console.log(result.data.status);
});
poller.stopPolling();

// Promise-based (awaits terminal state)
const finalStatus = await poller.pollUntilTerminal('payment-id');

Environment Setup

environment.ts

export const environment = {
  production: false,
  sablepayApiKey: 'sable_sk_sand_...',
  sablepayMerchantId: '00000000-0000-0000-0000-000000000000',
  sablepayBaseUrl: 'https://sandbox-api.sablepay.io/api/v1/',
};
  • Sandbox keys: sable_sk_sand_... → auto-routes to https://sandbox-api.sablepay.io
  • Production keys: sable_sk_live_... → auto-routes to https://api.sablepay.io
  • Sandbox web URL: https://sandbox.sablepay.io
  • Live web URL: https://www.sablepay.io/

Payment Flow States

| State | Description | |-------|-------------| | idle | No payment in progress | | creating | Payment being created via API | | awaiting | QR code displayed, waiting for customer | | processing | Customer scanned, processing on blockchain | | completed | Payment successful | | failed | Payment failed, expired, or error |


Angular Integration Examples

Standalone Component (Angular 14+)

import { Component, OnDestroy } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SablePay, QrCodeGenerator, isCompleted, isExpired } from '@sablepay/angular-sablepay-js';

@Component({
  selector: 'app-payment',
  standalone: true,
  imports: [CommonModule],
  template: `
    <button (click)="pay()">Pay $10.50</button>
    <img *ngIf="qrUrl" [src]="qrUrl" alt="Scan to pay" />
    <p *ngIf="status">{{ status }}</p>
  `,
})
export class PaymentComponent implements OnDestroy {
  qrUrl = '';
  status = '';
  private paymentId = '';

  async pay() {
    const sdk = SablePay.getInstance();
    const response = await sdk.createPayment({ amount: 10.50 });
    this.paymentId = response.paymentId;

    const qrGen = new QrCodeGenerator();
    this.qrUrl = (await qrGen.generatePaymentQr(response)) || '';

    this.pollStatus();
  }

  private async pollStatus() {
    const sdk = SablePay.getInstance();
    const statusResp = await sdk.getPaymentStatus(this.paymentId);
    this.status = statusResp.status;

    if (!isCompleted(statusResp.status) && !isExpired(statusResp.status)) {
      setTimeout(() => this.pollStatus(), 3000);
    }
  }

  ngOnDestroy() {}
}

NgModule-based (Angular 14+)

// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { SablePay } from '@sablepay/angular-sablepay-js';
import { environment } from './environments/environment';

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule],
  bootstrap: [AppComponent],
})
export class AppModule {
  constructor() {
    SablePay.initialize({
      apiKey: environment.sablepayApiKey,
      merchantId: environment.sablepayMerchantId,
      enableLogging: !environment.production,
    });
  }
}

Using APP_INITIALIZER

import { APP_INITIALIZER, NgModule } from '@angular/core';
import { SablePay } from '@sablepay/angular-sablepay-js';
import { environment } from './environments/environment';

function initializeSablePay(): () => void {
  return () => {
    SablePay.initialize({
      apiKey: environment.sablepayApiKey,
      merchantId: environment.sablepayMerchantId,
      enableLogging: !environment.production,
    });
  };
}

@NgModule({
  providers: [
    {
      provide: APP_INITIALIZER,
      useFactory: initializeSablePay,
      multi: true,
    },
  ],
  ...
})
export class AppModule {}

CORS / Proxy Configuration

During development, you may need to proxy API calls to avoid CORS issues. Add a proxy config:

proxy.conf.json

{
  "/api/proxy": {
    "target": "https://sandbox-api.sablepay.io/api/v1",
    "secure": true,
    "changeOrigin": true,
    "pathRewrite": {
      "^/api/proxy": ""
    }
  }
}

angular.json

{
  "architect": {
    "serve": {
      "options": {
        "proxyConfig": "src/proxy.conf.json"
      }
    }
  }
}

Then initialize with the proxy URL:

SablePay.initialize({
  apiKey: environment.sablepayApiKey,
  merchantId: environment.sablepayMerchantId,
  baseUrl: `${window.location.origin}/api/proxy/`,
});

Example App

A full working Angular example app is included in example-app/. It features a Coffee Shop POS and Payment Status Lookup.

cd example-app

# 1. Update credentials in src/environments/environment.ts

# 2. Install dependencies
npm install

# 3. Run the app
npm start

Open http://localhost:4200 to see the example.


Building the SDK

npm run build       # Build CJS + ESM + type declarations
npm test            # Run tests
npm run typecheck   # Type checking only

Publishing to npm

# Build the SDK
npm run build

# Login to npm
npm login

# Publish
npm publish --access public

License

MIT — see LICENSE