Skip to content

React SDK

React components and hooks for integrating ZevPay Checkout. Wraps the Inline Checkout SDK with idiomatic React APIs.

Installation

bash
npm install @zevpay/react @zevpay/inline

Requires React 18 or later.

Quick start

Button component

The simplest way to add checkout — renders a button that opens the payment modal on click:

tsx
import { ZevPayButton } from '@zevpay/react';

function CheckoutPage() {
  return (
    <ZevPayButton
      apiKey="pk_test_your_public_key"
      email="customer@example.com"
      amount={500000} // ₦5,000 in kobo
      onSuccess={(reference) => {
        console.log('Payment successful:', reference);
        // Verify payment on your server
      }}
    >
      Pay ₦5,000
    </ZevPayButton>
  );
}

Hook

For custom UI — call openCheckout() from any event handler:

tsx
import { useZevPayCheckout } from '@zevpay/react';

function CheckoutPage() {
  const { openCheckout } = useZevPayCheckout({
    apiKey: 'pk_test_your_public_key',
    onSuccess: (reference) => {
      console.log('Paid:', reference);
    },
    onClose: () => {
      console.log('Modal closed');
    },
  });

  return (
    <button onClick={() => openCheckout({
      email: 'customer@example.com',
      amount: 500000,
      reference: 'ORDER-123',
      firstName: 'John',
      lastName: 'Doe',
    })}>
      Pay ₦5,000
    </button>
  );
}

Provider (shared API key)

Wrap your app in <ZevPayProvider> to avoid repeating apiKey on every component:

tsx
import { ZevPayProvider, ZevPayButton } from '@zevpay/react';

function App() {
  return (
    <ZevPayProvider apiKey="pk_test_your_public_key">
      <StorePage />
    </ZevPayProvider>
  );
}

function StorePage() {
  // No apiKey needed — inherited from provider
  return (
    <ZevPayButton email="customer@example.com" amount={500000}>
      Pay ₦5,000
    </ZevPayButton>
  );
}

<ZevPayButton />

A button that opens ZevPay Checkout on click.

Props

PropTypeRequiredDescription
apiKeystringYes*Your public API key (pk_live_* or pk_test_*)
emailstringYesCustomer email address
amountnumberYesAmount in kobo (₦1 = 100 kobo)
currencystringNoCurrency code. Default: "NGN"
referencestringNoYour unique transaction reference
firstNamestringNoCustomer first name
lastNamestringNoCustomer last name
metadataobjectNoCustom metadata attached to the transaction
paymentMethods"all" | string[]NoPayment methods to show
onSuccess(reference: string) => voidNoCalled when payment is confirmed
onClose() => voidNoCalled when the modal closes
onError(error: Error) => voidNoCalled on error
onFailure(error?: Error) => voidNoCalled when payment fails
onExpired() => voidNoCalled when session expires
onInitialize() => voidNoCalled when session initializes
childrenReactNodeNoButton content. Default: "Pay Now"
classNamestringNoCSS class name for the button
disabledbooleanNoWhether the button is disabled

*Required unless <ZevPayProvider> is used.

Examples

tsx
// Minimal
<ZevPayButton
  apiKey="pk_test_xxx"
  email="customer@example.com"
  amount={500000}
  onSuccess={(ref) => verifyPayment(ref)}
>
  Pay
</ZevPayButton>

// With all options
<ZevPayButton
  apiKey="pk_test_xxx"
  email="customer@example.com"
  amount={500000}
  currency="NGN"
  reference="ORDER-123"
  firstName="John"
  lastName="Doe"
  metadata={{ orderId: '123' }}
  paymentMethods={['bank', 'payid']}
  className="btn btn-primary"
  onSuccess={(ref) => verifyPayment(ref)}
  onClose={() => console.log('closed')}
  onError={(err) => console.error(err)}
>
  Pay ₦5,000
</ZevPayButton>

useZevPayCheckout(config)

Hook for imperative checkout control.

Config

Shared options that persist across calls:

OptionTypeDescription
apiKeystringPublic API key (or use <ZevPayProvider>)
currencystringCurrency code
paymentMethods"all" | string[]Payment methods to enable
onSuccessfunctionSuccess callback
onClosefunctionClose callback
onErrorfunctionError callback
onFailurefunctionFailure callback
onExpiredfunctionExpiry callback
onInitializefunctionInit callback

Return value

PropertyTypeDescription
openCheckout(params) => voidOpens the checkout modal

openCheckout params

Per-call parameters:

ParamTypeRequiredDescription
emailstringYesCustomer email
amountnumberYesAmount in kobo
referencestringNoTransaction reference
firstNamestringNoCustomer first name
lastNamestringNoCustomer last name
metadataobjectNoCustom metadata

Example

tsx
function DonationPage() {
  const [email, setEmail] = useState('');
  const [amount, setAmount] = useState(0);

  const { openCheckout } = useZevPayCheckout({
    apiKey: 'pk_test_xxx',
    onSuccess: (reference) => {
      fetch('/api/verify', {
        method: 'POST',
        body: JSON.stringify({ reference }),
      });
    },
  });

  return (
    <form onSubmit={(e) => {
      e.preventDefault();
      openCheckout({ email, amount: amount * 100 });
    }}>
      <input
        type="email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        placeholder="Your email"
      />
      <input
        type="number"
        value={amount}
        onChange={(e) => setAmount(Number(e.target.value))}
        placeholder="Amount in Naira"
      />
      <button type="submit">Donate</button>
    </form>
  );
}

<ZevPayProvider>

Context provider for sharing configuration across components.

PropTypeRequiredDescription
apiKeystringYesShared public API key
childrenReactNodeYesChild components

Both <ZevPayButton> and useZevPayCheckout() will inherit the API key from the nearest provider. A direct apiKey prop/config always takes priority over the provider.

Payment methods

tsx
// All methods (default)
<ZevPayButton paymentMethods="all" ... />

// Specific methods
<ZevPayButton paymentMethods={['bank', 'payid']} ... />

// Bank transfer only
<ZevPayButton paymentMethods={['bank']} ... />
MethodValueStatus
Bank Transfer"bank"Available
ZevPay ID"payid"Available
Card"card"Coming soon

Verify payments

Always verify server-side

Never trust the client-side onSuccess callback alone. Always verify the payment on your server.

typescript
// Server-side (Node.js)
import ZevPay from '@zevpay/node';

const zevpay = new ZevPay('sk_live_xxx');
const result = await zevpay.checkout.verify(sessionId);

if (result.status === 'completed') {
  // Payment confirmed — fulfill the order
}

TypeScript

All types are exported:

tsx
import type {
  ZevPayCheckoutOptions,
  ZevPayButtonProps,
  UseZevPayConfig,
  OpenCheckoutParams,
  UseZevPayReturn,
  PaymentMethodOption,
} from '@zevpay/react';

Error types from the inline SDK are also re-exported:

tsx
import { CheckoutError } from '@zevpay/react';

Resources

ZevPay Checkout Developer Documentation