SettlraSettlra/Docs
DashboardAPI Playground

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'