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

quirk-sdk

v1.0.0

Published

Developer-first payment infrastructure SDK for African technology companies. One unified API for multi-rail payments, cards, virtual accounts, USSD, and mobile money with autonomous failover.

Readme

@quirk/sdk

Developer-first payment infrastructure and control plane for African technology companies.

npm version License: MIT TypeScript

One integration to access cards, bank transfers, virtual accounts, USSD, and mobile money across Africa.

QuickstartNamespacesMulti-Rail FailoverWebhooksVirtual AccountsBulk Transfers


Overview

Quirk standardizes heterogeneous African payment rails into a unified, type-safe interface. Integrate once, configure multiple underlying gateways (Paystack, Flutterwave, Monnify, Squad), and execute transactions with automatic failover routing.

  • Unified Interface: One data model across Paystack, Flutterwave, Monnify, and Squad.
  • Autonomous Failover: Automatically reroute traffic to healthy backup rails during provider degradation.
  • Normalized Lifecycle: Collapses 15+ disparate provider states into 4 canonical statuses: success, failed, pending, abandoned.
  • Consistent Minor Units: Amounts are specified as integers in minor currency units (e.g. 25000 for ₦250.00) or major units with utility converters.
  • Zero Configuration Drift: End-to-end TypeScript definitions for all charges, webhooks, splits, and refunds.

Quickstart

Installation

npm install @quirk/sdk
# or
pnpm add @quirk/sdk
# or
yarn add @quirk/sdk

Basic Initialization (Single Provider)

import { Quirk } from '@quirk/sdk';

// Initialize with Paystack
const quirk = Quirk.paystack(process.env.PAYSTACK_SECRET_KEY!);

// Create a payment session
const payment = await quirk.payments.create({
  amount: 25000, // ₦25,000 NGN
  email: '[email protected]',
  currency: 'NGN',
  metadata: { orderId: 'ord_987654' },
});

console.log(payment.authorizationUrl);
// => "https://checkout.paystack.com/..."

Multi-Rail Failover

Configure multiple payment providers simultaneously. When configured with dynamic_failover, Quirk executes the transaction on the primary provider and automatically falls back to secondary rails if network or gateway errors occur.

import { Quirk } from '@quirk/sdk';

const quirk = new Quirk({
  providers: {
    paystack: process.env.PAYSTACK_SECRET_KEY!,
    flutterwave: process.env.FLUTTERWAVE_SECRET_KEY!,
    monnify: process.env.MONNIFY_API_KEY!,
  },
  strategy: 'dynamic_failover',
  fallbackOrder: ['paystack', 'flutterwave', 'monnify'],
});

// Creates payment with autonomous failover protection
const payment = await quirk.payments.create({
  amount: 50000,
  email: '[email protected]',
  currency: 'NGN',
});

console.log(`Routed through: ${payment.routedProvider}`);

Core Namespaces

1. Payments (quirk.payments)

Initialize a Payment

const payment = await quirk.payments.create({
  amount: 10000,
  email: '[email protected]',
  currency: 'NGN',
  channels: ['card', 'bank_transfer', 'ussd'],
  callbackUrl: 'https://app.example.com/checkout/callback',
  idempotencyKey: 'idemp_txn_10293847',
});

Verify a Payment

const result = await quirk.payments.verify('qrk_ref_123456');

if (result.status === 'success') {
  console.log(`Verified payment of ${result.amount} ${result.currency}`);
  console.log(`Channel: ${result.channel}`);
  console.log(`Customer: ${result.customer.email}`);
}

Direct Charge (Recurring Token)

const charge = await quirk.payments.charge({
  amount: 15000,
  email: '[email protected]',
  channel: 'card',
  authorizationCode: 'AUTH_token_abc123',
});

2. Webhooks (quirk.webhooks)

Cryptographically verify HMAC-SHA256 signatures before processing event payloads.

import express from 'express';
import { Quirk } from '@quirk/sdk';

const app = express();
const quirk = Quirk.paystack(process.env.PAYSTACK_SECRET_KEY!, {
  webhookSecret: process.env.QUIRK_WEBHOOK_SECRET,
});

app.post('/api/webhooks', express.raw({ type: 'application/json' }), async (req, res) => {
  const signature = req.headers['x-paystack-signature'] as string;

  // Cryptographic signature check
  const isValid = quirk.webhooks.verify(req.body, signature);
  if (!isValid) {
    return res.status(401).send('Invalid signature');
  }

  // Parse into normalized event
  const event = quirk.webhooks.parse(req.body);

  if (event.type === 'charge.success') {
    console.log(`Received ${event.amount} ${event.currency} for ${event.reference}`);
    // Fulfill customer order
  }

  res.status(200).json({ received: true });
});

3. Dedicated Virtual Accounts (quirk.virtualAccounts)

Provision persistent bank accounts for automated customer deposit reconciliation.

const account = await quirk.virtualAccounts.create({
  email: '[email protected]',
  bvn: '22198765432',
  firstName: 'Amaka',
  lastName: 'Obi',
  phone: '+2348012345678',
});

console.log(`Account Number: ${account.accountNumber}`);
console.log(`Bank: ${account.bankName}`);

4. Bulk Transfers & Payouts (quirk.transfers)

Disburse funds to multiple bank accounts in a single batch.

const batch = await quirk.transfers.bulk({
  title: 'March 2026 Merchant Payouts',
  recipients: [
    {
      accountNumber: '0123456789',
      bankCode: '058',
      accountName: 'Folake Adeyemi',
      amount: 150000,
      narration: 'Merchant settlement #104',
    },
    {
      accountNumber: '9876543210',
      bankCode: '063',
      accountName: 'Chidi Okafor',
      amount: 220000,
      narration: 'Merchant settlement #105',
    },
  ],
});

console.log(`Batch ID: ${batch.batchReference}`);
console.log(`Successful dispatches: ${batch.successCount}`);

5. Refunds (quirk.refunds)

Initiate full or partial transaction refunds.

const refund = await quirk.refunds.create({
  reference: 'qrk_ref_123456',
  amount: 5000, // Optional partial amount; omits for full refund
  reason: 'Customer return',
});

console.log(`Refund status: ${refund.status}`);

Drop-in Checkout Widget

@quirk/sdk includes a drop-in browser checkout modal matching Quirk's minimal black and white aesthetic.

<link rel="stylesheet" href="node_modules/@quirk/sdk/checkout/quirk-checkout.css" />
<script src="node_modules/@quirk/sdk/checkout/quirk-checkout.js"></script>

<script>
  const checkout = new QuirkCheckout({
    key: 'pk_live_xxxxx',
    amount: 25000,
    currency: 'NGN',
    email: '[email protected]',
    onSuccess: function(response) {
      console.log('Payment successful:', response.reference);
    },
    onClose: function() {
      console.log('Checkout closed');
    }
  });

  document.getElementById('pay-btn').addEventListener('click', () => {
    checkout.open();
  });
</script>

Error Handling

All SDK exceptions derive from QuirkError, providing standard error codes, HTTP status codes, and provider diagnostics.

import { Quirk, QuirkError } from '@quirk/sdk';

try {
  const result = await quirk.payments.create({ ... });
} catch (error) {
  if (error instanceof QuirkError) {
    console.error(`Error Code: ${error.code}`);
    console.error(`HTTP Status: ${error.httpStatus}`);
    console.error(`Provider: ${error.provider}`);
    console.error(`Underlying details:`, error.providerDetails);
  }
}

Verification & Testing

# Run complete test suite (160+ unit & integration tests)
pnpm test

# Build CJS, ESM, and TypeScript declarations
pnpm run build

License

MIT © Quirk