Node.js SDK
The official Settlra Node.js SDK provides a typed, idiomatic TypeScript client for the Settlra API. It handles authentication, request serialization, error mapping, and retries.
Installation
bash
"color:#ff7b72">npm install @settlra/"color:#ff7b72">node "color:#8b949e"># or yarn add @settlra/"color:#ff7b72">node "color:#8b949e"># or pnpm add @settlra/"color:#ff7b72">node
Setup
settlra.tstypescript
"color:#ff7b72">import { SettlraClient } "color:#ff7b72">from '@settlra/node'; "color:#ff7b72">const client = "color:#ff7b72">new SettlraClient({ apiKey: process.env.SETTLRA_API_KEY!, "color:#8b949e">// Optional: override base URL "color:#ff7b72">for sandbox baseUrl: 'https://api-sandbox.settlra.com/v1', });
Quotes
Create a quote
typescript
"color:#ff7b72">const quote = "color:#ff7b72">await client.quotes.create({ sourceAmountUsdc: 500, targetCurrency: 'UGX', idempotencyKey: 'quote-' + Date.now(), }); console.log(quote.quoteId); "color:#8b949e">// "q_01j3ab4cd..." console.log(quote.targetAmount); "color:#8b949e">// 1871250 (UGX) console.log(quote.exchangeRate); "color:#8b949e">// 3742.5 console.log(quote.expiresAt); "color:#8b949e">// Date object
Get a quote
typescript
"color:#ff7b72">const quote = "color:#ff7b72">await client.quotes.get('q_01j3ab4cd5ef6gh7ij8kl9mn0p'); "color:#ff7b72">if (quote.status === 'EXPIRED') { "color:#8b949e">// Create a "color:#ff7b72">new quote }
Payouts
Create a payout
typescript
"color:#ff7b72">const payout = "color:#ff7b72">await client.payouts.create({ quoteId: quote.quoteId, recipientPhone: '+256700123456', recipientName: 'Jane Nakato', network: 'MTN_UG', idempotencyKey: 'payout-' + Date.now(), }); console.log(payout.payoutId); "color:#8b949e">// "pyt_01j3pq8rs..." console.log(payout.depositAddress); "color:#8b949e">// "0xABCD1234..." console.log(payout.status); "color:#8b949e">// "AWAITING_FUNDS" console.log(payout.message); "color:#8b949e">// "Send exactly 500.000000 USDC to..."
Get payout status
typescript
"color:#ff7b72">const payout = "color:#ff7b72">await client.payouts.get('pyt_01j3pq8rs9tu0vw1xy2za3bc4d'); console.log(payout.status); "color:#8b949e">// "SETTLED" console.log(payout.settledAt); "color:#8b949e">// Date object
List payouts
typescript
"color:#ff7b72">const { data, meta } = "color:#ff7b72">await client.payouts.list({ status: 'SETTLED', limit: 20, offset: 0, }); "color:#ff7b72">for ("color:#ff7b72">const payout of data) { console.log(payout.payoutId, payout.status); }
Create a bulk payout batch
typescript
"color:#8b949e">// First, create a quote "color:#ff7b72">for each payout "color:#ff7b72">const quotes = "color:#ff7b72">await Promise.all( recipients.map((r, i) => client.quotes.create({ sourceAmountUsdc: r.amountUsdc, targetCurrency: r.currency, idempotencyKey: `batch-quotes-${batchId}-${i}`, }) ) ); "color:#8b949e">// Submit the batch "color:#ff7b72">const batch = "color:#ff7b72">await client.payouts.createBulk({ payouts: recipients.map((r, i) => ({ quoteId: quotes[i].quoteId, recipientPhone: r.phone, recipientName: r.name, network: r.network, idempotencyKey: `batch-${batchId}-${i}`, })), }); console.log(batch.batchId); "color:#8b949e">// "batch_01j3rs4tu..." console.log(batch.totalCount); "color:#8b949e">// 50
Poll batch status
typescript
"color:#8b949e">// Poll until complete "color:#ff7b72">async "color:#ff7b72">function waitForBatch(batchId: string) { "color:#ff7b72">while ("color:#79c0ff">true) { "color:#ff7b72">const batch = "color:#ff7b72">await client.payouts.getBatch(batchId); "color:#ff7b72">if (batch.completed + batch.failed === batch.total) { console.log(`Batch complete: ${batch.completed} succeeded, ${batch.failed} failed`); "color:#ff7b72">return batch; } "color:#ff7b72">await "color:#ff7b72">new Promise(r => setTimeout(r, 5000)); } }
Webhook endpoint management
typescript
"color:#8b949e">// Register a webhook endpoint "color:#ff7b72">const endpoint = "color:#ff7b72">await client.webhooks.createEndpoint({ url: 'https://yourapp.com/webhooks/settlra', events: ['payout.settled', 'payout.failed'], description: 'Payout notifications', }); console.log(endpoint.secret); "color:#8b949e">// Store this securely! "color:#8b949e">// List endpoints "color:#ff7b72">const endpoints = "color:#ff7b72">await client.webhooks.listEndpoints(); "color:#8b949e">// Delete an endpoint "color:#ff7b72">await client.webhooks.deleteEndpoint(endpoint.id);
Webhook signature verification
typescript
"color:#ff7b72">import { verifyWebhookSignature } "color:#ff7b72">from '@settlra/node'; "color:#8b949e">// In your webhook handler (Express, Fastify, etc.) app.post('/webhooks/settlra', express.raw({ "color:#ff7b72">type: 'application/json' }), (req, res) => { "color:#ff7b72">const event = verifyWebhookSignature({ payload: req.body, "color:#8b949e">// raw Buffer signature: req.headers['x-settlra-signature'] as string, secret: process.env.SETTLRA_WEBHOOK_SECRET!, }); "color:#8b949e">// event is typed — event."color:#ff7b72">type narrows the data shape "color:#ff7b72">if (event."color:#ff7b72">type === 'payout.settled') { console.log('Settled:', event.data.payoutId); } res.json({ received: "color:#79c0ff">true }); });
Error handling
typescript
"color:#ff7b72">import { SettlraError, SettlraApiError } "color:#ff7b72">from '@settlra/node'; "color:#ff7b72">try { "color:#ff7b72">const payout = "color:#ff7b72">await client.payouts.create({ ... }); } "color:#ff7b72">catch (err) { "color:#ff7b72">if (err "color:#ff7b72">instanceof SettlraApiError) { "color:#8b949e">// Structured API error console.error(err.code); "color:#8b949e">// e.g. "QUOTE_EXPIRED" console.error(err.message); "color:#8b949e">// Human-readable message console.error(err.status); "color:#8b949e">// HTTP status code (400, 409, etc.) "color:#ff7b72">if (err.code === 'QUOTE_EXPIRED') { "color:#8b949e">// Create a "color:#ff7b72">new quote and retry } } "color:#ff7b72">else { "color:#8b949e">// Network error, timeout, etc. "color:#ff7b72">throw err; } }
TypeScript types
typescript
"color:#ff7b72">import "color:#ff7b72">type { Quote, Payout, PayoutBatch, WebhookEndpoint, WebhookEvent, MobileMoneyNetwork, FiatCurrency, PayoutStatus, } "color:#ff7b72">from '@settlra/node'; "color:#8b949e">// MobileMoneyNetwork: 'MTN_UG' | 'AIRTEL_UG' | 'MPESA_KE' | 'MTN_RW' | 'AIRTEL_TZ' "color:#8b949e">// FiatCurrency: 'UGX' | 'KES' | 'NGN' | 'GHS' | 'TZS' | 'ZMW'