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

@maxnate/provider-snippe

v0.3.1

Published

Snippe.sh payment provider for @maxnate/payments-core. Supports Mobile Money (M-Pesa, Airtel, Mixx, Halotel), Card, and Dynamic QR payments in Tanzania.

Readme

@maxnate/provider-snippe

Snippe.sh payment provider for @maxnate/payments-core.

Supports receiving payments only (collection). Payouts/disbursements are not part of this package.

Payment Types

| Type | paymentType | Currency | Flow | |---|---|---|---| | Mobile Money | "mobile" | TZS | USSD push to customer phone | | Card | "card" | TZS | Redirect to payment_url | | Dynamic QR | "dynamic-qr" | TZS | Scan QR code with mobile money app |

Hosted Sessions

Snippe Sessions are now supported as an optional hosted-checkout mode.

  • enable with credentials.useSessions = 'true'
  • optionally set profileId and allowedMethods in the gateway config
  • createPaymentIntent() returns redirectUrl = checkout_url plus short-link metadata when Sessions mode is active
  • additional helpers: getSession(), listSessions(), cancelSession(), cancelAttempt(), createPaymentLink()

UI Integration Guide

This provider supports two UI models. What you can build depends on which one you choose.

Shared Terminology

  • Customer UI: the payment or checkout experience in your own application.
  • Admin UI: your tenant/operator-facing setup and operations screens.
  • Provider-hosted checkout: Snippe's hosted Sessions/checkout page.
  • Provider dashboard: Snippe dashboard for API keys, webhook secret, and payment profiles.

1. Fully Custom UI In Your Project

Use Snippe direct payments when you want your own checkout screens inside your app.

  • You control: payment method picker, form layout, branding, validation, order summary, success/cancel pages, and overall customer journey in your frontend.
  • You can build:
    • your own mobile-money checkout page that asks for phone number then triggers USSD push
    • your own card handoff page before redirecting to Snippe/card gateway
    • your own QR payment page that renders the returned QR data in your UI
    • your own payment status polling / instructions UI around the Snippe transaction
  • You still rely on Snippe for: payment processing, webhook events, account balance, provider-side ledger, and the actual downstream payment rails.
  • Best when: you want a branded product experience and your team is comfortable owning the checkout UX in your application.

2. Snippe Hosted Checkout UI

Use Sessions when you want Snippe to host the checkout page.

  • You control: the page before redirect, session creation options, redirect destination, allowed methods, line items, custom fields, and whether to use full checkout URL or short payment link.
  • Snippe controls: the actual hosted checkout page UI, payment form, and payment-attempt screens.
  • You can build in your project:
    • a checkout launch page that creates the session and redirects to checkout_url
    • a share flow using payment_link_url for WhatsApp/SMS/email
    • a post-payment success page driven by your redirect_url
    • an admin setup screen that stores profileId, allowedMethods, and useSessions

What You Can Customize

  • In your own app UI: everything before and after payment handoff.
  • In direct-payment mode: almost the entire customer-facing experience in your frontend.
  • In Sessions mode:
    • allowed_methods
    • redirect_url
    • webhook_url
    • description
    • line_items
    • custom_fields
    • display
    • billing
    • profile_id

What You Cannot Customize Through This Package

  • You cannot CRUD Snippe payment profiles from API in 2026-01-25; profiles are managed in the Snippe dashboard.
  • You cannot fully replace Snippe's hosted checkout page UI when using Sessions.
  • You should not treat url_metadata as secret data; it is transport metadata, not encrypted application state.

Dashboard vs. Project UI

  • Use your project UI for: custom checkout pages, payment-method selection, order context, manual payment guidance, and branded customer journeys.
  • Use the Snippe dashboard for: API keys, webhook signing key, payment profile creation/editing, and provider-account operational settings.

Recommended Pattern

  • Choose direct payments if you want a fully custom UI in your application.
  • Choose Sessions if you want faster rollout, lower checkout implementation effort, and are comfortable with Snippe hosting the payment page.

Authentication

Snippe uses Bearer token authentication. The provider includes the API key on every request.

| Header | Value | |---|---| | Authorization | Bearer <apiKey> | | Idempotency-Key | Auto-generated as a hashed key derived from tenantId + orderId (max 30 chars) |

Credentials

| Field | Description | |---|---| | apiKey | Snippe API key. Get it from Settings > API Keys in the Snippe dashboard. | | webhookSecret | Optional. Webhook signing key (whsec_...). Used for HMAC verification. |

Usage

import { createPaymentProviderRegistry } from '@maxnate/payments-core'
import { SnippeProvider } from '@maxnate/provider-snippe'

const registry = createPaymentProviderRegistry()
registry.register(new SnippeProvider())

await registry.setConfig({
  id: 'snippe', name: 'Snippe', type: 'mobile_money', enabled: true,
  testMode: false,
  credentials: { apiKey: process.env.SNIPPE_API_KEY! },
  webhookSecret: process.env.SNIPPE_WEBHOOK_SECRET,
  currencies: ['TZS'], countries: ['TZ']
})

// Mobile Money (USSD push)
const result = await registry.createPaymentIntent('snippe', {
  orderId: 'ORD-001', amount: 5000, currency: 'TZS',
  paymentType: 'mobile',
  customerEmail: '[email protected]',
  customerPhone: '255712345678',
  metadata: { webhook_url: 'https://site.com/webhooks/snippe' }
})

// Card (redirect to checkout)
const cardResult = await registry.createPaymentIntent('snippe', {
  orderId: 'ORD-002', amount: 25000, currency: 'TZS',
  paymentType: 'card',
  returnUrl: 'https://site.com/success',
  cancelUrl: 'https://site.com/cancel',
  customerAddress: {
    address: '123 Street', city: 'Dar es Salaam',
    state: 'DSM', postcode: '14101', country: 'TZ'
  }
})

// Dynamic QR
const qrResult = await registry.createPaymentIntent('snippe', {
  orderId: 'ORD-003', amount: 10000, currency: 'TZS',
  paymentType: 'dynamic-qr'
})
// → qrResult.qrCodeData contains the QR code data string

// Hosted Session (Snippe UI)
const sessionResult = await registry.createPaymentIntent('snippe', {
  orderId: 'ORD-004', amount: 15000, currency: 'TZS',
  metadata: {
    useSessions: true,
    description: 'Order #004',
    allowed_methods: ['mobile_money', 'qr'],
    line_items: [{ name: 'Premium Package', quantity: 1, unit_price: 15000 }]
  }
})
// -> redirect the customer to sessionResult.redirectUrl

Webhook Handling

Snippe sends webhook events with HMAC-SHA256 signature verification and replay attack protection (5 minute window).

import { handlePaymentWebhook } from '@maxnate/payments-core'

app.post('/webhooks/snippe', async (req, res) => {
  const rawBody = JSON.stringify(req.body) // RAW body, not parsed JSON
  const signature = req.headers['x-webhook-signature']
  const headers = {
    'x-webhook-timestamp': req.headers['x-webhook-timestamp'],
    'x-webhook-event': req.headers['x-webhook-event']
  }

  const result = await handlePaymentWebhook(
    rawBody, signature, 'snippe', registry,
    {
      findPaymentIntent: (id) => db.payments.findById(id),
      updatePaymentIntent: (id, data) => db.payments.update(id, data),
      idempotencyStore  // Replica-safe; system-core's IdempotencyStore satisfies the duck-typed shape
    },
    headers
  )

  res.status(result.success ? 200 : 400).send(result.success ? 'OK' : result.error)
})

Webhook Events

| Snippe Event | Mapped Type | |---|---| | payment.completed | payment.succeeded | | payment.failed | payment.failed | | payment.voided | payment.cancelled | | payment.expired | payment.failed |

Admin Discovery And Self-Test

  • SnippeProvider.getCapabilities() exposes a machine-readable descriptor for admin UIs, including supported methods, currencies, credentials, and webhook URL template.
  • SnippeProvider.selfTest(config) validates credentials with GET /v1/payments/balance, so hosts can check connectivity without creating a real payment.
  • SnippeProvider.getBalance(), listPayments(), searchPayments(), and pushUssd(reference) expose the main direct-payment admin operations from the Snippe 2026-01-25 API.
  • SnippeProvider also exposes hosted-checkout helpers for Sessions, Payment Links, and session cancellation flows.

Enriched Webhook Data

handleWebhook() now maps additional Snippe fields into the normalized event surface so hosts can persist them without digging through raw payloads:

  • externalReference
  • failureReason
  • settlement.gross / fees / net
  • channel.type / provider
  • decoded metadata.url_metadata
  • customer details copied into providerData.customer

Status Mapping

| Snippe Status | Mapped Status | |---|---| | pending | pending | | completed | succeeded | | failed | failed | | voided | cancelled | | expired | failed |

Requirements

  • Node.js >= 18
  • @maxnate/payments-core ^0.3.0