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

@paylayer/react

v0.1.2

Published

React SDK for PayLayer - Build billing once. Switch providers anytime.

Downloads

307

Readme

💳 @paylayer/react

Build billing once. Switch providers anytime.

npm version License: MIT React Version

The official React SDK for PayLayer. Simple, type-safe hooks for integrating payments into your React application.

FeaturesQuick StartHooksAPI ReferenceConfiguration


What is PayLayer React?

PayLayer React provides React hooks and components that make it easy to integrate payments into your React application. Write your billing logic once, switch providers anytime.

Key Benefits:

  • Simple Hooks - useCharge, useSubscription, useBillingPortal for all payment operations
  • Provider Flexibility - Switch between Stripe, Paddle, PayPal, Lemon Squeezy, and Polar without code changes
  • Type Safety - Full TypeScript support with autocomplete
  • SSR Ready - Works with Next.js, Remix, and other React frameworks

💡 Looking for Node.js/Backend support? Check out @paylayer/core - the server-side SDK for PayLayer that powers this React SDK.


📋 Table of Contents


✨ Features

| Feature | Description | | ------------------------ | ------------------------------------------------------- | | 💰 One-time payments | useCharge hook for simple payment processing | | 🔄 Subscriptions | useSubscription hook for recurring billing management | | 🏢 Billing portal | useBillingPortal hook for customer self-service | | 🔀 Provider-agnostic | Switch providers without changing your code | | 📘 TypeScript | Full type safety with autocomplete | | ⚡ SSR Ready | Works with Next.js, Remix, and other React frameworks | | 🎣 Simple Hooks | Clean, intuitive API for all payment operations |


📦 Installation

npm install @paylayer/react

🚀 Quick Start

Step 1: Configure PayLayer

Load your configuration using setConfig() at the top level of your app, in the same place where you use PayLayerProvider:

import {
  PayLayerProvider,
  setConfig,
  type PayLayerConfig,
} from "@paylayer/react";

const config: PayLayerConfig = {
  provider: "stripe",
  environment: "sandbox",
  stripe: {
    secretKey: process.env.STRIPE_SECRET_KEY!,
  },
};

setConfig(config);

function App() {
  return (
    <PayLayerProvider>
      <YourApp />
    </PayLayerProvider>
  );
}

Important: setConfig() must be called at the top level of your app, in the same file where you render PayLayerProvider. It cannot be called inside components or hooks.

Step 2: Use the Hooks

import { useCharge } from "@paylayer/react";

function CheckoutButton() {
  const { charge, loading } = useCharge();

  const handlePayment = async () => {
    const result = await charge({
      amount: 29.99,
      currency: "USD",
      email: "[email protected]",
    });

    if (result.url) {
      window.location.href = result.url;
    }
  };

  return (
    <button onClick={handlePayment} disabled={loading}>
      {loading ? "Processing..." : "Pay $29.99"}
    </button>
  );
}

📝 Configuration

Using setConfig()

Load your PayLayer configuration by calling setConfig() with a configuration object. Important: setConfig() must be called at the top level of your app, in the same place where you render PayLayerProvider. It cannot be called inside components, hooks, or conditional blocks.

You can structure and load your config however you prefer - from a file, inline, or dynamically.

Basic Example (Inline):

import { setConfig, type PayLayerConfig } from "@paylayer/react";

const config: PayLayerConfig = {
  provider: "stripe",
  environment: "sandbox",
  stripe: {
    secretKey: process.env.STRIPE_SECRET_KEY!,
    webhookSecret: process.env.STRIPE_WEBHOOK_SECRET,
  },
};

setConfig(config);

Loading from a File (Recommended):

You can organize your config in a separate file. We recommend placing it in your project root, but you can put it anywhere you prefer:

import type { PayLayerConfig } from "@paylayer/react";

const config: PayLayerConfig = {
  provider: "stripe",
  environment: "sandbox",
  stripe: {
    secretKey: process.env.STRIPE_SECRET_KEY!,
    webhookSecret: process.env.STRIPE_WEBHOOK_SECRET,
  },
};

export default config;

Then load it at the top level of your app (in the same file where you use PayLayerProvider):

import { PayLayerProvider, setConfig } from "@paylayer/react";
import config from "./paylayer.config.ts";

setConfig(config);

function App() {
  return (
    <PayLayerProvider>
      <YourApp />
    </PayLayerProvider>
  );
}

Complete Example (All Providers):

import { setConfig, type PayLayerConfig } from "@paylayer/react";

const config: PayLayerConfig = {
  provider: "stripe",
  environment: "sandbox",
  stripe: {
    secretKey: process.env.STRIPE_SECRET_KEY!,
    webhookSecret: process.env.STRIPE_WEBHOOK_SECRET,
    checkoutSuccessUrl: "https://yourapp.com/success",
    checkoutCancelUrl: "https://yourapp.com/cancel",
    portalReturnUrl: "https://yourapp.com",
  },
  paddle: {
    apiKey: process.env.PADDLE_API_KEY!,
    webhookSecret: process.env.PADDLE_WEBHOOK_SECRET,
    sandbox: true,
  },
  paypal: {
    clientId: process.env.PAYPAL_CLIENT_ID!,
    clientSecret: process.env.PAYPAL_CLIENT_SECRET!,
    webhookId: process.env.PAYPAL_WEBHOOK_ID,
    sandbox: true,
  },
  lemonsqueezy: {
    apiKey: process.env.LEMONSQUEEZY_API_KEY!,
    storeId: process.env.LEMONSQUEEZY_STORE_ID!,
    webhookSecret: process.env.LEMONSQUEEZY_WEBHOOK_SECRET,
    testMode: true,
  },
  polar: {
    apiKey: process.env.POLAR_API_KEY!,
    webhookSecret: process.env.POLAR_WEBHOOK_SECRET,
    sandbox: true,
  },
};

setConfig(config);

Important: setConfig() must be called at the top level of your app, in the same file where you render PayLayerProvider. It must be called before PayLayerProvider is rendered, and cannot be called inside components, hooks, or conditional blocks.


🎣 Hooks

useCharge

One-time payment hook.

Returns:

| Property | Type | Description | | ---------------------------- | ---------------------- | ------------------------------ | | charge(input: ChargeInput) | function | Execute payment | | loading | boolean | Loading state | | error | Error \| null | Error object (if any) | | payment | ChargeResult \| null | Last successful payment result |

Parameters:

| Parameter | Type | Required | Description | | ------------ | -------- | -------- | --------------------------------------------------------------- | | amount | number | ✅* | Payment amount (e.g., 29.99) - See provider support below | | priceId | string | ✅* | Provider-specific price ID - Recommended for most providers | | productId | string | ✅* | Provider-specific product ID - Works with all providers | | currency | string | ✅ | ISO 4217 currency code (e.g., USD) | | email | string | ❌ | Customer email address | | successUrl | string | ❌ | URL to redirect after successful payment | | cancelUrl | string | ❌ | URL to redirect if payment is cancelled | | metadata | object | ❌ | Additional metadata to attach to the payment |

*Either amount, priceId, or productId must be provided.

Setting the Payment Amount:

You can specify the payment amount in three ways:

  1. amount - Direct amount value (e.g., 29.99)
  2. priceId - Provider-specific price ID (recommended for most providers)
  3. productId - Provider-specific product ID (works with all providers)

Provider Support:

| Provider | amount | priceId | productId | Recommendation | | ----------------- | -------- | --------- | ----------- | ---------------------------- | | Stripe | ✅ | ✅ | ✅ | Use amount for Stripe | | Paddle | ❌ | ✅ | ✅ | Use priceId or productId | | PayPal | ✅ | ❌ | ✅ | Use amount or productId | | Lemon Squeezy | ✅* | ✅ | ✅ | Use priceId or productId | | Polar | ❌ | ❌ | ✅ | Use productId only |

*Lemon Squeezy supports amount with custom_price, but requires a variant ID from environment or priceId.

Best Practices:

  • For Stripe: You can use amount directly - it's the simplest option
  • For other providers: Use priceId or productId for better compatibility
  • For maximum compatibility: Use productId - it works with all providers

Examples:

Using amount (Stripe, PayPal, Lemon Squeezy):

import { useCharge } from "@paylayer/react";

function CheckoutButton() {
  const { charge, loading } = useCharge();

  const handlePayment = async () => {
    const result = await charge({
      amount: 29.99,
      currency: "USD",
      email: "[email protected]",
    });

    if (result.url) {
      window.location.href = result.url;
    }
  };

  return (
    <button onClick={handlePayment} disabled={loading}>
      {loading ? "Processing..." : "Pay $29.99"}
    </button>
  );
}

Using priceId (Recommended for most providers):

const result = await charge({
  priceId: "price_1234567890",
  currency: "USD",
  email: "[email protected]",
});

Using productId (Works with all providers):

const result = await charge({
  productId: "prod_1234567890",
  currency: "USD",
  email: "[email protected]",
});

useSubscription

Subscription management hook.

Returns:

| Property | Type | Description | | ---------------------------------- | ---------------------------- | --------------------- | | subscribe(input: SubscribeInput) | function | Create subscription | | cancel(subscriptionId: string) | function | Cancel subscription | | pause(subscriptionId: string) | function | Pause subscription | | resume(subscriptionId: string) | function | Resume subscription | | loading | boolean | Loading state | | error | Error \| null | Error object (if any) | | subscription | SubscriptionResult \| null | Current subscription |

Subscribe Parameters:

| Parameter | Type | Required | Description | | ---------- | -------- | -------- | ------------------------------------ | | plan | string | ✅ | Plan identifier | | currency | string | ✅ | ISO 4217 currency code (e.g., USD) | | email | string | ❌ | Customer email address |

Example:

import { useSubscription } from "@paylayer/react";

function SubscriptionButton() {
  const { subscribe, cancel, pause, resume, loading, subscription } =
    useSubscription();

  const handleSubscribe = async () => {
    try {
      const result = await subscribe({
        plan: "pro-monthly",
        currency: "USD",
        email: "[email protected]",
      });

      if (result.url) {
        window.location.href = result.url;
      }
    } catch (err) {
      console.error("Subscription failed:", err);
    }
  };

  return (
    <div>
      <button onClick={handleSubscribe} disabled={loading}>
        Subscribe
      </button>
      {subscription && (
        <div>
          <p>Status: {subscription.status}</p>
          <button onClick={() => cancel(subscription.id)}>Cancel</button>
        </div>
      )}
    </div>
  );
}

useBillingPortal

Billing portal access hook.

Returns:

| Property | Type | Description | | -------------------------------- | ---------- | ------------------------------------ | | open(input: { email: string }) | function | Open billing portal (auto-redirects) | | loading | boolean | Loading state |

Parameters:

| Parameter | Type | Required | Description | | --------- | -------- | -------- | ---------------------- | | email | string | ✅ | Customer email address |

Example:

import { useBillingPortal } from "@paylayer/react";

function BillingPortalButton() {
  const { open, loading } = useBillingPortal();

  const handleOpenPortal = async () => {
    try {
      await open({ email: "[email protected]" });
    } catch (err) {
      console.error("Failed to open portal:", err);
    }
  };

  return (
    <button onClick={handleOpenPortal} disabled={loading}>
      {loading ? "Opening..." : "Manage Billing"}
    </button>
  );
}

What customers can do:

  • Update payment methods
  • View billing history
  • Cancel subscriptions
  • Update billing information
  • Download invoices

📘 TypeScript Support

The SDK is written in TypeScript and provides full type definitions:

import { useCharge } from "@paylayer/react";
import type { ChargeResult, ChargeInput } from "@paylayer/react";

const { charge } = useCharge();

const result: ChargeResult = await charge({
  amount: 29.99,
  currency: "USD",
  email: "[email protected]",
});

Available Types

All types are exported from @paylayer/react:

import type {
  UseChargeReturn,
  UseSubscriptionReturn,
  UseBillingPortalReturn,
  ChargeInput,
  ChargeResult,
  SubscribeInput,
  SubscriptionResult,
  ProviderName,
  ProviderConfig,
  PayLayerConfig,
  CurrencyCode,
  CustomerInfo,
  Provider,
} from "@paylayer/react";

import { Currency } from "@paylayer/react";

Currency Enum

The SDK includes a comprehensive Currency enum with 150+ currencies for type safety and autocomplete:

import { useCharge, Currency } from "@paylayer/react";

const { charge } = useCharge();

const result = await charge({
  amount: 29.99,
  currency: Currency.USD, // TypeScript autocomplete available
  email: "[email protected]",
});

Common Currencies:

  • Currency.USD, Currency.EUR, Currency.GBP, Currency.JPY
  • Currency.AUD, Currency.CAD, Currency.CHF, Currency.CNY
  • Currency.HKD, Currency.NZD, Currency.SGD

For a complete list, use your IDE's autocomplete or refer to the TypeScript definitions.


🔧 API Reference

setConfig

Loads the PayLayer configuration.

Parameters:

| Parameter | Type | Required | Description | | --------- | ---------------- | -------- | --------------------------------- | | config | PayLayerConfig | ✅ | The PayLayer configuration object |

When to use:

  • Call setConfig() at the top level of your app, in the same file where you render PayLayerProvider
  • Must be called before rendering PayLayerProvider
  • Must be called outside of components, hooks, or conditional blocks
  • Use when you want to configure PayLayer programmatically instead of using environment variables

Example:

import { setConfig, type PayLayerConfig } from "@paylayer/react";

const config: PayLayerConfig = {
  provider: "stripe",
  environment: "sandbox",
  stripe: {
    secretKey: process.env.STRIPE_SECRET_KEY!,
  },
};

setConfig(config);

PayLayerProvider

Root provider component that provides PayLayer context to your React tree.

Props:

| Property | Type | Required | Description | | ---------- | ----------- | -------- | -------------- | | children | ReactNode | ✅ | React children |

Configuration Priority:

  1. Config loaded via setConfig()
  2. Environment variables (if setConfig() was not called)

Example:

import { PayLayerProvider } from "@paylayer/react";

function App() {
  return (
    <PayLayerProvider>
      <YourApp />
    </PayLayerProvider>
  );
}

🔄 Provider Abstraction

PayLayer abstracts away provider-specific details. Switch between Stripe, Paddle, PayPal, Lemon Squeezy, or Polar by changing your configuration - no code changes needed.

| Provider | Status | Features | | ----------------- | ------ | ----------------------------------------------- | | Stripe | ✅ | Payments, subscriptions, and billing portal | | Paddle | ✅ | Merchant of record, subscriptions, and checkout | | PayPal | ✅ | Payments and subscriptions | | Lemon Squeezy | ✅ | Checkout and subscriptions | | Polar.sh | ✅ | Billing infrastructure and subscriptions |

All providers are fully implemented with proper error handling and API integration.

Example:

const config: PayLayerConfig = {
  provider: "stripe", // or "paddle", "paypal", "lemonsqueezy", "polar"
};

🔒 Security

Important: All API keys and secrets should be stored on your backend. The React SDK makes HTTP requests to your API endpoints. Never expose payment provider credentials in your frontend code.


❓ Troubleshooting

Config Not Loading

If you're getting errors about the provider not being configured:

  1. Make sure you're calling setConfig() at the top level before rendering PayLayerProvider:

    setConfig(config);
    function App() {
      return <PayLayerProvider>...</PayLayerProvider>;
    }
  2. Verify your config structure - Ensure your config matches the PayLayerConfig type:

    import type { PayLayerConfig } from "@paylayer/react";
    
    const config: PayLayerConfig = {
      provider: "stripe",
    };

Using Environment Variables Instead

If you prefer to use environment variables instead of calling setConfig(), simply don't call setConfig(). PayLayer will automatically read from environment variables:

# .env
PAYLAYER_PROVIDER=stripe
STRIPE_SECRET_KEY=sk_test_...

No setConfig() call needed - just use <PayLayerProvider> directly.


📚 Examples

Next.js Quickstarter

A beautiful, production-ready Next.js starter template with PayLayer integration:

  • PayLayer Next.js Quickstarter - Complete Next.js 16 application with:
    • Beautiful, animated UI with Tailwind CSS
    • Ready-to-use charge and subscription flows
    • Webhook handling
    • TypeScript support
    • Production-ready setup

Other Examples

See the examples directory for additional integration examples.


🔗 Related Packages

  • @paylayer/core - The server-side Node.js SDK for PayLayer. Use this for backend payment processing, webhooks, and server-side operations.

📄 License

MIT


Made with ❤️ by PayLayer