@meru.app/checkout-react
v0.1.0
Published
React components to embed Meru Checkout (crypto exchanges + QR Bolivia) into any React app.
Maintainers
Readme
@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 dependency1. 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 frontend2a. 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
succeededserver-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' });