@sablepay/react-native-sablepay-js
v1.0.3
Published
SablePay React Native SDK for crypto payment integration with QR codes, polling, hooks, and pre-built payment flow management
Readme
@sablepay/react-native-sablepay-js
The official SablePay React Native SDK for React Native applications.
Accept crypto payments (USDC, USDT, and more) with QR codes, automatic status polling, and pre-built React hooks.
Features
- Full TypeScript support with complete type definitions
- React Native Hooks —
useSablePay,usePaymentFlow - QR code generation — Built-in QR code generation (PNG, SVG)
- Automatic polling — Poll payment status with configurable intervals
- Retry logic — Automatic retry with exponential backoff for network errors
- Payment flow management — End-to-end payment lifecycle handling
- Compatible with React Native 0.70+ and Expo
- 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/react-native-sablepay-js
# or
yarn add @sablepay/react-native-sablepay-js
# or
pnpm add @sablepay/react-native-sablepay-jsQuick Start
1. Initialize the SDK
// In your App.tsx or root component
import { SablePay } from '@sablepay/react-native-sablepay-js';
// Initialize once on app startup
SablePay.initialize({
apiKey: 'sable_sk_sand_...',
merchantId: '00000000-0000-0000-0000-000000000000',
enableLogging: __DEV__,
});2. Create a Payment (Simplest)
import React, { useState } from 'react';
import { View, Button, Image, Text } from 'react-native';
import { SablePay, QrCodeGenerator } from '@sablepay/react-native-sablepay-js';
function CheckoutScreen() {
const [qrUrl, setQrUrl] = useState('');
const [loading, setLoading] = useState(false);
const pay = async () => {
setLoading(true);
const sdk = SablePay.getInstance();
const response = await sdk.createPayment({ amount: 10.50 });
const qrGen = new QrCodeGenerator();
const dataUrl = await qrGen.generatePaymentQr(response);
setQrUrl(dataUrl || '');
setLoading(false);
};
return (
<View>
<Button title="Pay $10.50" onPress={pay} disabled={loading} />
{qrUrl ? <Image source={{ uri: qrUrl }} style={{ width: 300, height: 300 }} /> : null}
</View>
);
}3. Use the usePaymentFlow Hook (Recommended)
import React, { useEffect } from 'react';
import { View, Button, Image, Text } from 'react-native';
import { usePaymentFlow } from '@sablepay/react-native-sablepay-js';
function PaymentScreen() {
const {
state,
qrDataUrl,
paymentStatus,
error,
startPayment,
cancel,
release,
} = usePaymentFlow();
useEffect(() => {
return () => release(); // Clean up on unmount
}, []);
const handlePay = async () => {
await startPayment(10.50, undefined, {
onPaymentCompleted: (status) => {
console.log('Done!', status.transactionId);
},
onPaymentFailed: (err) => {
console.error('Failed:', err.message);
},
});
};
return (
<View>
{state.type === 'idle' && <Button title="Pay $10.50" onPress={handlePay} />}
{state.type === 'creating' && <Text>Creating payment...</Text>}
{state.type === 'awaiting' && qrDataUrl && (
<>
<Image source={{ uri: qrDataUrl }} style={{ width: 300, height: 300 }} />
<Text>Scan the QR code with your wallet</Text>
<Button title="Cancel" onPress={cancel} />
</>
)}
{state.type === 'processing' && <Text>Processing payment...</Text>}
{state.type === 'completed' && <Text>Payment complete!</Text>}
{state.type === 'failed' && <Text>Error: {error}</Text>}
</View>
);
}Using useSablePay Hook
The useSablePay hook wraps the core SablePay singleton for convenient use in components:
import React from 'react';
import { View, Button, Text } from 'react-native';
import { useSablePay } from '@sablepay/react-native-sablepay-js';
function PaymentComponent() {
const { createPayment, getPaymentStatus, getEnvironment } = useSablePay();
const handlePay = async () => {
const response = await createPayment({ amount: 25.00 });
console.log('Payment ID:', response.paymentId);
console.log('Payment Link:', response.paymentLink);
};
return (
<View>
<Text>Environment: {getEnvironment()}</Text>
<Button title="Pay $25.00" onPress={handlePay} />
</View>
);
}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();useSablePay Hook
const {
sdk, // SablePay instance
createPayment, // (request) => Promise<CreatePaymentResponse>
getPaymentStatus, // (paymentId) => Promise<PaymentStatusResponse>
listPayments, // (limit?, offset?) => Promise<PaymentStatusResponse[]>
getEnvironment, // () => string | null
isConfigured, // () => boolean
createPaymentFlow, // (options?) => PaymentFlow
} = useSablePay();usePaymentFlow Hook
Complete payment lifecycle management with automatic state tracking.
const {
state, // PaymentFlowState
isActive, // boolean
qrDataUrl, // string | null
paymentResponse, // CreatePaymentResponse | null
paymentStatus, // PaymentStatusResponse | null
error, // string | null
startPayment, // (amount, metadata?, callbacks?, options?) => Promise<void>
cancel, // () => void
release, // () => void — call in useEffect cleanup
} = usePaymentFlow();Callbacks:
await 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
expiresIn?: number; // Expiration in seconds (default: 600)
}
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/react-native-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/react-native-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/react-native-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
// config/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 |
React Native Integration Examples
Functional Component with Hooks
import React, { useEffect } from 'react';
import { View, Button, Image, Text, ActivityIndicator } from 'react-native';
import { usePaymentFlow } from '@sablepay/react-native-sablepay-js';
export function PaymentScreen() {
const { state, qrDataUrl, error, startPayment, cancel, release } = usePaymentFlow();
useEffect(() => () => release(), []);
return (
<View style={{ flex: 1, padding: 20 }}>
{state.type === 'idle' && (
<Button title="Pay $10.50" onPress={() => startPayment(10.50)} />
)}
{state.type === 'creating' && (
<ActivityIndicator size="large" />
)}
{state.type === 'awaiting' && qrDataUrl && (
<View style={{ alignItems: 'center' }}>
<Image source={{ uri: qrDataUrl }} style={{ width: 300, height: 300 }} />
<Text>Scan to pay</Text>
<Button title="Cancel" onPress={cancel} />
</View>
)}
{state.type === 'completed' && <Text>Payment complete!</Text>}
{state.type === 'failed' && <Text style={{ color: 'red' }}>Error: {error}</Text>}
</View>
);
}Class Component (Direct SDK)
import React, { Component } from 'react';
import { View, Button, Image, Text } from 'react-native';
import {
SablePay,
QrCodeGenerator,
isCompleted,
isExpired,
} from '@sablepay/react-native-sablepay-js';
export class PaymentComponent extends Component {
state = { qrUrl: '', status: '', paymentId: '' };
pay = async () => {
const sdk = SablePay.getInstance();
const response = await sdk.createPayment({ amount: 10.50 });
this.setState({ paymentId: response.paymentId });
const qrGen = new QrCodeGenerator();
const dataUrl = await qrGen.generatePaymentQr(response);
this.setState({ qrUrl: dataUrl || '' });
this.pollStatus(response.paymentId);
};
pollStatus = async (paymentId) => {
const sdk = SablePay.getInstance();
const statusResp = await sdk.getPaymentStatus(paymentId);
this.setState({ status: statusResp.status });
if (!isCompleted(statusResp.status) && !isExpired(statusResp.status)) {
setTimeout(() => this.pollStatus(paymentId), 3000);
}
};
render() {
return (
<View>
<Button title="Pay" onPress={this.pay} />
{this.state.qrUrl ? (
<Image source={{ uri: this.state.qrUrl }} style={{ width: 300, height: 300 }} />
) : null}
<Text>Status: {this.state.status}</Text>
</View>
);
}
}Expo App Initialization
import React, { useEffect, useState } from 'react';
import { View, Text } from 'react-native';
import { SablePay } from '@sablepay/react-native-sablepay-js';
export default function App() {
const [ready, setReady] = useState(false);
useEffect(() => {
SablePay.initialize({
apiKey: 'sable_sk_sand_...',
merchantId: '00000000-0000-0000-0000-000000000000',
enableLogging: __DEV__,
});
setReady(true);
return () => SablePay.release();
}, []);
if (!ready) return <Text>Loading...</Text>;
return (
<View>
{/* Your payment screens here */}
</View>
);
}Example App
A full working React Native (Expo) example app is available at https://github.com/Sable-Payments-Inc/sablepay-react-native-sdk-example. It features a Coffee Shop POS and Payment Status Lookup — matching the Angular SDK example.
# 1. Clone the example app repository
git clone https://github.com/Sable-Payments-Inc/sablepay-react-native-sdk-example
cd sablepay-react-native-sdk-example
# 2. Update credentials in src/config/environment.js
# 3. Install dependencies
npm install
# 4. Run the app
npx expo start # Start the Expo dev server (scan QR code with Expo Go)
# Or run on a specific platform:
npm run android # expo run:android
npm run ios # expo run:ios
npm run web # expo start --webBuilding the SDK
npm install
npm run build # Build CJS + ESM + type declarations
npm run typecheck # Type checking onlyPublishing to npm
# Build the SDK
npm run build
# Login to npm
npm login
# Publish (scoped package — needs public access)
npm publish --access publicLicense
MIT — see LICENSE
