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

payluk-escrow-inline-checkout

v0.3.0

Published

TypeScript escrow checkout wrapper with built-in script loader and session creation, ready for React/Next.js

Downloads

162

Readme

Escrow Checkout JS/TS SDK

A lightweight client SDK that initializes your checkout configuration, creates a session, and launches the escrow checkout widget. Includes a React hook for easy integration in React apps.

  • Zero manual script tags: the widget script is loaded automatically.
  • Promise-based API.
  • First-class TypeScript types.
  • Optional React hook with loading/error state.
  • Multi-escrow support: pay for multiple escrows in a single checkout session.

Installation

npm i payluk-escrow-inline-checkout

Quick Start (Vanilla JS/TS)

// app.ts
import { initEscrowCheckout, pay } from 'payluk-escrow-inline-checkout';

// 1) Initialize once at app startup
initEscrowCheckout({
  publicKey: '<YOUR_PUBLISHABLE_KEY>' // publishable key only
});

// 2) Trigger a payment flow (e.g., on a button click)
async function onPayClick() {
  try {
    await pay({
      paymentToken: '<PAYMENT_TOKEN>',
      reference: '<REFERENCE_ID>',
      redirectUrl: 'https://your-app.example.com/checkout/complete',
      logoUrl: 'https://mediacloud.me/media/W8HU9TK245QF528ZULCFSJXX2SBBLT.jpg', // optional
      brand: 'YourBrand', // optional
      customerId: 'YourBrand', // optional only for merchants using customer vaulting
      callback: (result) => {
        console.log('Checkout result:', result);
      },
      onClose: () => {
        console.log('Widget closed');
      }
    });
  } catch (err) {
    console.error('Payment failed:', err);
  }
}

Inline Usage

<!DOCTYPE html>
<html lang="en">

<head>
  <title>Checkout Demo</title>
</head>

<body>
  <h1>Checkout Demo</h1>
  <!-- HTML -->
  <script src="https://checkout.payluk.ng/escrow-checkout.min.js"></script>
  <button id="pay">Pay via Wallet(Business) or Debit Card (Merchant)</button>
  <script>
    const PUBLISHABLE_KEY = 'pk_live_f1yCEbpo980rDMWUAMH0Ho0NC7gzkqSr'; // Public Key
    let navigated = false;


    async function openEscrowCheckout() {
      const baseUrl = window.EscrowCheckout.baseUrl
      const resp = await fetch(`${baseUrl}/v1/checkout/session`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          paymentToken: 'PY_vevIhjtQ3000',
          reference: "Reference",
          publicKey: PUBLISHABLE_KEY,
          redirectUrl: 'http://localhost:63342/payluk-inlinejs/thank-you.html',
          customerId: '6933b6353e4615c1cabdd1d9' // Optional: For merchant business only
        }),
      });
      if (!resp.ok) {
        const err = await resp.json().catch(() => ({}));
        return alert(err.message || 'Failed to create session');
      }

      const { session } = await resp.json();

      // Initialize the widget
      EscrowCheckout({
        session,
        logoUrl: "https://mediacloud.me/media/W8HU9TK245QF528ZULCFSJXX2SBBLT.jpg",
        brand: "Business Name",
        publicKey: PUBLISHABLE_KEY,
        customerId: '6933b6353e4615c1cabdd1d9' // Optional: For merchant business only
        callback: ({ paymentId }) => {
          console.log('Payment token received', paymentId);
          navigated = true;
          const url = `/payluk-inlinejs/thank-you.html?paymentId=${encodeURIComponent(paymentId)}`;
          window.location.replace(url);
        },
        onClose: function () {
          console.log('Checkout closed');
        },
      });
    }

    document.getElementById('pay').addEventListener('click', openEscrowCheckout);
  </script>
</body>

</html>

React Usage

import { initEscrowCheckout } from 'payluk-escrow-inline-checkout';

export default function ClientEscrowInit() {
    useEffect(() => {
        initEscrowCheckout({
            publicKey: 'pk_live_*************************',
        });
    }, []);
    return null;
}
export default function RootLayout({ children }: Readonly<{children: React.ReactNode}>) {
    return (
        <html lang="en">
            <body className={`${geistSans.variable} ${geistMono.variable} antialiased`}>
                <ClientEscrowInit />
                {children}
            </body>
        </html>
    );
}
import React from 'react';
import { useEscrowCheckout } from 'payluk-escrow-inline-checkout/react';

export function CheckoutButton() {
  const { pay } = useEscrowCheckout();

  const handleClick = async () => {
    try {
      await pay({
        paymentToken: '<PAYMENT_TOKEN>',
        reference: '<REFERENCE_ID>',
        redirectUrl: 'https://your-app.example.com/checkout/complete',
        logoUrl: 'https://mediacloud.me/media/W8HU9TK245QF528ZULCFSJXX2SBBLT.jpg',
        brand: 'YourBrand',
        extra: { theme: 'light' },
        customerId: 'YourBrand', // optional only for merchants using customer vaulting
        callback: (result) => console.log(result)
      });
    } catch {
      // error is also exposed via `error` state
    }
  };

  return (
    <button onClick={handleClick}>
      Pay Now
    </button>
  );
}

Note: In React apps, call initEscrowCheckout(...) once in your app bootstrap (e.g., in the root component or an app initializer). The hook uses that configuration.

Important:

  • Only use publishable keys in the browser. Keep any secret keys on your server.
  • Validate inputs on your backend and return the required session payload.

Multi-Escrow Payments

You can now pay for multiple escrows in a single checkout session by passing an array of payment tokens. This is useful when a customer wants to pay for multiple items or services at once.

Requirements

  • All escrows must belong to the same merchant
  • All escrows must be in PENDING status
  • If using merchant escrows, a customerId is required
  • The total amount from all escrows will be charged in a single transaction

Vanilla JS/TS Example

import { initEscrowCheckout, pay } from 'payluk-escrow-inline-checkout';

// Initialize once
initEscrowCheckout({
  publicKey: '<YOUR_PUBLISHABLE_KEY>'
});

// Pay for multiple escrows
async function onPayMultipleClick() {
  try {
    await pay({
      // Pass an array of payment tokens
      paymentToken: ['TOKEN_1', 'TOKEN_2', 'TOKEN_3'],
      reference: '<REFERENCE_ID>',
      redirectUrl: 'https://your-app.example.com/checkout/complete',
      logoUrl: 'https://mediacloud.me/media/W8HU9TK245QF528ZULCFSJXX2SBBLT.jpg',
      brand: 'YourBrand',
      customerId: 'customer_123', // Required for merchant escrows
      callback: (result) => {
        // result.paymentId will contain comma-separated IDs: "id1,id2,id3"
        // result.reference will contain unique refs: "REF_1,REF_2,REF_3"
        console.log('Multi-escrow checkout result:', result);
      },
      onClose: () => {
        console.log('Widget closed');
      }
    });
  } catch (err) {
    console.error('Payment failed:', err);
  }
}

React Example

import React from 'react';
import { useEscrowCheckout } from 'payluk-escrow-inline-checkout/react';

export function MultiEscrowCheckoutButton() {
  const { pay } = useEscrowCheckout();

  const handleClick = async () => {
    try {
      await pay({
        // Array of payment tokens for multi-escrow checkout
        paymentToken: ['TOKEN_1', 'TOKEN_2', 'TOKEN_3'],
        reference: '<REFERENCE_ID>',
        redirectUrl: 'https://your-app.example.com/checkout/complete',
        customerId: 'customer_123',
        callback: (result) => {
          console.log('Payment successful:', result);
        }
      });
    } catch (err) {
      console.error('Payment failed:', err);
    }
  };

  return (
    <button onClick={handleClick}>
      Pay for Multiple Items
    </button>
  );
}

How It Works

  1. Individual Processing: Each escrow is processed individually with its own payment intent
  2. Aggregated Total: The checkout widget displays the total amount from all escrows
  3. Unique References: Multi-payments generate unique references for each escrow (e.g., REF_1, REF_2, REF_3)
  4. Single Transaction: The customer completes one payment for all escrows combined
  5. Backward Compatible: Single payment tokens (strings) still work exactly as before

Response Format

When using multi-escrow payments, the callback receives:

{
  paymentId: "token1,token2,token3",  // Comma-separated escrow IDs
  reference: "REF_1,REF_2,REF_3"      // Comma-separated unique references
}

API

initEscrowCheckout(config)

Initializes the SDK. Must be called before any pay(...).

Required:

  • publicKey: string — publishable key only

Advanced (optional):

  • scriptUrlOverride?: string — custom widget script URL
  • globalName?: string — custom global widget function name
  • crossOrigin?: '' | 'anonymous' | 'use-credentials' — script tag crossOrigin

Example:

import { initEscrowCheckout } from 'payluk-escrow-inline-checkout';

initEscrowCheckout({
  publicKey: '<YOUR_PUBLISHABLE_KEY>'
});

pay(input): Promise<void>

Creates a checkout session via your backend and opens the widget.

Required:

  • paymentToken: string | string[] — single payment token or array of tokens for multi-escrow checkout
  • reference: string
  • redirectUrl: string

Optional:

  • logoUrl?: string
  • customerId?: string — required for merchant escrows, optional for business escrows
  • brand?: string
  • callback?: (result: unknown) => void
  • onClose?: () => void
  • extra?: Record<string, unknown> — additional widget configuration

Returns:

  • Promise<void> that resolves when the widget is opened (and rejects on errors).

Multi-Escrow Notes:

  • When using an array of payment tokens, all escrows must belong to the same merchant
  • The checkout widget will display the aggregated total amount
  • Each escrow is processed individually with its own payment intent
  • Empty arrays or arrays containing empty strings will be rejected

useEscrowCheckout(): { ready, loading, error, pay }

React hook that exposes:

  • ready: boolean — becomes true after a successful load/pay attempt
  • loading: boolean — true while pay is running
  • error: Error | null — last error encountered
  • pay: same function as pay(...)

Import:

import { useEscrowCheckout } from 'payluk-escrow-inline-checkout/react';

Framework and SSR Notes

  • Browser-only: pay(...) and the widget require window. Avoid calling them during server-side rendering.
  • Initialize on the client: If using frameworks like Next.js, call initEscrowCheckout(...) in a client component or in an effect.
  • Preloading: The hook marks ready after the first successful pay. If you need earlier preloading, you can trigger a preparatory flow (depending on your setup).

Error Handling

Common issues:

  • Not initialized: Ensure initEscrowCheckout({ publicKey }) is called before pay(...).
  • Browser-only: Do not call pay(...) on the server.
  • Network/API errors: If the session endpoint fails, pay(...) will reject with an EscrowCheckoutError that includes a code, optional HTTP status, and details.

EscrowCheckoutError codes:

  • NOT_INITIALIZED
  • BROWSER_ONLY
  • INVALID_INPUT
  • WIDGET_LOAD
  • NETWORK
  • SESSION_CREATE
  • SESSION_RESPONSE

You can import the error class if you want stricter checks in TypeScript:

import { EscrowCheckoutError } from 'payluk-escrow-inline-checkout';

Example:

try {
  await pay({ /* ... */ });
} catch (err) {
  if (err instanceof EscrowCheckoutError) {
    console.error(err.code, err.status, err.message);
    alert(err.message);
  } else {
    alert('Checkout failed');
  }
}

Security

  • Use only publishable keys in the client.
  • Keep any secret or private keys on your server.
  • Validate and authorize requests on your backend before creating sessions.

Types

This package ships with TypeScript types. No additional type packages are required.

Contributing

  • Install dependencies: npm install
  • Build: npm run build
  • Lint/Test: add scripts as needed for your project

License

MIT (or your chosen license)