ReferenceSdks
Next.js SDK
Official Next.js SDK with React hooks for lomi. payments API.
Official Next.js SDK for the lomi. payments API. Built specifically for Next.js 13+ with App Router, providing React hooks and seamless server/client integration.
The Next.js SDK extends the TypeScript SDK with React-specific features like hooks and server component utilities.
Installation
npm install @lomi./sdk-next
# or
pnpm add @lomi./sdk-nextQuick Start
Server-side Setup
// lib/lomi.ts
import { LomiSDK } from '@lomi./sdk-next';
export const lomi = new LomiSDK({
apiKey: process.env.LOMI_API_KEY!,
environment: process.env.NODE_ENV === 'development' ? 'test' : 'live',
});Client-side Usage
'use client';
import { useLomiRequest } from '@lomi./sdk-next';Server Components
Fetch Customers
// app/customers/page.tsx
import { lomi } from '@/lib/lomi';
export default async function CustomersPage() {
const customers = await lomi.customers.list();
return (
<div>
<h1>Customers ({customers.length})</h1>
<ul>
{customers.map((customer) => (
<li key={customer.id}>{customer.name} - {customer.email}</li>
))}
</ul>
</div>
);
}Fetch Transactions with Filters
// app/transactions/page.tsx
import { lomi } from '@/lib/lomi';
export default async function TransactionsPage() {
const transactions = await lomi.transactions.list({
status: 'completed',
pageSize: 50,
});
return (
<table>
<thead>
<tr>
<th>ID</th>
<th>Amount</th>
<th>Status</th>
<th>Provider</th>
</tr>
</thead>
<tbody>
{transactions.map((tx) => (
<tr key={tx.id}>
<td>{tx.id}</td>
<td>{tx.gross_amount} {tx.currency_code}</td>
<td>{tx.status}</td>
<td>{tx.provider_code}</td>
</tr>
))}
</tbody>
</table>
);
}Get Organization Metrics
// app/dashboard/page.tsx
import { lomi } from '@/lib/lomi';
export default async function DashboardPage() {
const metrics = await lomi.organizations.getMetrics();
return (
<div className="grid grid-cols-3 gap-4">
<div>
<h3>MRR</h3>
<p>{metrics.mrr.toLocaleString()} {metrics.currency_code}</p>
</div>
<div>
<h3>ARR</h3>
<p>{metrics.arr.toLocaleString()} {metrics.currency_code}</p>
</div>
<div>
<h3>Customers</h3>
<p>{metrics.total_customers}</p>
</div>
</div>
);
}Client Components (Hooks)
useLomiRequest Hook
'use client';
import { useLomiRequest } from '@lomi./sdk-next';
import { lomi } from '@/lib/lomi';
export function CustomerList() {
const { data, loading, error, execute } = useLomiRequest(
() => lomi.customers.list()
);
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<div>
<button onClick={() => execute()}>Refresh</button>
<ul>
{data?.map((customer) => (
<li key={customer.id}>{customer.name}</li>
))}
</ul>
</div>
);
}Create Customer Form
'use client';
import { useState } from 'react';
import { useLomiRequest } from '@lomi./sdk-next';
import { lomi } from '@/lib/lomi';
export function CreateCustomerForm() {
const [formData, setFormData] = useState({
name: '',
email: '',
phone_number: '',
});
const { loading, error, execute } = useLomiRequest(
() => lomi.customers.create(formData),
{ manual: true }
);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
const result = await execute();
if (result) {
alert(`Customer created: ${result.id}`);
}
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
placeholder="Name"
value={formData.name}
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
/>
<input
type="email"
placeholder="Email"
value={formData.email}
onChange={(e) => setFormData({ ...formData, email: e.target.value })}
/>
<input
type="tel"
placeholder="Phone"
value={formData.phone_number}
onChange={(e) => setFormData({ ...formData, phone_number: e.target.value })}
/>
<button type="submit" disabled={loading}>
{loading ? 'Creating...' : 'Create Customer'}
</button>
{error && <p>Error: {error.message}</p>}
</form>
);
}API Routes
Create Checkout Session
// app/api/checkout/route.ts
import { NextResponse } from 'next/server';
import { lomi } from '@/lib/lomi';
export async function POST(request: Request) {
const body = await request.json();
const session = await lomi.checkoutSessions.create({
amount: body.amount,
currency_code: 'XOF',
title: body.title || 'Payment',
success_url: `${process.env.NEXT_PUBLIC_URL}/success`,
cancel_url: `${process.env.NEXT_PUBLIC_URL}/cancel`,
customer_email: body.email,
metadata: {
user_id: body.userId,
order_id: body.orderId,
},
});
return NextResponse.json({ url: session.checkout_url });
}Webhook Handler
// app/api/webhooks/lomi/route.ts
import { NextResponse } from 'next/server';
import crypto from 'crypto';
export async function POST(request: Request) {
const signature = request.headers.get('x-lomi-signature') || '';
const body = await request.text();
// Verify signature
const expectedSignature = crypto
.createHmac('sha256', process.env.LOMI_WEBHOOK_SECRET!)
.update(body)
.digest('hex');
if (signature !== expectedSignature) {
return NextResponse.json({ error: 'Invalid signature' }, { status: 400 });
}
const event = JSON.parse(body);
switch (event.type) {
case 'PAYMENT_SUCCEEDED':
console.log('Payment succeeded:', event.data.gross_amount);
// Update order status in database
break;
case 'SUBSCRIPTION_RENEWED':
console.log('Subscription renewed:', event.data.id);
// Extend access
break;
case 'REFUND_COMPLETED':
console.log('Refund processed:', event.data.id);
// Handle refund
break;
default:
console.log('Unhandled event:', event.type);
}
return NextResponse.json({ received: true });
}Checkout Button Component
'use client';
import { useState } from 'react';
interface CheckoutButtonProps {
amount: number;
productName: string;
email?: string;
}
export function CheckoutButton({ amount, productName, email }: CheckoutButtonProps) {
const [loading, setLoading] = useState(false);
const handleCheckout = async () => {
setLoading(true);
try {
const response = await fetch('/api/checkout', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
amount,
title: productName,
email
}),
});
const { url } = await response.json();
window.location.href = url;
} catch (error) {
console.error('Checkout error:', error);
alert('Failed to start checkout');
} finally {
setLoading(false);
}
};
return (
<button
onClick={handleCheckout}
disabled={loading}
className="bg-blue-600 hover:bg-blue-700 text-white px-6 py-3 rounded-lg"
>
{loading ? 'Loading...' : `Pay ${amount.toLocaleString()} XOF`}
</button>
);
}Environment Variables
# .env.local
LOMI_API_KEY=sk_live_xxxxxxxxxxxxxxxxxxxxxx
LOMI_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxxxxxxxxxxx
NEXT_PUBLIC_URL=https://yoursite.comTypeScript Types
import type {
Customer,
CustomerCreate,
CheckoutSession,
CheckoutSessionCreate,
Transaction,
Product,
Subscription,
PaymentLink,
} from '@lomi./sdk-next';Resources
- TypeScript SDK - Base SDK documentation
- API Reference - Full API documentation
- GitHub
- Discord Community