swiftshopr-payments
v1.2.2
Published
SwiftShopr white-label USDC payments SDK for React Native - Scan & Go checkout with SMS auth
Maintainers
Readme
swiftshopr-payments
Official Node.js SDK for SwiftShopr Payments API. Accept USDC payments with zero chargebacks, instant settlement, and lower fees than card networks.
Features
- Zero Dependencies - Uses native
fetch(Node.js 18+) - TypeScript Support - Full type definitions included
- Automatic Retries - Exponential backoff for failed requests
- Idempotency - Safe retries for payment operations
- Webhook Verification - HMAC signature validation
Installation
npm install swiftshopr-paymentsQuick Start
const { SwiftShoprClient } = require('swiftshopr-payments');
const client = new SwiftShoprClient({
apiKey: 'sk_live_your_api_key',
});
// Create an onramp session (Add Funds)
const session = await client.payments.createSession({
amount: 25.00,
orderId: 'ORDER-123',
storeId: 'STORE001',
});
console.log('Redirect user to:', session.onrampUrl);Payment Flows
Two-Button Pattern
SwiftShopr supports two payment methods:
| Button | Method | When to Use | Fees |
|--------|--------|-------------|------|
| Add Funds | createSession() | User has no USDC | ~$0.30 |
| Purchase | createTransfer() | User has USDC balance | $0 |
// Check user's USDC balance first
const balance = await getUserBalance(); // Your wallet SDK
if (balance >= purchaseAmount) {
// Direct transfer - no fees!
const transfer = await client.payments.createTransfer({
amount: 25.00,
userWalletAddress: '0xUserWallet...',
storeId: 'STORE001',
});
} else {
// Onramp - small fee for ACH conversion
const session = await client.payments.createSession({
amount: 25.00,
storeId: 'STORE001',
});
}API Reference
Payments
Create Onramp Session
const session = await client.payments.createSession({
amount: 25.00, // Required: Amount in USD
orderId: 'ORDER-123', // Optional: Your order reference
storeId: 'STORE001', // Optional: Store ID (resolves wallet)
destinationAddress: '0x...', // Optional: Explicit wallet address
paymentMethod: 'ACH_BANK_ACCOUNT', // Optional: ACH_BANK_ACCOUNT, CARD
});
// Response
{
intentId: 'uuid',
sessionId: 'sess_xxx',
orderId: 'ORDER-123',
onrampUrl: 'https://pay.coinbase.com/...',
expiresAt: '2024-12-23T10:30:00Z',
branding: { ... }
}Create Direct Transfer
const transfer = await client.payments.createTransfer({
amount: 25.00,
userWalletAddress: '0xUserWallet...',
storeId: 'STORE001',
});
// Response includes transfer instructions
{
intentId: 'uuid',
transfer: {
to: '0xRetailerWallet...',
amount: '25.00',
asset: 'USDC',
network: 'base',
chainId: 8453,
}
}Get Payment Status
// By intent ID
const status = await client.payments.getStatus('intent-uuid');
// By your order ID
const status = await client.payments.getStatusByOrderId('ORDER-123');
// Poll until complete
const finalStatus = await client.payments.waitForCompletion('intent-uuid', {
timeout: 300000, // 5 minutes
interval: 2000, // Check every 2 seconds
onStatusChange: (status) => console.log('Status:', status.status),
});Refunds
Request a Refund
const refund = await client.refunds.create({
intentId: 'original-payment-intent-uuid',
amount: 25.00, // Optional: Defaults to full refund
reason: 'Customer request',
});
// Response includes transfer instructions
{
id: 'refund-uuid',
status: 'requested',
instructions: {
message: 'Send USDC to complete the refund...',
transfer: {
to: '0xUserWallet...',
amount: '25.00',
asset: 'USDC',
},
fromWallet: '0xYourStoreWallet...',
}
}Check Refund Status
const refund = await client.refunds.get('refund-uuid');
// List all refunds for a payment
const refunds = await client.refunds.listForPayment('intent-uuid');
// Wait for completion
const completedRefund = await client.refunds.waitForCompletion('refund-uuid');Dashboard
// Summary metrics
const summary = await client.dashboard.getSummary();
// Transaction list with filters
const { transactions, pagination } = await client.dashboard.getTransactions({
status: 'completed',
storeId: 'STORE001',
startDate: '2024-01-01',
endDate: '2024-12-31',
limit: 50,
});
// Store breakdown
const stores = await client.dashboard.getStores();
// Daily data for charts
const daily = await client.dashboard.getDaily({ days: 30 });
// Export CSV
const csv = await client.dashboard.export({
startDate: '2024-01-01',
endDate: '2024-12-31',
});Branding
// Get branding for white-label UI
const branding = await client.branding.get('STORE001');
// Generate CSS variables
const css = client.branding.toCssVariables(branding);
// --swiftshopr-primary: #E31837;
// --swiftshopr-background: #FFFFFF;
// Get CDP/OnchainKit theme tokens
const cdpTheme = client.branding.toCdpTheme(branding);Webhooks
Verify Webhook Signatures
const { SwiftShoprClient, webhookMiddleware } = require('swiftshopr-payments');
// Option 1: Express middleware
app.post('/webhooks/swiftshopr',
express.raw({ type: 'application/json' }),
webhookMiddleware('whsec_your_secret'),
(req, res) => {
const event = req.webhookEvent;
switch (event.type) {
case 'payment.completed':
console.log('Payment completed:', event.data.orderId);
break;
case 'refund.completed':
console.log('Refund completed:', event.data.refundId);
break;
}
res.json({ received: true });
}
);
// Option 2: Manual verification
const client = new SwiftShoprClient({
apiKey: 'sk_live_...',
webhookSecret: 'whsec_your_secret',
});
const event = client.webhooks.constructEvent(
req.body, // Raw body
req.headers // { 'x-webhook-signature': '...', 'x-webhook-timestamp': '...' }
);Webhook Events
| Event | Description |
|-------|-------------|
| payment.completed | Payment confirmed on-chain |
| payment.failed | Payment failed |
| payment.expired | Payment intent expired |
| refund.requested | Refund initiated |
| refund.completed | Refund confirmed on-chain |
| refund.failed | Refund failed |
Error Handling
const { SwiftShoprError, HttpError, TimeoutError } = require('swiftshopr-payments');
try {
await client.payments.createSession({ amount: 25.00 });
} catch (error) {
if (error instanceof SwiftShoprError) {
// Validation or business logic error
console.log('Code:', error.code);
console.log('Message:', error.message);
console.log('Details:', error.details);
} else if (error instanceof HttpError) {
// HTTP error from API
console.log('Status:', error.statusCode);
console.log('Response:', error.response);
} else if (error instanceof TimeoutError) {
// Request timed out
console.log('Timeout after:', error.timeout, 'ms');
}
}Configuration
const client = new SwiftShoprClient({
apiKey: 'sk_live_...', // Required
webhookSecret: 'whsec_...', // Optional: For webhook verification
baseUrl: 'https://...', // Optional: Custom API URL
timeout: 30000, // Optional: Request timeout (ms)
retries: 3, // Optional: Retry attempts
// Hooks for logging/monitoring
onRequest: ({ method, url }) => {
console.log(`[API] ${method} ${url}`);
},
onResponse: ({ status, data }) => {
console.log(`[API] Response: ${status}`);
},
onError: (error) => {
console.error('[API] Error:', error.message);
},
});TypeScript
Full TypeScript support with type definitions:
import { SwiftShoprClient, PaymentStatus, RefundResult } from 'swiftshopr-payments';
const client = new SwiftShoprClient({ apiKey: 'sk_live_...' });
const status: PaymentStatus = await client.payments.getStatus('uuid');
const refund: RefundResult = await client.refunds.create({ intentId: 'uuid' });Requirements
- Node.js 18+ (uses native
fetch) - SwiftShopr API key
Support
- Documentation: https://docs.swiftshopr.com
- Issues: https://github.com/swiftshopr/payments-sdk/issues
- Email: [email protected]
License
MIT
