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

@cashiaapp/pay-with-cashia

v0.1.6

Published

A framework-agnostic Cashia payment button library that opens a payment modal.

Readme

Pay with Cashia

@cashiaapp/pay-with-cashia adds a Cashia payment button and hosted checkout modal to a website. It is framework-agnostic and can be used through its JavaScript API or as a Web Component.

How the integration works

  1. A customer selects Pay with Cashia on your checkout page.
  2. The library calls the createSession function supplied by your application.
  3. Your frontend asks your backend to create a payment session.
  4. Your backend authenticates with Cashia and returns the hosted checkout URL.
  5. The library opens that URL in a modal iframe.
  6. Cashia closes the modal when the hosted payment flow finishes or is cancelled.

[!IMPORTANT] Create Cashia payment sessions on your backend. Never expose Cashia API keys, access tokens, or other credentials in browser code.

Prerequisites

Before integrating, obtain the following from Cashia:

  • Access to the public @cashiaapp/pay-with-cashia npm package
  • Your Cashia API credentials and payment-session API details
  • The hosted checkout URL or environment details for sandbox and production
  • A publicly accessible HTTPS URL for your partner logo

The library requires a browser DOM. Server-side rendered applications must initialize it on the client.

Installation

Install the package from the public npm registry with your package manager:

npm install @cashiaapp/pay-with-cashia
# or
pnpm add @cashiaapp/pay-with-cashia
# or
yarn add @cashiaapp/pay-with-cashia

Quick start

Add a container where the payment button should appear:

<div id="cashia-payment"></div>

Create the button in browser code:

import { createPaymentButton } from "@cashiaapp/pay-with-cashia";

const paymentButton = createPaymentButton("#cashia-payment", {
  partnerLogoUrl: "https://merchant.example/assets/logo.png",
  createSession: async () => {
    // Ask your backend to create the Cashia session so credentials stay server-side.
    const response = await fetch("/api/cashia/payment-sessions", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        orderId: "order-123",
        amount: 500,
        currency: "KES",
        phoneNumber: "0712345678",
      }),
    });

    if (!response.ok) {
      throw new Error("Unable to start the Cashia payment");
    }

    // Return the absolute hosted checkout URL for the library to open in its modal.
    const session = (await response.json()) as { url: string };
    return session.url;
  },
});

createSession may return a string or a Promise<string>. The string must be an absolute Cashia hosted checkout URL, including the session identifier supplied by Cashia. The library adds parentOrigin and partnerLogoUrl query parameters before opening the URL.

The request body above is illustrative. Build payment details from your trusted order data and follow the payment-session contract supplied during Cashia onboarding.

Backend responsibility

Your /api/cashia/payment-sessions endpoint should:

  1. Authenticate the customer and load the order from trusted server-side data.
  2. Validate the amount, currency, customer, and order status.
  3. Create a payment session with Cashia using server-side credentials.
  4. Return only the absolute hosted checkout URL needed by the library.

For example, the response consumed by createSession is:

{
  "url": "https://cashia-checkout.example/pay?sessionId=SESSION_ID"
}

The actual Cashia domain and response fields are environment-specific. Use the values provided during onboarding.

React and Next.js

Initialize the library in a client component and destroy the handle when the component unmounts. A dynamic import prevents the DOM-dependent library from being evaluated during server rendering.

"use client";

import { useEffect, useRef } from "react";
import type { PaymentButtonHandle } from "@cashiaapp/pay-with-cashia";

export function CashiaPaymentButton() {
  const containerRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    let handle: PaymentButtonHandle | undefined;
    let disposed = false;

    void import("@cashiaapp/pay-with-cashia").then(
      ({ createPaymentButton }) => {
        if (disposed || !containerRef.current) return;

        handle = createPaymentButton(containerRef.current, {
          partnerLogoUrl: "https://merchant.example/assets/logo.png",
          createSession: async () => {
            const response = await fetch("/api/cashia/payment-sessions", {
              method: "POST",
            });

            if (!response.ok) {
              throw new Error("Unable to start the Cashia payment");
            }

            const session = (await response.json()) as { url: string };
            return session.url;
          },
        });
      },
    );

    return () => {
      disposed = true;
      handle?.destroy();
    };
  }, []);

  return <div ref={containerRef} />;
}

Web Component

Register the custom element once, assign its required createSession property, and then add it to the page.

<cashia-payment-button
  id="cashia-payment"
  partner-logo-url="https://merchant.example/assets/logo.png"
></cashia-payment-button>

<script type="module">
  import { definePaymentButtonElement } from "@cashiaapp/pay-with-cashia";

  definePaymentButtonElement();

  const element = document.querySelector("#cashia-payment");
  element.createSession = async () => {
    const response = await fetch("/api/cashia/payment-sessions", {
      method: "POST",
    });

    if (!response.ok) {
      throw new Error("Unable to start the Cashia payment");
    }

    const session = await response.json();
    return session.url;
  };
</script>

definePaymentButtonElement() is safe to call more than once. Pass a custom tag name if your application requires one:

definePaymentButtonElement("merchant-cashia-payment");

Web Component attributes

| Attribute | Description | | --- | --- | | partner-logo-url | Required partner logo URL shown in the hosted checkout | | button-text | Trigger label; child text is used when this attribute is omitted | | button-class-name | Space-separated CSS classes added to the button | | logo-url | Image URL or raw SVG used as the trigger icon | | special-offer-text | Badge text displayed on the button | | button-background-color | Trigger background color | | button-text-color | Trigger text and icon color | | special-offer-background-color | Badge background color | | special-offer-text-color | Badge text color |

Configuration

PaymentButtonConfig

| Property | Type | Required | Default | Description | | --- | --- | --- | --- | --- | | createSession | () => string \| Promise<string> | Yes | - | Creates a session and returns its absolute hosted checkout URL | | partnerLogoUrl | string | Yes | - | Public partner logo URL passed to the hosted checkout | | buttonText | string | No | "Pay with Cashia" | Trigger button label | | buttonClassName | string | No | - | Space-separated CSS classes added to the trigger button | | buttonLogoUrl | string | No | Cashia logo | Image URL or raw <svg>...</svg> markup for the trigger icon | | specialOfferText | string | No | "SPECIAL OFFER" | Badge text; use an empty string to hide it in the JavaScript API | | buttonBackgroundColor | string | No | "#e01864" | Trigger background color | | buttonTextColor | string | No | "#ffffff" | Trigger foreground color | | specialOfferBackgroundColor | string | No | "#ffffff" | Badge background color | | specialOfferTextColor | string | No | "#e01864" | Badge text color |

Any valid browser CSS color can be used for the color properties.

PaymentButtonHandle

createPaymentButton returns a handle for controlling the integration:

const handle = createPaymentButton(container, config);

await handle.open();
handle.close();
handle.update({ buttonText: "Complete payment" });
handle.destroy();

| Member | Description | | --- | --- | | buttonElement | The generated HTMLButtonElement | | open() | Creates a new session and opens the modal | | close() | Closes the current modal | | update(config) | Updates appearance or session configuration at runtime | | destroy() | Closes the modal and removes the button and its listeners |

Calling open() while a session is being created or the modal is already open has no effect. The trigger button is disabled while createSession is pending.

Error handling

When a customer clicks the generated button and createSession fails, the button dispatches a payment-button-error custom event. Use it to display an error in your own interface or send the failure to monitoring.

paymentButton.buttonElement.addEventListener("payment-button-error", (event) => {
  const error = (event as CustomEvent<unknown>).detail;
  console.error("Cashia payment could not be opened", error);
});

When you call handle.open() directly, handle the rejected promise with try/catch.

Security and deployment

  • Keep Cashia credentials and authoritative payment data on your backend.
  • Use HTTPS for the host page, API endpoint, logo assets, and hosted checkout URL in production.
  • Allow the Cashia hosted checkout origin in your Content Security Policy frame-src directive.
  • Allow required logo origins in img-src if your Content Security Policy restricts images.
  • Return a newly created or still-valid session URL for each payment attempt.
  • Treat payment completion as authoritative only after server-side verification using the Cashia integration supplied during onboarding. Closing the modal is not proof of payment.

The library validates modal close messages against the hosted checkout URL's origin. The hosted checkout closes the modal with:

window.parent.postMessage(
  { type: "PAYMENT_BUTTON_CLOSE" },
  new URLSearchParams(window.location.search).get("parentOrigin"),
);

Troubleshooting

The package cannot be installed

Confirm that your package manager can access https://registry.npmjs.org. Remove any .npmrc rule that maps the @cashiaapp scope to a private registry.

The button does not appear

Ensure the container exists before calling createPaymentButton. In an SSR framework, initialize the library only in browser code.

The modal does not open

Listen for payment-button-error, check the session endpoint response, and confirm that createSession returns a valid absolute URL rather than a relative path.

The iframe is blocked

Check the browser console and your Content Security Policy. The Cashia checkout origin must be allowed by frame-src, and your server must not apply a conflicting iframe policy to the hosted checkout.

Package exports

import {
  createPaymentButton,
  definePaymentButtonElement,
  PaymentButtonElement,
} from "@cashiaapp/pay-with-cashia";

import type {
  CloseMessage,
  CreatePaymentSession,
  PaymentButtonAppearance,
  PaymentButtonConfig,
  PaymentButtonHandle,
} from "@cashiaapp/pay-with-cashia";

Repository development

This repository is a pnpm monorepo:

| Path | Purpose | | --- | --- | | packages/pay-with-cashia | Published library | | examples/host-app | Next.js integration example |

From the repository root:

pnpm install
pnpm build
pnpm dev:package
pnpm dev:host

Support

Contact your Cashia integration representative for credentials, environment URLs, payment-session API details, and production onboarding support.

License

MIT