npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@sodasoft/meshtally

v2.7.10

Published

Meshtally Node.js SDK — Smart Payment Routing, Orchestration & Pricing Intelligence

Readme

@sodasoft/meshtally

Official Node.js SDK for the Meshtally Smart Payment Routing & Orchestration API.

Zero dependencies. Full TypeScript support. 77 tests. Node.js 18+ (uses native fetch).

npm version

Features

  • Zero runtime dependencies — no supply chain risk
  • Full TypeScript — strict types, exported interfaces, JSDoc on every method
  • Automatic retries — exponential backoff with jitter, respects Retry-After
  • Idempotency — UUID v4 keys auto-generated for POST/PATCH
  • Webhook verification — HMAC-SHA256 with timing-safe comparison and 5-min replay protection
  • Async paginationpaginate() generator for automatic page traversal
  • Debug safe — sensitive fields (IBAN, email, wallet) redacted from debug logs
  • 77 tests — unit, validation, integration (mock HTTP server), webhook verification

Install

npm install @sodasoft/meshtally

Quick Start

import { Meshtally } from '@sodasoft/meshtally';

const meshtally = new Meshtally({
  apiKey: process.env.MESHTALLY_API_KEY!,
  environment: 'sandbox',
});

const session = await meshtally.checkoutSessions.create({
  amount: 99.99,
  currency: 'EUR',
  customer_email: '[email protected]',
  success_url: 'https://yoursite.com/success',
  cancel_url: 'https://yoursite.com/cancel',
});

// Redirect customer to hosted checkout
res.redirect(session.checkout_url);

ML-Powered Routing Context

Pass transaction context to enable intelligent PSP routing. The more context you provide, the better the ML model optimizes approval rates:

const session = await meshtally.checkoutSessions.create({
  amount: 499.99,
  currency: 'EUR',

  // Routing context — improves ML predictions
  customer_country: 'DE',
  card_bin: '411111',             // First 6 digits (Visa/MC/Amex detection)
  channel: 'web',                 // 'web' | 'mobile' | 'api' | 'in_store'
  risk_level: 'low',              // 'low' | 'medium' | 'high'
  device_type: 'desktop',         // 'desktop' | 'mobile' | 'tablet'
  payment_type: 'subscription',   // 'one_time' | 'subscription' | 'recurring' | 'deposit' | 'withdrawal'

  // Product context — for analytics & routing
  product_category: 'trading_deposit',
  product_name: 'Pro Plan',
  price_tier: 'high',             // 'micro' | 'low' | 'medium' | 'high' | 'premium'
  subscription_interval: 'monthly',

  // Customer context
  customer_email: '[email protected]',
  is_returning_customer: true,
  customer_lifetime_payments: 12,
  billing_address: { country: 'DE', postal_code: '10115' },

  // URLs
  success_url: 'https://yoursite.com/success',
  cancel_url: 'https://yoursite.com/cancel',
  metadata: { order_id: 'ORD-123' },
});

Multi-Item Checkout (Line Items)

For orders with multiple products (e-commerce, airline tickets, etc.):

const session = await meshtally.checkoutSessions.create({
  currency: 'EUR',
  line_items: [
    { name: 'Flight BEG-LHR', quantity: 1, unit_price: 289.00, currency: 'EUR' },
    { name: 'Extra Baggage 23kg', quantity: 2, unit_price: 35.00, currency: 'EUR' },
    { name: 'Seat Selection 14A', quantity: 1, unit_price: 12.00, currency: 'EUR' },
  ],
  customer_country: 'RS',
  payment_type: 'one_time',
  product_category: 'airline_ticket',
  success_url: 'https://airline.com/booking/success',
});
// Total: €371.00 (auto-calculated from line items)

Configuration

const meshtally = new Meshtally({
  apiKey: process.env.MESHTALLY_API_KEY!,
  environment: 'sandbox',  // 'sandbox' | 'production'
  timeout: 30000,           // request timeout in ms (default: 30000)
  maxRetries: 3,            // retry count for 429/5xx (default: 3)
  debug: false,             // enable request/response logging (default: false)
});

Resources

Checkout Sessions

// Create
const session = await meshtally.checkoutSessions.create({ amount: 99.99, currency: 'EUR' });

// Retrieve
const detail = await meshtally.checkoutSessions.retrieve('cs_abc123');

// List
const { sessions, total } = await meshtally.checkoutSessions.list({ status: 'completed', limit: 20 });

// Expire
await meshtally.checkoutSessions.expire('cs_abc123');

Transactions

// Retrieve
const txn = await meshtally.transactions.retrieve('txn_abc123');

// List with filters
const { transactions, total } = await meshtally.transactions.list({
  status: 'captured',
  currency: 'EUR',
  limit: 50,
});

// Update metadata
await meshtally.transactions.update('txn_abc123', {
  metadata: { order_id: 'order_456' },
});

Refunds

// Create (full or partial)
const refund = await meshtally.refunds.create({
  transaction_id: 'txn_abc123',
  amount: 25.00,
  reason: 'Customer request',
});

// List refunds for a transaction
const { refunds } = await meshtally.refunds.list({ transaction_id: 'txn_abc123' });

Payouts

// Create payout to beneficiary
const payout = await meshtally.payouts.create({
  beneficiary_id: 'ben_abc123',
  amount: 500.00,
  currency: 'EUR',
});

// List payouts
const { payouts } = await meshtally.payouts.list({ status: 'completed' });

// Approve / Cancel
await meshtally.payouts.approve('po_abc123');
await meshtally.payouts.cancel('po_abc123');

// Batch payouts
await meshtally.payouts.createBatch({
  instructions: [
    { beneficiary_id: 'ben_1', amount: 100, currency: 'EUR' },
    { beneficiary_id: 'ben_2', amount: 200, currency: 'EUR' },
  ],
});

Beneficiaries

// Create
const beneficiary = await meshtally.beneficiaries.create({
  first_name: 'John',
  last_name: 'Doe',
  type: 'trader',
  email: '[email protected]',
});

// Retrieve
const ben = await meshtally.beneficiaries.retrieve('ben_abc123');

// Update
await meshtally.beneficiaries.update('ben_abc123', { email: '[email protected]' });

// List
const { beneficiaries, total } = await meshtally.beneficiaries.list({ limit: 50 });

// Delete (soft-delete — sets status to blocked)
await meshtally.beneficiaries.delete('ben_abc123');

// ─── Payout methods ─────────────────────────────────────────

// Add a bank account
await meshtally.beneficiaries.addPayoutMethod('ben_abc123', {
  method_type: 'bank',
  currency: 'EUR',
  iban: 'DE89370400440532013000',
  swift_bic: 'COBADEFFXXX',
  bank_name: 'Commerzbank',
  bank_country: 'DE',
});

// Add a crypto wallet
await meshtally.beneficiaries.addPayoutMethod('ben_abc123', {
  method_type: 'crypto',
  currency: 'USDT',
  crypto_network: 'tron',
  wallet_address: 'TEbatdMV3...',
});

// List payout methods for a beneficiary
const { payout_methods } = await meshtally.beneficiaries.listPayoutMethods({
  beneficiary_id: 'ben_abc123',
});

// Update label or set as default
await meshtally.beneficiaries.updatePayoutMethod('pm_xyz789', {
  label: 'Primary EUR account',
  is_default: true,
});

// Delete (soft-delete — sets status to inactive)
await meshtally.beneficiaries.deletePayoutMethod('pm_xyz789');

Settlement

// Get all balances
const balances = await meshtally.settlement.getBalances();

// Get balance for specific currency
const eurBalance = await meshtally.settlement.getBalance('EUR');

// Get settlement ledger
const ledger = await meshtally.settlement.getLedger({ currency: 'EUR', limit: 100 });

Account

const account = await meshtally.account.retrieve();
console.log(account.name, account.status);

Fees — contracted fee profiles (Pricing Intelligence)

Manage the contracted fees you pay each PSP. Profiles go through a dual-control approval workflow — the submitter cannot also be the approver. Only approved profiles are evaluated when routing or when calling calculate().

// Create a draft fee profile
const draft = await meshtally.fees.create({
  psp_connector_id: pspId,
  fee_model: 'interchange_plus',
  payment_method: 'card',
  card_scheme: 'visa',
  merchant_country: 'AE',
  fixed_fee: 0.15,           // currency units, e.g. 0.15 EUR
  percentage_fee: 0.025,     // 2.5%
  interchange_fee_percentage: 0.003,
  three_ds_fee: 0.02,
  cross_border_fee: 0.10,
});

// Submit for Finance approval
await meshtally.fees.submit(draft.id);

// Finance approves (must be a different user)
await meshtally.fees.approve(draft.id, 'Matches signed schedule v3');

// Estimate the fee for a given transaction context
const estimate = await meshtally.fees.calculate({
  psp_connector_id: pspId,
  amount: 250,
  currency: 'EUR',
  merchant_country: 'AE',
  issuer_country: 'DE',
  payment_method: 'card',
  card_scheme: 'visa',
  requires_3ds: true,
});
// estimate.estimated_total, estimate.breakdown.{fixed, percent, scheme, ...}
// estimate.confidence_hint: 'low' | 'medium' | 'high'

Observed Fees — settlement-report import

Observed fees are the effective cost recorded on each transaction by the PSP — the source of truth for cost_variance analytics. Import via CSV with a saved column mapping, or map ad-hoc.

const preview = await meshtally.observedFees.previewImport({
  tenant_id,
  psp_connector_id: pspId,
  csv_base64,                           // base64-encoded CSV contents
  filename: 'adyen-2026-04.csv',
  mapping: {
    transaction_ref: 'PSP Reference',
    fee_total: 'Total Fee',
    settlement_currency: 'Settlement Currency',
    reported_at: 'Report Date',
  },
});
// preview.matched_count, preview.unmatched_count, preview.preview_unmatched_sample[]

// Commit after review
const result = await meshtally.observedFees.commitImport({ /* same params */ });
// result.inserted — count of psp_observed_fees rows; backfills observed_cost on attempts

Pricing Intelligence health

const health = await meshtally.pricingHealth.get();
// health.ml_retrain.healthy, health.insights_engine.healthy,
// health.fx_rates.healthy, health.psp_fee_sync.healthy

// Deeper diagnostics if a pipe is unhealthy
const cron = await meshtally.pricingHealth.cronStatus();
// cron.pg_cron_enabled, cron.pg_net_enabled
// cron.jobs[i].jobname / schedule / last_run_at / last_status / last_return_message

Pricing insights

Automatically surfaced findings from the Pricing Intelligence feedback loop — variance alerts, savings opportunities, activation suggestions, and stale-profile warnings. Recomputed every 2 hours on a schedule; ad-hoc via recompute().

const open = await meshtally.pricingInsights.list();
for (const i of open) {
  console.log(`[${i.severity}] ${i.title}`);
  console.log(i.body);
  // i.kind: 'variance_alert' | 'savings_opportunity' | 'activation_suggestion' | 'profile_stale'
  // i.cta_target: 'fees' | 'observed-fees' | 'cost-readiness' (where to deep-link)
}

// Clear once handled
await meshtally.pricingInsights.markActioned(open[0].id);

PSP fee sync

Configure how observed fee data flows into Meshtally per PSP. Four channels are available; webhook and CSV work for any PSP, API pull needs a PSP-specific adapter (currently Stripe + Adyen).

// Enable automatic API pull for Stripe every hour
await meshtally.pspFeeSync.upsert({
  psp_connector_id: stripeConnectorId,
  sync_method: 'api_pull',
  sync_enabled: true,
  pull_frequency: 'hourly',
  pull_lookback_days: 3,
});

// Inspect current config for every PSP
const configs = await meshtally.pspFeeSync.list();

// Trigger a pull right now (no need to wait for the cron)
const result = await meshtally.pspFeeSync.pullNow(stripeConnectorId);
// result.results[0].fees = number of new observed fees ingested

BIN lookup

const info = await meshtally.bin.resolve('411111');
// { card_scheme: 'visa', issuer_country: 'US', card_type: 'credit', confidence: 'medium', matched: true }

The smart routing optimizer auto-enriches the transaction context when only card_bin is provided — you do not need to call this explicitly before routing.

Cost Readiness — per-bucket gate management

Cost-aware routing is never automatic. An admin must enable a cost routing gate per bucket (country × currency × brand × amount-bucket × PSP) after confidence reaches high. The server rejects enabling a gate on a below-threshold bucket.

const matrix = await meshtally.costReadiness.matrix();
// matrix[i].cost_confidence_level: 'low' | 'medium' | 'high'

// Only 'high' buckets can be enabled
await meshtally.costReadiness.setGate({
  psp_connector_id: pspId,
  bucket_key: matrix[0].bucket_key,
  enabled: true,
  reason: 'Two weeks of fresh observed fees, variance within ±2%.',
});

// Force a recomputation (otherwise refreshes every 30 minutes)
await meshtally.costReadiness.refresh();

Webhook Verification

Verify incoming webhook signatures (HMAC-SHA256):

import { WebhooksResource } from '@sodasoft/meshtally';

app.post('/webhooks/meshtally', express.raw({ type: 'application/json' }), (req, res) => {
  try {
    const event = WebhooksResource.constructEvent(
      req.body,
      req.headers['x-meshtally-signature'] as string,
      process.env.MESHTALLY_WEBHOOK_SECRET!,
    );

    switch (event.payload.event_type) {
      case 'payment.succeeded':
        console.log('Payment captured:', event.payload.data.transaction);
        break;
      case 'payment.failed':
        console.log('Payment failed:', event.payload.data.transaction);
        break;
      case 'refund.processed':
        console.log('Refund completed');
        break;
      case 'payout.completed':
        console.log('Payout sent:', event.payload.data.payout);
        break;
    }

    res.json({ received: true });
  } catch (err) {
    res.status(400).send('Invalid signature');
  }
});

Error Handling

import { MeshtallyError, AuthenticationError, InvalidRequestError, RateLimitError, NetworkError } from '@sodasoft/meshtally';

try {
  await meshtally.checkoutSessions.create({ amount: 100, currency: 'EUR' });
} catch (err) {
  if (err instanceof AuthenticationError) {
    // Invalid or expired API key (401/403)
  } else if (err instanceof InvalidRequestError) {
    // Bad parameters — check err.message for details (400/422)
  } else if (err instanceof RateLimitError) {
    // Too many requests — SDK retries automatically with backoff
  } else if (err instanceof NetworkError) {
    // DNS failure, timeout, connection reset
  }
  // All errors have: err.message, err.status, err.code, err.requestId
}

Error Properties

| Property | Type | Description | |----------|------|-------------| | message | string | Human-readable error message | | status | number | HTTP status code | | code | string | Machine-readable error code | | requestId | string | Server request ID for support |

Pagination

// Manual pagination
const page1 = await meshtally.transactions.list({ limit: 50, offset: 0 });
const page2 = await meshtally.transactions.list({ limit: 50, offset: 50 });

// Auto-pagination (async generator)
for await (const txn of meshtally.paginate(meshtally.transactions, 'list', { status: 'captured' })) {
  console.log(txn.id, txn.amount);
}

Environment

  • Runtime: Node.js 18+ only (uses native fetch and node:crypto)
  • Not compatible with browsers — use the hosted checkout redirect flow for browser-based integrations
  • TypeScript: Full type definitions included, strict mode compatible
  • Dependencies: Zero runtime dependencies

Retry Behavior

Automatic retries with exponential backoff:

  • Retried: 429 (rate limited), 5xx (server errors), network errors, timeouts
  • Not retried: 400, 401, 403, 404, 422 (client errors)
  • Backoff: 500ms → 1s → 2s (with 0-25% jitter)
  • Max retries: 3 (configurable)

Idempotency

All write operations automatically include an Idempotency-Key header (UUID v4). You can also provide your own:

const session = await meshtally.checkoutSessions.create(
  { amount: 99.99, currency: 'EUR' },
  { idempotencyKey: 'order-123-checkout' },
);

Industry Examples

FX Broker — Trader Deposit

await meshtally.checkoutSessions.create({
  amount: 1000, currency: 'USD',
  payment_type: 'deposit',
  product_category: 'trading_deposit',
  customer_country: 'AE',
  is_returning_customer: true,
});

iGaming — Player Top-Up

await meshtally.checkoutSessions.create({
  amount: 50, currency: 'EUR',
  payment_type: 'deposit',
  product_category: 'gaming_deposit',
  channel: 'mobile',
  risk_level: 'low',
});

Prop Trading — Challenge Fee

await meshtally.checkoutSessions.create({
  amount: 499.99, currency: 'USD',
  payment_type: 'one_time',
  product_category: 'challenge_fee',
  product_name: '100K Funded Challenge',
  price_tier: 'high',
});

SaaS — Monthly Subscription

await meshtally.checkoutSessions.create({
  amount: 29.99, currency: 'EUR',
  payment_type: 'subscription',
  subscription_interval: 'monthly',
  product_name: 'Pro Plan',
  is_returning_customer: true,
  customer_lifetime_payments: 6,
});

Changelog

v2.7.6

  • Feature: pricingHealth resource — get() returns the system-level pipeline snapshot (ML retrain / insights / FX / fee sync), cronStatus() returns the full scheduled-job diagnostic (jobs, last runs, pg_cron / pg_net availability).
  • Types: PricingIntelligenceHealth, PricingIntelligenceHealthPipe, PricingIntelligenceCronStatus, PricingIntelligenceCronJob.

v2.7.5

  • Feature: Learning progress visibility — estimate_bucket_time_to_high_confidence RPC exposes per-bucket samples, velocity, days remaining and blocking reasons so merchants can track cost-aware readiness.
  • Feature: Public health snapshot — pricing_intelligence_health() RPC feeds the Pricing Intelligence section on the public /status page with ML retrain freshness, insights engine heartbeat, FX rates, and PSP fee sync counts. Aggregate only, no tenant-identifying data.
  • Feature: Every ML retrain run now logged to ml_training_runs (success/failure, rows trained, observed vs estimated split).

v2.7.4

  • Feature: ML training now ingests observed_cost from transaction_attempts (preferred over contract estimate). Records cost_data_source and cost_observed_coverage so routing can weight the cost signal by trust.
  • Feature: Pricing Insights engine — automatic variance alerts, savings opportunities, activation suggestions, and stale-profile warnings. New pricingInsights SDK resource.
  • Feature: Cost-per-approved reporting backed by ML weights, broken down by PSP × country × brand with source badge (observed / mixed / estimated).
  • Types: PricingInsight, PricingInsightKind, PricingInsightSeverity, PricingInsightStatus.

v2.7.3

  • Feature: Automatic fee extraction from Stripe, Adyen, and Checkout.com payment webhooks — observed cost populates on every attempt within seconds.
  • Feature: Scheduled PSP API pull for settlement fees (Stripe /v1/balance_transactions, Adyen /payoutSettlements) every 15 minutes via pg_cron.
  • Feature: New pspFeeSync resource — list(), upsert(), pullNow() — for managing per-PSP ingestion mode.
  • Types: PspFeeSyncConfig, PspFeeSyncMethod, PspFeeSyncFrequency, PspFeeSyncUpsertParams, PspFeeSyncRunResult.

v2.7.2

  • Feature: Volume-based fee tiering on fee profiles (FeeProfile.volume_tiers[]) — server picks the right tier from rolling 30-day volume and tx count.
  • Feature: Contract CSV import — fees.previewCsvImport() / fees.commitCsvImport(). Rows land as drafts; Finance approval preserved.
  • Feature: bin.resolve(bin) resource, and auto-enrichment inside smart-routing-optimizer when only card_bin is supplied.
  • Feature: Mid-market FX rate conversion — calculate_transaction_cost converts transaction amount to settlement currency before applying percent fees; fx_rate_applied and amount_in_settlement added to the response.
  • Types: FeeVolumeTier, BinLookupResult, ContractImportParams, ContractImportPreview, ContractImportResult.

v2.7.1

  • Feature (Pricing Intelligence): New fees, observedFees and costReadiness resources.
    • fees.list / get / create / submit / approve / reject / archive / calculate — contracted fee profiles with dual-control approval (DB trigger blocks self-approval).
    • observedFees.list / coverage / imports / previewImport / commitImport — ingest PSP settlement reports via CSV with reusable column-mapping templates; observed fees take priority over contracted estimates in the confidence engine.
    • costReadiness.matrix / refresh / gates / setGate — per-bucket readiness signals (approved profile, sample count, coverage %, freshness) and gated cost-aware routing activation. Enabling a gate below the required confidence is rejected server-side.
  • Feature (Routing): Smart routing optimizer now returns cost_estimate, cost_estimate_breakdown, cost_confidence_level, effective_goal, cost_gate_applied, bucket_key and decision_explanation in every decision.
  • Types: Exported FeeProfile, FeeProfileStatus, FeeEstimate, FeeEstimateBreakdown, ObservedFee, SettlementImportParams, SettlementImportPreview, SettlementImportResult, CostReadinessBucket, CostRoutingGate, CostRoutingGateToggleParams, CostConfidenceLevel, RoutingMode.

v2.6.2

  • Security: Removed email-based beneficiary filtering to prevent enumeration attacks. Use external_id instead.

v2.6.1

  • Security: Debug logging now redacts sensitive fields (IBAN, email, wallet address, card numbers, phone).
  • Safety: Production warning printed to stderr when debug: true used with sk_live_ key or environment: 'production'.

v2.6.0

  • Feature: Payout method management — addPayoutMethod(), retrievePayoutMethod(), listPayoutMethods(), updatePayoutMethod(), deletePayoutMethod().
  • Feature: New types: PayoutMethod, PayoutMethodStatus, CreatePayoutMethodParams, UpdatePayoutMethodParams, ListPayoutMethodsParams.
  • Server-side validation per method type (bank IBAN, crypto wallet, card last 4, mobile number).
  • 11 new validation tests (77 total).

v2.5.0

  • Initial public release with checkout sessions, transactions, refunds, payouts (including batch), beneficiaries, settlement, account, and webhook verification.

Links

License

MIT — Sodasoft LLC