@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 Services —
SablePayService,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-jsQuick 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 resourcesPaymentFlowService
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 ngOnDestroyCallbacks:
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 tohttps://sandbox-api.sablepay.io - Production keys:
sable_sk_live_...→ auto-routes tohttps://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 startOpen 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 onlyPublishing to npm
# Build the SDK
npm run build
# Login to npm
npm login
# Publish
npm publish --access publicLicense
MIT — see LICENSE
