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

@selcom/payment-plugin-sdk

v1.2.0

Published

Server-side HTTP client for the Selcom Payment Plugin API. Create checkout sessions, look up payment intents, manage developer keys, mint anonymous demo sessions, and request live access from Node.js, Deno, or Bun.

Readme

@selcom/payment-plugin-sdk

Typed Axios-based client for the Payment Plugin embeddable checkout API.

Install

pnpm add @selcom/payment-plugin-sdk

Configuration

| target | baseUrl example | Paths | |----------|-------------------|--------| | gateway (default) | http://localhost:8000 | /api/plugin/*, /api/admin/plugin/*, /api/developer/*, /api/admin/developers/* | | direct | http://localhost:9025 | /api/v1/plugin/*, /api/v1/plugin/admin/* |

Merchant checkout (publishable + secret keys)

import { PaymentPluginClient } from '@selcom/payment-plugin-sdk';

const client = new PaymentPluginClient({
  baseUrl: process.env.SELCOM_GATEWAY_URL ?? 'http://localhost:8000',
  target: 'gateway',
  publicKey: process.env.SELCOM_PLUGIN_PUBLIC_KEY!,
  secretKey: process.env.SELCOM_PLUGIN_SECRET_KEY!,
});

// Server-side: create session
const session = await client.createSession(
  { amount: 1050, currency: 'NAD', reference: 'order-42' },
  { idempotencyKey: '550e8400-e29b-41d4-a716-446655440000' },
);

const sessionToken = String(session.sessionToken);

// Browser-facing steps use the same client from your BFF, passing sessionToken:
await client.attachPaymentMethod(sessionToken, { type: 'card' });
await client.payWithCard(sessionToken, {
  cardNumber: '4111111111111111',
  expiryMonth: 12,
  expiryYear: 2030,
  cvv: '123',
  cardholderName: 'Test User',
});

// Poll from merchant backend
const status = await client.getMerchantPayment(String(session.intentId));

Wallet OTP

await client.requestWalletOtp(sessionToken, { phone: '+264811234567' });
await client.verifyWalletOtp(sessionToken, { otpReference: '...', otp: '123456' });

Admin: issue keys

Through the gateway, configure PAYMENT_PLUGIN_ADMIN_API_KEY on the gateway (must match PLUGIN_ADMIN_API_KEY on payment-plugin-service). The client only sends the admin JWT:

const admin = new PaymentPluginClient({
  baseUrl: 'http://localhost:8000',
  target: 'gateway',
});

const keys = await admin.adminCreatePluginKeys(adminAccessToken, {
  merchantId: 'merchant_1',
  name: 'Storefront',
  environment: 'test',
  branding: { merchantName: 'Demo Shop' },
  allowedOrigins: ['https://shop.example'],
});
// keys.publicKey, keys.secretKey — secret shown once

Direct to port 9025 (no gateway JWT), pass the admin header only:

await admin.adminCreatePluginKeys(undefined, payload, {
  xPluginAdminKey: process.env.PLUGIN_ADMIN_API_KEY!,
});

Developer self-serve

Available since 1.1.0. The same client speaks the developer-portal surface under /api/developer/* (gateway) or /api/v1/developer/* (direct).

Anonymous demo sessions (no auth)

const anon = new PaymentPluginClient({ baseUrl: 'https://sandbox-api.selcom.com.na' });

const session = await anon.mintAnonymousDeveloperSession({
  purpose: 'plugin-demo',
  userAgent: 'demo-cli/1.0',
});
console.log(session.publicKey, session.expiresAt);

// Poll the delivered-event log (typically every ~2s).
const events = await anon.listAnonymousDeveloperSessionEvents(session.sessionId);
for (const ev of events) {
  console.log(ev.type, ev.data);
}

The mint endpoint is rate-limited to 10/min/IP, the events endpoint to 120/min/IP, and the issued public key only works against sandbox merchants. The session expires after 30 minutes.

Read settings + request live access (developer JWT)

Since 1.2.0, requestLiveAccess requires a full body (at minimum applicantType + legalName).

const dev = new PaymentPluginClient({ baseUrl: 'https://api.selcom.com.na' });

const settings = await dev.getDeveloperSettings(developerAccessToken);
console.log(settings.kycStatus); // 'sandbox_only' | 'pending' | 'approved' | 'rejected'

const updated = await dev.requestLiveAccess(developerAccessToken, {
  applicantType: 'business',
  legalName: 'Acme (Pty) Ltd',
  country: 'NA',
  businessRegistrationNumber: 'CC123',
  integrationType: 'api',
  applicantNotes: 'Launching checkout next month.',
});
console.log(updated.latestApplication?.trustScore);

const history = await dev.listOwnDeveloperApplications(developerAccessToken);

// Public page (no JWT) — token from approval email
const revealed = await dev.revealKeySecret('srv_…');
console.log(revealed.secretKey);

Admin: developer onboarding (gateway JWT)

Since 1.2.0. Same admin machinery as plugin keys: gateway injects X-Plugin-Admin-Key; the SDK only sends the operator JWT.

const admin = new PaymentPluginClient({ baseUrl: 'http://localhost:8000', target: 'gateway' });

const page = await admin.adminListDeveloperApplications(adminJwt, { status: 'pending' });
const detail = await admin.adminGetDeveloperDetail(adminJwt, userId);
const approved = await admin.adminApproveDeveloper(adminJwt, userId, {
  initialKey: { label: 'Live key', allowedOrigins: ['https://shop.example'] },
});
// approved.liveKey.secretKey, approved.reveal.token, approved.reveal.revealUrl

Errors

Failed responses throw PaymentPluginRequestError with status, code, and message.

Spec

See docs/selcom-payments-gateway.openapi.yaml (tags Payment Plugin, Developer Self-Serve, Developer Admin, and Developer Anonymous Demo) and docs/channels/payment-plugin.md.