~10 min read • Step-by-step with screenshots
API Key Format
sable_sk_live_XXXXXXXXXXX...sable_sk_sand_XXXXXXXXXXX...Required Headers
| Header | Value | Description |
|---|---|---|
X-API-Key | Your API key | Starts with sable_sk_live_ or sable_sk_sand_ |
X-Merchant-ID | Your Merchant ID | UUID from your dashboard |
Content-Type | application/json | Required for POST requests |
/api/v1/payments/createRequest Body
| Field | Type | Required | Description |
|---|---|---|---|
amount | number | Required | Payment amount (0.01 - 1,000,000). Interpreted as local currency if merchant region has conversion enabled (e.g., PKR for PAK), otherwise treated as USD. |
items | array | Optional | Array of items (max 100) |
metadata | object | Optional | Custom key-value pairs (orderId, etc.) |
Code Examples
curl -X POST "https://sandbox-api.sablepay.io/api/v1/payments/create" \
-H "Content-Type: application/json" \
-H "X-API-Key: sable_sk_live_YOUR_API_KEY_HERE" \
-H "X-Merchant-ID: YOUR_MERCHANT_ID" \
-d '{
"amount": 25.99,
"metadata": {
"orderId": "ORD-12345"
}
}'Success Response (USD region)
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "PENDING",
"amount": 25.99,
"acceptedTokens": "ALL_STABLECOINS",
"paymentLink": "https://sablepay.io/pay/550e8400...",
"businessName": "SF Cali CaffeCoffe",
"paymentExpirationTime": 10,
"expiresAt": "2026-02-02T12:10:00.000Z",
"createdAt": "2026-02-02T12:00:00.000Z",
"currency_symbol": "$",
"stablecoin_label": "STABLECOIN"
}Success Response (PAK region with conversion)
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "PENDING",
"amount": 5000,
"acceptedTokens": "ALL_STABLECOINS",
"paymentLink": "https://sablepay.io/pay/550e8400...",
"businessName": "Karachi Store",
"paymentExpirationTime": 10,
"expiresAt": "2026-02-02T12:10:00.000Z",
"createdAt": "2026-02-02T12:00:00.000Z",
"currency_symbol": "?",
"stablecoin_label": "USDC",
"converted_currency": "17.99",
"conversion_rate": "278.05",
"conversion_rate_fluctuation": "0.10",
"conversion_currency_symbol": "USD"
}paymentLink URL to redirect customers or generate a QR code. Payments expire in 10 minutes. When the merchant's region has conversion enabled, converted_currency shows the USD equivalent and conversion_rate shows the exchange rate used./api/v1/paymentsComing Soon/api/v1/). To view payment history, use the SablePay Dashboard. This endpoint will be added to the public API in an upcoming release./api/v1/payments/{id}Payment Status Values
Example Request
curl -X GET "https://sandbox-api.sablepay.io/api/v1/payments/PAYMENT_ID" \
-H "X-API-Key: sable_sk_live_YOUR_API_KEY_HERE" \
-H "X-Merchant-ID: YOUR_MERCHANT_ID"Completed Payment Response (USD region)
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"amount": 25.99,
"acceptedTokens": "ALL_STABLECOINS",
"status": "completed",
"terminalId": "t-001",
"terminalName": "Main Counter",
"txHash": "0x1234567890abcdef...",
"paidToken": "USDC",
"paidNetwork": "base",
"paidAmount": "25.99",
"createdAt": "2026-02-02T12:00:00.000Z",
"completedAt": "2026-02-02T12:05:00.000Z",
"expiresAt": "2026-02-02T12:10:00.000Z",
"currency_symbol": "$",
"stablecoin_label": "STABLECOIN"
}Completed Payment Response (PAK region)
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"amount": 5000,
"originalAmount": 5000,
"acceptedTokens": "ALL_STABLECOINS",
"status": "completed",
"terminalId": "t-002",
"terminalName": "Karachi POS",
"txHash": "0xabcdef1234567890...",
"paidToken": "USDC",
"paidNetwork": "polygon",
"paidAmount": "17.99",
"createdAt": "2026-02-02T12:00:00.000Z",
"completedAt": "2026-02-02T12:03:00.000Z",
"expiresAt": "2026-02-02T12:10:00.000Z",
"currency_symbol": "?",
"stablecoin_label": "USDC",
"converted_currency": "17.99",
"conversion_rate": "278.05",
"conversion_rate_fluctuation": "0.10",
"conversion_currency_symbol": "USD"
}Webhook Events
Webhook Payload
All webhook payloads share a common envelope. The data field varies by event type.
// payment.created
{
"id": "evt_a1b2c3d4e5f67890",
"type": "payment.created",
"timestamp": "2026-02-02T12:00:00.000Z",
"data": {
"paymentId": "550e8400-e29b-41d4-a716-446655440000",
"amount": 25.99,
"originalAmount": 25.99,
"originalCurrency": "USD",
"acceptedTokens": ["USDC", "USDT"],
"status": "PENDING",
"paymentLink": "https://sablepay.io/pay/550e8400...",
"expiresAt": "2026-02-02T12:10:00.000Z"
}
}// payment.confirmed
{
"id": "evt_f8e7d6c5b4a39210",
"type": "payment.confirmed",
"timestamp": "2026-02-02T12:05:00.000Z",
"data": {
"paymentId": "550e8400-e29b-41d4-a716-446655440000",
"amount": 25.99,
"originalAmount": 25.99,
"currency": "USDC",
"status": "completed",
"txHash": "0x1234567890abcdef...",
"fromAddress": "0xCustomerWallet...",
"toAddress": "0xMerchantWallet...",
"networkName": "base",
"completedAt": "2026-02-02T12:05:00.000Z"
}
}Verify Webhook Signature
Always verify the webhook signature using the X-SablePay-Signature header. The signature is an HMAC-SHA256 hash of the payload body:
const crypto = require('crypto');
function verifyWebhook(payload, signature, webhookSecret) {
const expectedSignature = crypto
.createHmac('sha256', webhookSecret)
.update(JSON.stringify(payload))
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
// In your webhook handler:
app.post('/webhook', (req, res) => {
const signature = req.headers['x-sablepay-signature'];
if (!verifyWebhook(req.body, signature, process.env.WEBHOOK_SECRET)) {
return res.status(401).json({ error: 'Invalid signature' });
}
const { type, data } = req.body;
if (type === 'payment.confirmed') {
// Update order status, send confirmation email, etc.
console.log('Payment completed:', data.paymentId);
console.log('TX Hash:', data.txHash);
console.log('Network:', data.networkName);
}
res.json({ received: true });
});Webhook Best Practices
200 response quickly (within 5 seconds)Error Response Format
{
"error": "Error message description",
"requestId": "req_1706871234567_abc123"
}Common Error Codes
| Code | Error | Solution |
|---|---|---|
| 400 | Invalid amount | Amount must be between 0.01 and 1,000,000 |
| 401 | Missing API key | Add X-API-Key header |
| 401 | Invalid API credentials | Check API key is active and matches Merchant ID |
| 403 | Insufficient permissions | API key lacks required scope (payments:create) |
| 404 | Payment not found | Check payment ID exists |
| 429 | Rate limit exceeded | Wait 1 minute and retry |
| 500 | Server error | Retry after a few seconds or contact support |
Rate Limits
sable_sk_sand_...) for testing. Never expose production keys in the browser.curl -X POST "https://sandbox-api.sablepay.io/api/v1/payments/create" \
-H "Content-Type: application/json" \
-H "X-API-Key: YOUR_API_KEY" \
-H "X-Merchant-ID: YOUR_MERCHANT_ID" \
-d '{"amount": 10}'Requirements
Installation
Add to your build.gradle.kts:
dependencies {
implementation("io.sablepay:sdk:1.0.5")
}Initialize SDK
import io.sablepay.sdk.SablePay
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
SablePay.initialize(
context = this,
apiKey = "sable_sk_live_YOUR_API_KEY_HERE",
merchantId = "your-merchant-uuid-here",
baseUrl = "https://sandbox-api.sablepay.io/api/v1/",
enableLogging = BuildConfig.DEBUG
)
}
}Collect Payment
Launch a full payment screen with QR code, countdown timer, and auto-polling - all in one line:
import io.sablepay.sdk.SablePay
import io.sablepay.sdk.launchPayment
// Launch payment screen (one line!)
SablePay.launchPayment(this, 10.50) // amountHandle Payment Result
The SDK handles QR display, status polling, and success/failure screens automatically. Handle the result in your Activity:
import io.sablepay.sdk.handlePaymentResult
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
SablePay.handlePaymentResult(requestCode, resultCode, data) { result ->
result.onSuccess { payment ->
// Payment successful!
println("Payment ID: ${payment.paymentId}")
println("TX Hash: ${payment.transactionHash}")
println("Paid: ${payment.formattedPaidAmount}")
}
result.onFailure { error ->
// Payment failed or cancelled
println("Error: ${error.message}")
}
}
}Cleanup
When the merchant logs out or switches accounts:
SablePay.release() // Clears stored credentials@sablepay/react-sablepay-jsRequirements
Installation
npm install @sablepay/react-sablepay-jsQuick Start
1. Initialize the SDK
// app/layout.tsx (Next.js App Router) or _app.tsx (Pages Router)
import { SablePay } from '@sablepay/react-sablepay-js';
SablePay.initialize({
apiKey: process.env.NEXT_PUBLIC_SABLEPAY_API_KEY!,
merchantId: process.env.NEXT_PUBLIC_SABLEPAY_MERCHANT_ID!,
enableLogging: process.env.NODE_ENV === 'development',
});2. Use the PaymentButton (Easiest)
import { PaymentButton } from '@sablepay/react-sablepay-js/react';
export default function CheckoutPage() {
return (
<PaymentButton
amount={10.50}
onSuccess={(status) => {
console.log('Payment complete!', status.txHash);
}}
onError={(err) => {
console.error('Payment failed:', err);
}}
/>
);
}3. Or use the Hook (More Control)
import { usePaymentFlow } from '@sablepay/react-sablepay-js/react';
export default function PaymentPage() {
const { state, startPayment, cancel, qrDataUrl, error } = usePaymentFlow({
onPaymentCompleted(status) {
console.log('Done!', status.txHash);
},
});
return (
<div>
{state.type === 'idle' && (
<button onClick={() => startPayment(10.50)}>Pay $10.50</button>
)}
{state.type === 'creating' && <p>Creating payment...</p>}
{state.type === 'awaiting' && qrDataUrl && (
<div>
<img src={qrDataUrl} alt="Scan to pay" width={300} height={300} />
<p>Scan the QR code with your wallet</p>
</div>
)}
{state.type === 'processing' && <p>Processing payment...</p>}
{state.type === 'completed' && <p>Payment complete!</p>}
{state.type === 'failed' && <p>{error}</p>}
{state.type !== 'idle' && state.type !== 'completed' && (
<button onClick={cancel}>Cancel</button>
)}
</div>
);
}Usage with Context Provider
// app/providers.tsx
'use client';
import { SablePayProvider } from '@sablepay/react-sablepay-js/react';
export function Providers({ children }: { children: React.ReactNode }) {
return (
<SablePayProvider
apiKey={process.env.NEXT_PUBLIC_SABLEPAY_API_KEY!}
merchantId={process.env.NEXT_PUBLIC_SABLEPAY_MERCHANT_ID!}
>
{children}
</SablePayProvider>
);
}
// In any child component
import { useSablePay } from '@sablepay/react-sablepay-js/react';
function MyComponent() {
const sdk = useSablePay();
// sdk.createPayment(), sdk.getPaymentStatus(), etc.
}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.txHash, 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();React Hooks
usePaymentFlow(options?) — Recommended
Complete payment lifecycle management with reactive state.
const {
state, // PaymentFlowState
startPayment, // (amount, metadata?) => Promise<void>
cancel, // () => void
isActive, // boolean
qrDataUrl, // string | null
paymentResponse, // CreatePaymentResponse | null
paymentStatus, // PaymentStatusResponse | null
error, // string | null
} = usePaymentFlow({
onPaymentCreated: (response, qrUrl) => {},
onStatusUpdate: (status) => {},
onPaymentCompleted: (status) => {},
onPaymentFailed: (error) => {},
qrCodeConfig: { width: 400 },
pollOptions: { intervalMs: 3000 },
});usePayment() — Low-level
Direct API access with loading/error state.
const {
createPayment, // (request) => Promise<CreatePaymentResponse>
getPaymentStatus, // (id) => Promise<PaymentStatusResponse>
listPayments, // (limit?, offset?) => Promise<PaymentStatusResponse[]>
loading, // boolean
error, // Error | null
clearError, // () => void
} = usePayment();useSablePay() — SDK Instance
Access the raw SDK instance (requires <SablePayProvider>).
const sdk = useSablePay();React Components
<PaymentButton>
<PaymentButton
amount={10.50}
label="Checkout"
metadata={{ orderId: 'ORD-123' }}
onSuccess={(status) => {}}
onError={(message) => {}}
onCancel={() => {}}
className="my-button"
disabled={false}
/><PaymentQrCode>
<PaymentQrCode
paymentResponse={response}
// Or: paymentLink="https://pay.sablepay.io/..."
config={{ width: 400, height: 400 }}
onGenerated={(dataUrl) => {}}
onError={(error) => {}}
/><PaymentStatus>
<PaymentStatus
paymentId="payment-id"
autoPoll={true}
pollInterval={3000}
onStatusChange={(status) => {}}
onTerminal={(status) => {}}
/>
{/* Or with custom rendering */}
<PaymentStatus paymentId="payment-id">
{(status, loading, error) => (
<div>{status?.status}</div>
)}
</PaymentStatus>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
txHash?: string | null; // Blockchain TX hash
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-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-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-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 Variables
NEXT_PUBLIC_SABLEPAY_API_KEY=sable_sk_sand_...
NEXT_PUBLIC_SABLEPAY_MERCHANT_ID=00000000-0000-0000-0000-000000000000sable_sk_sand_... → auto-routes to sandbox APIsable_sk_live_... → auto-routes to production APIPayment 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 |
Next.js Integration
App Router
// app/layout.tsx
import { SablePay } from '@sablepay/react-sablepay-js';
// Initialize outside component (runs once)
if (!SablePay.isInitialized()) {
SablePay.initialize({
apiKey: process.env.NEXT_PUBLIC_SABLEPAY_API_KEY!,
merchantId: process.env.NEXT_PUBLIC_SABLEPAY_MERCHANT_ID!,
});
}
export default function RootLayout({ children }) {
return <html><body>{children}</body></html>;
}Pages Router
// pages/_app.tsx
import { SablePay } from '@sablepay/react-sablepay-js';
if (!SablePay.isInitialized()) {
SablePay.initialize({
apiKey: process.env.NEXT_PUBLIC_SABLEPAY_API_KEY!,
merchantId: process.env.NEXT_PUBLIC_SABLEPAY_MERCHANT_ID!,
});
}
export default function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />;
}@sablepay/react-native-sablepay-jsRequirements
Installation
npm install @sablepay/react-native-sablepay-jsQuick Start
1. Initialize the SDK
// App.tsx
import { SablePay } from '@sablepay/react-native-sablepay-js';
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 } from 'react-native';
import { SablePay, QrCodeGenerator } from '@sablepay/react-native-sablepay-js';
export default function CheckoutScreen() {
const [qrUrl, setQrUrl] = useState('');
const pay = async () => {
const sdk = SablePay.getInstance();
const response = await sdk.createPayment({ amount: 10.50 });
const qrGen = new QrCodeGenerator();
const dataUrl = await qrGen.generatePaymentQr(response);
setQrUrl(dataUrl || '');
};
return (
<View>
<Button title="Pay $10.50" onPress={pay} />
{qrUrl ? <Image source={{ uri: qrUrl }} style={{ width: 300, height: 300 }} /> : null}
</View>
);
}3. Use usePaymentFlow (Recommended)
import React, { useEffect } from 'react';
import { View, Button, Image, Text } from 'react-native';
import { usePaymentFlow } from '@sablepay/react-native-sablepay-js';
export default function PaymentScreen() {
const { state, qrDataUrl, error, startPayment, cancel, release } = usePaymentFlow();
useEffect(() => {
return () => release();
}, [release]);
return (
<View>
{state.type === 'idle' && <Button title="Pay $10.50" onPress={() => startPayment(10.50)} />}
{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
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 });
const status = await getPaymentStatus(response.paymentId);
console.log('Status:', status.status);
};
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();React Native Hooks
usePaymentFlow(options?) - Recommended
Complete payment lifecycle management with reactive state.
const {
state, // PaymentFlowState
startPayment, // (amount, metadata?, callbacks?, options?) => Promise<void>
cancel, // () => void
release, // () => void
isActive, // boolean
qrDataUrl, // string | null
paymentResponse, // CreatePaymentResponse | null
paymentStatus, // PaymentStatusResponse | null
error, // string | null
} = usePaymentFlow({
onPaymentCreated: (response, qrUrl) => {},
onStatusUpdate: (status) => {},
onPaymentCompleted: (status) => {},
onPaymentFailed: (error) => {},
onStateChange: (state) => {},
});useSablePay() - Core Access
Convenient access to core SDK methods inside components.
const {
sdk, // SablePay instance
createPayment, // (request) => Promise<CreatePaymentResponse>
getPaymentStatus, // (id) => Promise<PaymentStatusResponse>
listPayments, // (limit?, offset?) => Promise<PaymentStatusResponse[]>
getEnvironment, // () => 'sandbox' | 'production' | null
isConfigured, // () => boolean
createPaymentFlow // (options?) => PaymentFlow
} = useSablePay();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/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
// src/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/',
};sable_sk_sand_... ? auto-routes to https://sandbox-api.sablepay.iosable_sk_live_... ? auto-routes to https://api.sablepay.ioPayment 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 |
Expo / App Lifecycle Integration
Initialize Once at App Startup
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 */}</View>;
}@sablepay/angular-sablepay-js v1.3.1Compatibility
2. Initialize once (app startup)
import { SablePay } from '@sablepay/angular-sablepay-js';
SablePay.initialize({
apiKey: 'sable_sk_sand_...',
merchantId: '00000000-0000-0000-0000-000000000000',
enableLogging: false,
});3. Collect Payment (one line)
SablePay.launchPayment() handles QR generation, polling, and result - all in a single call.
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SablePay } from '@sablepay/angular-sablepay-js';
@Component({
selector: 'app-checkout',
standalone: true,
imports: [CommonModule],
template: `
<button (click)="pay()" [disabled]="loading">Pay</button>
<img *ngIf="qrUrl" [src]="qrUrl" alt="Scan to pay" width="300" height="300" />
<p *ngIf="status">{{ status }}</p>
`,
})
export class CheckoutComponent {
loading = false;
qrUrl = '';
status = '';
pay() {
this.loading = true;
// Launch payment - handles QR, polling, and result automatically
SablePay.launchPayment(10.50, {
onPaymentCreated: (response, qrDataUrl) => {
this.qrUrl = qrDataUrl;
},
onSuccess: (status) => {
this.status = 'Payment complete! TX: ' + status.transactionId;
this.loading = false;
},
onFailure: (error) => {
this.status = 'Failed: ' + error.message;
this.loading = false;
},
});
}
}Cancel / Cleanup
SablePay.cancelPayment(); // Cancel active payment
SablePay.release(); // Clear credentials (on logout)Optional: Environment values
export const environment = {
production: false,
sablepayApiKey: 'sable_sk_sand_...',
sablepayMerchantId: '00000000-0000-0000-0000-000000000000',
};sable_sk_sand_... ? auto-routes to sandbox APIsable_sk_live_... ? auto-routes to production APIAPI Reference
| Method | Description |
|---|---|
SablePay.initialize(config) | Set API key, merchant ID, and options. Call once at startup. |
SablePay.launchPayment(amount, callbacks) | Create payment, generate QR, poll status, and fire callbacks. |
SablePay.cancelPayment() | Cancel the currently active payment. |
SablePay.release() | Clear stored credentials (call on logout). |
Callbacks
SablePay.launchPayment(amount, {
onPaymentCreated: (response, qrDataUrl) => { }, // Payment created, QR ready
onSuccess: (status) => { }, // Payment completed
onFailure: (error) => { }, // Payment failed or error
});Requirements
Quick Start
1. Initialize the SDK
import 'package:sablepay_flutter/sablepay_flutter.dart';
Future<void> initSablePay() async {
await SablePay.initialize(
apiKey: const String.fromEnvironment('SABLEPAY_API_KEY'),
merchantId: const String.fromEnvironment('SABLEPAY_MERCHANT_ID'),
enableLogging: true,
);
}2. Create a Payment
final sdk = SablePay.instance;
final payment = await sdk.createPayment(
amount: 10.50,
metadata: {'orderId': 'ORD-12345'},
);
print(payment.paymentId);
print(payment.paymentLink);3. Render QR + Poll Status
final qrGenerator = QrCodeGenerator(width: 320, height: 320);
final qrDataUrl = await qrGenerator.generatePaymentQr(payment);
final poller = PaymentPoller((id) => SablePay.instance.getPaymentStatus(id));
final status = await poller.pollUntilTerminal(payment.paymentId);
if (status.status == PaymentState.completed) {
print('Paid on: ${status.paidNetwork}');
} else {
print('Payment ended with ${status.status}');
}Environment Setup
# .env (or --dart-define values)
SABLEPAY_API_KEY=sable_sk_sand_...
SABLEPAY_MERCHANT_ID=00000000-0000-0000-0000-000000000000sable_sk_sand_... route to sandbox API automatically.sable_sk_live_... route to production API automatically.Android & Web Example App
Use the official Flutter example app for Android and Web integration patterns:
# Web setup from the example repo
cp .env.example .env
# Keep this for Web runs
SABLEPAY_BASE_URL=http://localhost:8787/api/v1/
# Terminal 1: start proxy
cd proxy
cp .env.example .env
# Add your real SablePay API key + Merchant ID in proxy/.env
npm install
npm start
# Terminal 2: run Flutter Web
flutter pub get
flutter run -d chrome --web-port 54410
# Keep WEB_ORIGIN in proxy/.env aligned with the Flutter web port
WEB_ORIGIN=http://localhost:54410
# For Android/mobile sandbox direct API usage
# SABLEPAY_BASE_URL=https://sandbox-api.sablepay.io/api/v1/Android SDK
AvailableNative Android SDK with Kotlin support. Includes complete POS integration example.
- Android Kotlin example
- QR Code generation
- Payment status polling
React SDK
AvailableOfficial JavaScript/TypeScript SDK for React and Next.js. Pre-built components, hooks, and full payment flow management.
- React hooks & components
- QR code generation (PNG, SVG)
- Automatic status polling
- Next.js App Router & Pages Router
React Native SDK
AvailableOfficial TypeScript SDK for React Native and Expo. Includes hooks, QR generation, and full payment lifecycle management.
- React Native hooks
- QR code generation (PNG, SVG)
- Automatic status polling
- Expo-compatible initialization
Angular SDK
AvailableOfficial TypeScript SDK for Angular. Services, payment flow management, QR codes, and automatic polling.
- Angular 14+ (standalone & NgModule)
- PaymentFlowService & SablePayService
- QR code generation (PNG, SVG)
- Automatic status polling
- Full TypeScript support
iOS SDK
Native Swift SDK for iOS applications
Coming SoonNever expose API keys in client-side code
Always call the SablePay API from your server, not from browser JavaScript.
Store keys in environment variables
Use .env files or secret managers. Never commit keys to git.
Use sandbox keys for testing
Keys starting with sable_sk_sand_ are for development only.
Rotate keys regularly
API keys expire after 90 days. Rotate at 75 days to avoid disruption.
Android SDK v1.0.5
- Updated Android SDK to version 1.0.5 (
io.sablepay:sdk:1.0.5) - Bug fixes and stability improvements for POS terminals
Flutter SDK Docs Update
- Added dedicated Flutter SDK docs section with install, initialization, and payment flow examples
- Added Flutter-specific QR and polling examples for mobile checkout screens
- Updated SDK navigation and search metadata to surface Flutter docs directly
- Linked official Flutter package and example app: pub.dev/package and Android/Web reference implementation
Angular SDK Release
- Angular SDK (
@sablepay/angular-sablepay-js) — Angular 14+ support - PaymentFlowService & SablePayService for Angular
- QR code generation, automatic polling, retry logic
- Coffee Shop POS example application
Initial Release
- Payment API with QR code generation
- Multi-network support (Ethereum, Polygon, Base, Arbitrum, Optimism)
- USDC, USDT, and DAI stablecoin support
- Webhook notifications for payment events
- Android SDK (Maven Central)
- Merchant dashboard with analytics
Quick Reference
Current API URL
https://sandbox-api.sablepay.io/api/v1Environment
SandboxCreate Payment
POST /payments/createGet Status
GET /payments/{id}Payment Expiry
10 minutesAPI Key Prefix
sable_sk_live_ | sable_sk_sand_Ready to Accept Stablecoin Payments?
Create your account and start accepting crypto in minutes.
