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

@afinx/bridge-sdk

v0.2.1

Published

JavaScript SDK for integrating Afinx Bridge — connect bank accounts and mobile money across Africa.

Downloads

66

Readme

@afinx/bridge-sdk

JavaScript SDK for integrating the Afinx Bridge widget — let your users securely connect their bank accounts and mobile money wallets across Africa.

npm install @afinx/bridge-sdk

Production (recommended): server-minted link token

Keep your secret key on your server. Mint a one-shot link token there, hand it to the browser, and pass it to the SDK — the key never ships in client code.

// 1. Your backend mints a link token with your secret key.
//    POST https://api.afinx.co/bridge/link-token
//    Authorization: Bearer afinx_test_sk_...   → { linkToken: "link_..." }

// 2. Your frontend opens the widget with that token (no key in the browser):
import { createBridge } from '@afinx/bridge-sdk';

const bridge = createBridge(); // no apiKey needed when you pass a linkToken
bridge.open({
  linkToken,                              // from your backend
  onSuccess: async (publicToken) => {
    // 3. Exchange the public token on YOUR BACKEND (never in the browser).
    await fetch('/api/afinx/exchange-token', {
      method: 'POST',
      body: JSON.stringify({ publicToken }),
    });
  },
  onExit: () => console.log('User closed the widget.'),
  onError: (err) => console.error('Bridge error:', err),
});

Sandbox quick start

For quick local testing you can let the SDK mint the link token in-browser with a sandbox key. Don't use this with a live key — the key would be exposed in client code.

const bridge = createBridge({ apiKey: 'afinx_test_sk_...', environment: 'sandbox' });
bridge.open({ userId: 'user_123', onSuccess: (publicToken) => {/* … */} });

Either way, the widget handles institution selection, credential capture, USSD/OTP MFA (and inbox/upload for the Statements product), and returns a single-use publicToken your backend exchanges for an access token.

Configuration

createBridge(config)

| Field | Type | Required | Default | Description | |---|---|---|---|---| | apiKey | string | no* | — | afinx_test_sk_... / afinx_live_sk_.... *Required only if you DON'T pass a linkToken to open() (i.e. the sandbox in-browser-mint path). Omit it in production. | | environment | 'sandbox' \| 'production' | no | 'production' | Selects the default apiUrl and bridgeUrl. | | apiUrl | string | no | env-derived | Override the API host (self-hosted setups, custom subdomains). | | bridgeUrl | string | no | env-derived | Override the widget host. |

Default URLs by environment

| Environment | apiUrl | bridgeUrl | |---|---|---| | sandbox | https://api.sandbox.afinx.co | https://bridge.afinx.co | | production | https://api.afinx.co | https://bridge.afinx.co |

The widget URL is the same in both environments — the link token (minted by either the sandbox or live API) tells the widget which API to call back to. One widget deployment serves both.

Security: never put a live apiKey in client-side code. For browser integrations, mint a one-shot link token on your backend and pass it to open({ linkToken }) instead (see Production). Available since 0.2.0.

bridge.open(options)

| Field | Type | Description | |---|---|---| | linkToken | string | A one-shot link token your backend minted (POST /bridge/link-token). Pass this in production — the SDK then skips client-side minting, so apiKey isn't needed in the browser. | | userId | string | Your stable identifier for the end user. | | redirectUri | string | Where to send the user after the flow (redirect mode — coming in 0.2). | | webhookUrl | string | Per-session webhook override. Falls back to your developer-level webhook. | | metadata | object | Arbitrary JSON attached to the session and returned in webhooks. | | onSuccess | (publicToken, metadata) => void | Fired with the single-use public token. | | onExit | (error?) => void | Fired when the user closes the widget. error is set if the close was due to a problem. | | onError | (error) => void | Fired on terminal failures (network, invalid session, etc.). |

bridge.close() / bridge.isOpen()

Programmatic control of the widget. Useful for cleanup on route change in SPAs.

useEffect(() => () => bridge.close(), []);

Token exchange (server-side)

The publicToken returned to onSuccess is single-use and expires in 10 minutes. Exchange it on your backend immediately:

// pages/api/afinx/exchange-token.ts (Next.js example)
const r = await fetch('https://api.afinx.co/bridge/exchange-token', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.AFINX_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ publicToken: req.body.publicToken }),
});
const { accessToken, itemId, accounts } = await r.json();
// Persist accessToken keyed on your user. Use it to call /v1/transactions etc.

TypeScript

Full types ship with the package — BridgeConfig, BridgeOpenOptions, BridgeInstance are exported.

import type { BridgeConfig, BridgeOpenOptions } from '@afinx/bridge-sdk';

Bundle size

  • Tree-shakeable ("sideEffects": false).
  • Zero runtime dependencies.
  • ~3 kB gzipped.

Browser support

Modern evergreen browsers (Chrome/Edge/Firefox/Safari, last 2 versions). The SDK uses window.postMessage, window.open, and fetch — no polyfills included, no IE11.

Versioning

This package follows Semantic Versioning starting at 0.1.0. While the major version is 0.x, minor releases may include breaking changes. Pin to a minor in production:

// package.json
"@afinx/bridge-sdk": "~0.2.0"   // accepts 0.2.x, not 0.3.0

Links

  • Docs: https://afinx.co/docs
  • Dashboard: https://afinx.co/dashboard
  • Changelog: CHANGELOG.md
  • Issues: https://github.com/afinx/bridge-sdk/issues

License

MIT — see LICENSE.