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

paybridge

v0.1.3

Published

One API, every payment provider. Unified payment SDK for Node.js — SoftyComp, Yoco, Ozow, and more.

Readme

PayBridge

One API. Every payment provider. 🌍

npm version License: MIT TypeScript

Unified payment SDK for Node.js that works with multiple payment providers through a single, consistent API. Focus on South African providers first, with support for international gateways.

WaSP is to WhatsApp what PayBridge is to payments — one SDK, multiple backends, zero friction.

Features

  • Unified API — Same code works across all providers
  • TypeScript-first — Full type safety and autocomplete
  • South African focus — SoftyComp, Yoco, Ozow, PayFast ready
  • International support — Stripe, PayStack, Peach Payments (coming soon)
  • Production-ready — Webhooks, refunds, subscriptions, retries
  • Zero lock-in — Switch providers by changing 1 config line

Installation

npm install paybridge

Interactive Playground

Want to see PayBridge in action before writing code? Try our Stripe-style interactive playground:

cd playground
npm install
npm start

Then open http://localhost:4020 in your browser.

The playground lets you:

  • Create real payments against SoftyComp sandbox
  • Watch webhooks arrive in real-time
  • Generate code snippets (TypeScript/JavaScript)
  • Compare PayBridge vs raw API complexity
  • Test all payment operations with a beautiful UI

Perfect for demos, learning, and rapid prototyping. See playground/README.md for details.

Quick Start

One-time Payment

import { PayBridge } from 'paybridge';

// Initialize with your provider
const pay = new PayBridge({
  provider: 'softycomp',
  credentials: {
    apiKey: process.env.SOFTYCOMP_API_KEY,
    secretKey: process.env.SOFTYCOMP_SECRET_KEY
  },
  sandbox: true
});

// Create payment — same API regardless of provider
const payment = await pay.createPayment({
  amount: 299.00,        // Always in major currency unit (rands)
  currency: 'ZAR',
  reference: 'INV-001',
  customer: {
    name: 'John Doe',
    email: '[email protected]',
    phone: '0825551234'
  },
  urls: {
    success: 'https://myapp.com/success',
    cancel: 'https://myapp.com/cancel',
    webhook: 'https://myapp.com/webhook'
  }
});

// Redirect customer to payment page
console.log(payment.checkoutUrl);
// Payment details
console.log(payment.id);       // Provider payment ID
console.log(payment.status);   // 'pending' | 'completed' | 'failed' | 'cancelled'
console.log(payment.provider); // 'softycomp'

Recurring Subscription

const subscription = await pay.createSubscription({
  amount: 299.00,
  currency: 'ZAR',
  interval: 'monthly',     // 'weekly' | 'monthly' | 'yearly'
  reference: 'SUB-001',
  customer: {
    name: 'Jane Smith',
    email: '[email protected]'
  },
  urls: {
    success: 'https://myapp.com/success',
    cancel: 'https://myapp.com/cancel',
    webhook: 'https://myapp.com/webhook'
  },
  startDate: '2026-04-01',  // Must be future date
  billingDay: 1             // Day of month (1-28)
});

Refund

// Full refund
const refund = await pay.refund({
  paymentId: 'pay_123'
});

// Partial refund
const refund = await pay.refund({
  paymentId: 'pay_123',
  amount: 100.00,
  reason: 'Customer request'
});

Check Payment Status

const payment = await pay.getPayment('pay_123');
if (payment.status === 'completed') {
  console.log('Payment received!');
}

Webhooks

import express from 'express';

const app = express();

// IMPORTANT: Use express.raw() for signature verification
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  // Verify webhook signature
  if (!pay.verifyWebhook(req.body, req.headers)) {
    return res.status(400).send('Invalid signature');
  }

  // Parse webhook event
  const event = pay.parseWebhook(req.body, req.headers);

  switch (event.type) {
    case 'payment.completed':
      console.log('Payment completed:', event.payment);
      // Fulfill order, activate subscription, etc.
      break;

    case 'payment.failed':
      console.log('Payment failed:', event.payment);
      // Notify customer
      break;

    case 'payment.cancelled':
      console.log('Payment cancelled:', event.payment);
      break;

    case 'refund.completed':
      console.log('Refund completed:', event.refund);
      break;
  }

  res.sendStatus(200);
});

Supported Providers

| Provider | One-time | Subscriptions | Refunds | Webhooks | Status | |----------|----------|---------------|---------|----------|--------| | SoftyComp | ✅ | ✅ | ✅ | ✅ | Production | | Yoco | 🚧 | 🚧 | 🚧 | 🚧 | Coming soon | | Ozow | 🚧 | 🚧 | 🚧 | 🚧 | Coming soon | | PayFast | 📋 | 📋 | 📋 | 📋 | Planned | | PayStack | 📋 | 📋 | 📋 | 📋 | Planned | | Stripe | 📋 | 📋 | 📋 | 📋 | Planned | | Peach Payments | 📋 | 📋 | 📋 | 📋 | Planned |

Legend: ✅ Production ready | 🚧 In development | 📋 Planned

Provider Configuration

SoftyComp

const pay = new PayBridge({
  provider: 'softycomp',
  credentials: {
    apiKey: 'your_api_key',
    secretKey: 'your_secret_key'
  },
  sandbox: true,
  webhookSecret: 'optional_webhook_secret'
});

Docs: SoftyComp API

Yoco (Coming Soon)

const pay = new PayBridge({
  provider: 'yoco',
  credentials: {
    apiKey: 'sk_test_...' // Secret key
  },
  sandbox: true,
  webhookSecret: 'whsec_...'
});

Docs: Yoco Developer

Ozow (Coming Soon)

const pay = new PayBridge({
  provider: 'ozow',
  credentials: {
    apiKey: 'your_api_key',
    siteCode: 'your_site_code',
    privateKey: 'your_private_key'
  },
  sandbox: true
});

Docs: Ozow Hub

Switch Providers in 1 Line

// Using SoftyComp
const pay1 = new PayBridge({ provider: 'softycomp', credentials: { ... } });

// Switch to Yoco — SAME API!
const pay2 = new PayBridge({ provider: 'yoco', credentials: { ... } });

// Switch to Ozow — SAME API!
const pay3 = new PayBridge({ provider: 'ozow', credentials: { ... } });

// All methods work identically
const payment = await pay1.createPayment({ ... }); // SoftyComp
const payment = await pay2.createPayment({ ... }); // Yoco
const payment = await pay3.createPayment({ ... }); // Ozow

Why PayBridge?

South Africa's payment landscape is fragmented. Different providers for different use cases:

  • SoftyComp — Debit orders and bill presentment
  • Yoco — Card payments for SMEs
  • Ozow — Instant EFT
  • PayFast — Online payments

Each has its own SDK, quirks, and integration patterns. PayBridge unifies them all.

Before PayBridge

// SoftyComp
const softycomp = new SoftyComp({ ... });
const bill = await softycomp.createBill({ amount: 299.00, frequency: 'once-off', ... });

// Yoco
const yoco = new Yoco({ ... });
const checkout = await yoco.checkouts.create({ amountInCents: 29900, ... });

// Ozow
const ozow = new Ozow({ ... });
const payment = await ozow.initiatePayment({ Amount: '299.00', HashCheck: '...', ... });

Different APIs, different amount formats, different field names.

With PayBridge

// ONE API for all providers
const payment = await pay.createPayment({
  amount: 299.00,
  currency: 'ZAR',
  reference: 'INV-001',
  customer: { ... },
  urls: { ... }
});

Same code. Every provider.

API Reference

PayBridge

Constructor

new PayBridge(config: PayBridgeConfig)

Methods

  • createPayment(params: CreatePaymentParams): Promise<PaymentResult>
  • createSubscription(params: CreateSubscriptionParams): Promise<SubscriptionResult>
  • getPayment(id: string): Promise<PaymentResult>
  • refund(params: RefundParams): Promise<RefundResult>
  • parseWebhook(body: any, headers?: any): WebhookEvent
  • verifyWebhook(body: any, headers?: any): boolean
  • getProviderName(): string
  • getSupportedCurrencies(): string[]

Types

See src/types.ts for full type definitions.

Currency Handling

PayBridge always uses major currency units (rands, dollars) in the API:

// ✅ Correct
{ amount: 299.00, currency: 'ZAR' }

// ❌ Wrong (don't use cents)
{ amount: 29900, currency: 'ZAR' }

PayBridge handles provider-specific conversions internally:

  • SoftyComp uses rands → no conversion
  • Yoco uses cents → converts to cents
  • Ozow uses rands → no conversion

Error Handling

try {
  const payment = await pay.createPayment({ ... });
} catch (error) {
  console.error('Payment failed:', error.message);
  // Handle error (invalid credentials, network error, etc.)
}

Webhook Security

Always verify webhook signatures in production:

app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  // Verify signature
  if (!pay.verifyWebhook(req.body, req.headers)) {
    return res.status(401).send('Unauthorized');
  }

  // Signature valid — process event
  const event = pay.parseWebhook(req.body, req.headers);
  // ...
});

Roadmap

  • [x] v0.1 — Core API + SoftyComp provider
  • [ ] v0.2 — Yoco provider
  • [ ] v0.3 — Ozow provider
  • [ ] v0.4 — PayFast provider
  • [ ] v0.5 — PayStack provider (Nigeria)
  • [ ] v0.6 — Stripe provider (international)
  • [ ] v0.7 — Peach Payments provider
  • [ ] v1.0 — Production-ready with all SA providers

Contributing

We welcome contributions! To add a new payment provider:

  1. Create src/providers/yourprovider.ts extending PaymentProvider
  2. Implement all abstract methods
  3. Add provider to src/index.ts factory
  4. Update README with provider details
  5. Submit PR

See src/providers/softycomp.ts for reference implementation.

License

MIT © Kobie Wentzel

Related Projects

  • WaSP — Unified WhatsApp API (Baileys, Cloud API, Twilio)
  • softycomp-node — Official SoftyComp SDK

Built with ❤️ in South Africa