@withlocus/checkout-react
v1.2.0
Published
Locus Checkout SDK for React
Maintainers
Readme
@withlocus/checkout-react
React SDK for integrating Locus Checkout into your application. Accept USDC payments from any wallet.
Installation
npm install @withlocus/checkout-react
# or
yarn add @withlocus/checkout-react
# or
pnpm add @withlocus/checkout-reactQuick Start
1. Create a Checkout Session (Server-side)
import type {
CreateCheckoutSessionRequest,
CreateCheckoutSessionResponse,
} from '@withlocus/checkout-react';
const body: CreateCheckoutSessionRequest = {
amount: '10.00',
description: 'Premium API Access',
webhookUrl: 'https://yourapp.com/webhooks/locus',
successUrl: 'https://yourapp.com/thank-you',
};
const response = await fetch('https://api.paywithlocus.com/api/checkout/sessions', {
method: 'POST',
headers: {
'Authorization': `Bearer ${YOUR_CLAW_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
});
const { data } = (await response.json()) as CreateCheckoutSessionResponse;
// data.id = 'sess_xxx'
// data.checkoutUrl = 'https://checkout.paywithlocus.com/sess_xxx'2. Integrate the Checkout Component (Client-side)
import { LocusCheckout } from '@withlocus/checkout-react';
function PaymentPage({ sessionId }: { sessionId: string }) {
return (
<LocusCheckout
sessionId={sessionId}
onSuccess={(data) => {
// Fires after payment is confirmed on-chain and the session
// status is set to PAID. The checkout page sends a
// `locus:checkout:success` postMessage with the payment details.
console.log('Payment successful!', data.txHash);
}}
onCancel={() => {
console.log('Payment cancelled');
}}
mode="embedded" // or "popup" or "redirect"
/>
);
}Note: You can pass the full checkout URL from the API response (e.g.
https://checkout.paywithlocus.com/sess_xxx) as thecheckoutUrlprop — the SDK automatically extracts the origin and appends/{sessionId}. Passing a base URL likehttps://checkout.paywithlocus.comalso works.
Usage Options
Embedded Mode (Default)
Renders the checkout inline in your page as an iframe.
The iframe has a minimum height of 700px and takes 100% width of its container. For best results, place the component in a container that is at least 450px wide and 700px tall:
<div style={{ maxWidth: '450px', minHeight: '700px', margin: '0 auto' }}>
<LocusCheckout
sessionId="sess_xxx"
mode="embedded"
onSuccess={handleSuccess}
/>
</div>Popup Mode
Opens the checkout in a centered popup window (450x650):
<LocusCheckout
sessionId="sess_xxx"
mode="popup"
onSuccess={handleSuccess}
onCancel={handleCancel}
/>Redirect Mode
Redirects the user to the checkout page:
<LocusCheckout
sessionId="sess_xxx"
mode="redirect"
/>Using the Hook
For more control, use the useLocusCheckout hook:
import { useLocusCheckout } from '@withlocus/checkout-react';
function CheckoutButton({ sessionId }: { sessionId: string }) {
const { openPopup, redirectToCheckout } = useLocusCheckout();
return (
<button onClick={() => openPopup(sessionId)}>
Pay with Locus
</button>
);
}Props
LocusCheckout
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| sessionId | string | required | The checkout session ID |
| onSuccess | (data: CheckoutSuccessData) => void | - | Called when payment is confirmed on-chain and the session status is PAID. Receives payment details including txHash, amount, and payerAddress. |
| onCancel | () => void | - | Called when user cancels (or closes the popup window) |
| onError | (error: Error) => void | - | Called on error |
| mode | 'embedded' \| 'popup' \| 'redirect' | 'embedded' | Display mode |
| checkoutUrl | string | 'https://checkout.paywithlocus.com' | Checkout URL. Accepts either a base URL or a full checkout URL — the SDK extracts the origin automatically. |
| style | React.CSSProperties | - | Custom styles for the outer container |
| className | string | - | Custom class name for the outer container |
useLocusCheckout
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| checkoutUrl | string | 'https://checkout.paywithlocus.com' | Checkout URL. Accepts either a base URL or a full checkout URL — the SDK extracts the origin automatically. |
CheckoutSuccessData
interface CheckoutSuccessData {
sessionId: string;
amount: string;
currency: string;
txHash: string;
payerAddress: string;
paidAt: string;
}Server-side Types
The SDK exports TypeScript types for server-side API integration. These are pure type exports with no React dependency:
import type {
CreateCheckoutSessionRequest,
CreateCheckoutSessionResponse,
CheckoutWebhookPayload,
CheckoutWebhookEvent,
GetCheckoutSessionResponse,
} from '@withlocus/checkout-react';Checking Session Status
To check if a session was paid without relying on webhooks, poll the session status endpoint:
import type { GetCheckoutSessionResponse } from '@withlocus/checkout-react';
const response = await fetch(
`https://api.paywithlocus.com/api/checkout/sessions/${sessionId}`,
{
headers: {
'Authorization': `Bearer ${YOUR_CLAW_API_KEY}`,
},
},
);
const { data } = (await response.json()) as GetCheckoutSessionResponse;
if (data.status === 'PAID') {
// Payment confirmed — data.paymentTxHash has the on-chain tx hash
}Webhooks
When a payment is confirmed, Locus will send a webhook to your configured URL:
import type { CheckoutWebhookPayload } from '@withlocus/checkout-react';
// POST https://yourapp.com/webhooks/locus
const payload: CheckoutWebhookPayload = {
event: 'checkout.session.paid',
data: {
sessionId: 'sess_xxx',
amount: '10.00',
currency: 'USDC',
paymentTxHash: '0x...',
payerAddress: '0x...',
paidAt: '2024-01-01T12:00:00Z',
metadata: { plan: 'premium' },
},
timestamp: '2024-01-01T12:00:00Z',
};Verify webhooks using the signature in the X-Signature-256 header:
import crypto from 'crypto';
function verifyWebhook(payload: string, signature: string, secret: string): boolean {
const expected = `sha256=${crypto.createHmac('sha256', secret).update(payload).digest('hex')}`;
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}License
MIT
