Next.js Integration
Integrate StableOps with Next.js App Router: create idempotent payment orders on the server, send wallet transfers, and fulfill from verified Webhooks.
This guide uses the App Router and the current TypeScript SDK.
Install
pnpm add @stableops/api-sdkConfigure
STABLEOPS_API_KEY=sk_sandbox_...
STABLEOPS_WEBHOOK_SECRET=whsec_...Create lib/stableops.ts:
import { StableOps } from '@stableops/api-sdk'
export const stableops = new StableOps({
apiKey: process.env.STABLEOPS_API_KEY!,
})This guide uses a sandbox key and Base Sepolia. Import a base-sepolia receiving address in Sandbox and prepare test USDC first. For production, switch the API key, accepted mainnet assets, and Live address pool together; changing only the key is not enough.
These snippets omit business authentication. In production, authenticate the user, check order ownership, and load the payable amount from trusted server-side product or invoice records rather than accepting a client-supplied price. Authorize order retrieval and cancellation as well.
Create an order
Create app/actions/payment.ts:
'use server'
import { revalidatePath } from 'next/cache'
import { stableops } from '@/lib/stableops'
export async function createPaymentOrder(formData: FormData) {
const amount = String(formData.get('amount') ?? '')
const merchantOrderId = String(formData.get('orderId') ?? '')
const order = await stableops.paymentOrders.create(
{
merchantOrderId,
amount,
acceptedAssets: [{ chain: 'base-sepolia', asset: 'USDC' }],
expiresAt: new Date(Date.now() + 30 * 60 * 1000).toISOString(),
metadata: { source: 'nextjs_checkout' },
},
{ idempotencyKey: merchantOrderId },
)
revalidatePath('/payments')
return order
}Show one payment candidate from the returned order:
{
order.paymentInstructions[0] ? (
<div>
Send {order.amount} {order.paymentInstructions[0].asset} on{' '}
{order.paymentInstructions[0].chain} to:
<code>{order.paymentInstructions[0].address}</code>
</div>
) : null
}Verify webhooks
Create app/api/webhooks/stableops/route.ts:
import { SIGNATURE_HEADER, verifySignature } from '@stableops/api-sdk/webhooks'
const WEBHOOK_SECRET = process.env.STABLEOPS_WEBHOOK_SECRET!
export async function POST(req: Request) {
const rawBody = await req.text()
const result = verifySignature({
secrets: [WEBHOOK_SECRET],
header: req.headers.get(SIGNATURE_HEADER) ?? undefined,
rawBody,
})
if (!result.ok) {
return new Response(`invalid signature: ${result.reason}`, { status: 400 })
}
const event = JSON.parse(rawBody) as {
type: string
data: { payment_order_id?: string }
}
switch (event.type) {
case 'payment.detected':
break
case 'payment.confirmed':
break
case 'payment.finalized':
// Fulfill after your own idempotency check.
break
case 'payment.expired':
case 'payment.reverted':
break
}
return new Response('ok')
}The empty branches demonstrate event routing, not production fulfillment. Persist the event and recoverable work before acknowledging it. Commit business updates and the processed marker together, or use a recoverable processing state. See reliable Webhook handling.
How is this guide?
Last updated
Operational Events Webhook
Reference StableOps operational and Agent Webhook events, including triggers, payload fields, signature verification, retry behavior, and automation guidance.
Express Integration
Integrate StableOps into Express with sandbox payment orders, server-side keys, raw-body Webhook verification, and idempotent processing for safe fulfillment.