npm.io
0.1.0 • Published yesterday

@meru.app/checkout-react

Licence
MIT
Version
0.1.0
Deps
0
Size
55 kB
Vulns
0
Weekly
0

@meru.app/checkout-react

React components to embed Meru Checkout (crypto exchanges + QR Bolivia) into any React app.

Security: your secret key (sk_live_…) stays on your backend. Create the checkout session server-side, then pass the returned session id/url to these client components. The key never touches the browser.

Install

npm install @meru.app/checkout-react
# react >= 17 is a peer dependency

1. Create a session on your backend

// your server
const res = await fetch('https://checkout-api.meru.com/v1/checkouts', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.MERU_SECRET_KEY}`, // sk_live_…
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ amountFiat: 50, reference: 'order_123' }),
});
const session = await res.json(); // { id, url, ... }
// send session.id (or session.url) to your frontend

2a. Embed it (modal)

import { useState } from 'react';
import { MeruCheckout } from '@meru.app/checkout-react';

export function PayButton({ checkoutId }: { checkoutId: string }) {
  const [open, setOpen] = useState(false);
  return (
    <>
      <button onClick={() => setOpen(true)}>Pay with crypto</button>
      {open && (
        <MeruCheckout
          checkoutId={checkoutId}
          display="modal"
          onSuccess={(m) => console.log('paid', m.reference, m.txHash)}
          onCancel={() => console.log('canceled')}
          onClose={() => setOpen(false)}
        />
      )}
    </>
  );
}

Or render it inline:

<MeruCheckout checkoutId={checkoutId} display="inline" height={680} />

2b. Or redirect to the hosted page

import { redirectToCheckout } from '@meru.app/checkout-react';

<button onClick={() => redirectToCheckout({ checkoutId })}>Checkout</button>;

3. (optional) Reconcile status on the client

import { useCheckoutStatus } from '@meru.app/checkout-react';

const { status, isSettled } = useCheckoutStatus(checkoutId);
// 'created' | 'pending' | 'processing' | 'succeeded' | 'failed' | 'expired'

Always confirm succeeded server-side (GET /checkouts/:id) before fulfilling anything of value — the client signals are for UX.

<MeruCheckout> props

Prop Type Default
checkoutId string Session id (provide this or url).
url string Full session URL.
baseUrl string https://checkout.meru.com Hosted checkout origin.
display 'modal' | 'inline' 'modal'
height number | string 640 Inline height.
autoClose boolean true Close modal on success/cancel.
onReady / onProcessing / onSuccess / onFailed / onCancel (m: CheckoutMessage) => void Lifecycle events.
onMessage (m: CheckoutMessage) => void Catch-all.
onClose () => void Modal closed.
CheckoutMessage
{
  source: 'meru-checkout';
  type: 'ready' | 'processing' | 'success' | 'failed' | 'cancel';
  checkoutId?: string;
  status?: string;
  reference?: string | null;
  amount?: string;
  currency?: string;
  txHash?: string | null;
}

Self-hosted / sandbox

Point at a different deployment with baseUrl (component / redirect) and apiUrl (status hook):

<MeruCheckout checkoutId={id} baseUrl="https://checkout.sandbox.meru.com" />
useCheckoutStatus(id, { apiUrl: 'https://checkout-api.sandbox.meru.com' });

Keywords