Webhooks
Receive and process data change events
Webhooks
Receive events on your server when data changes.
Overview
When webhooks are configured, a POST request is sent to the specified URL when the following events occur:
create- New document createdupdate- Document updated
Webhook Setup
Create an API Route
import { handleWebhook } from '@01.software/sdk/webhook'
export async function POST(request: Request) {
return handleWebhook(request, async (event) => {
console.log('Collection:', event.collection)
console.log('Operation:', event.operation)
console.log('Data:', event.data)
})
}Register the Webhook URL
Set the Webhook URL in the tenant settings of the 01.software Console.
https://your-domain.com/api/webhookPayload Structure
WebhookEvent
interface WebhookEvent {
collection: string
operation: 'create' | 'update'
data: any
timestamp: string // ISO 8601
}JSON Example
{
"collection": "products",
"operation": "create",
"data": {
"id": "product-id",
"title": "Product Name",
"price": 10000
},
"timestamp": "2026-02-24T10:30:45.123Z"
}SDK Handlers
handleWebhook
The basic webhook handler.
import { handleWebhook } from '@01.software/sdk/webhook'
export async function POST(request: Request) {
return handleWebhook(request, async (event) => {
if (event.collection === 'orders' && event.operation === 'create') {
await sendOrderNotification(event.data)
}
})
}createTypedWebhookHandler
Creates a type-safe handler for a specific collection.
import { handleWebhook, createTypedWebhookHandler } from '@01.software/sdk/webhook'
const handleOrderWebhook = createTypedWebhookHandler(
'orders',
async (event) => {
// event.data type is inferred as Order
console.log('Order:', event.data.orderNumber)
console.log('Total:', event.data.totalAmount)
if (event.operation === 'create') {
await sendOrderConfirmation(event.data.email)
}
}
)
export async function POST(request: Request) {
return handleWebhook(request, handleOrderWebhook)
}isValidWebhookEvent
A type guard that validates webhook events.
import { isValidWebhookEvent } from '@01.software/sdk/webhook'
export async function POST(request: Request) {
const body = await request.json()
if (!isValidWebhookEvent(body)) {
return new Response('Invalid event', { status: 400 })
}
// body is inferred as WebhookEvent type
console.log(body.collection, body.operation)
}Handling Multiple Collections
import { handleWebhook } from '@01.software/sdk/webhook'
export async function POST(request: Request) {
return handleWebhook(request, async (event) => {
switch (event.collection) {
case 'orders':
if (event.operation === 'create') {
await sendOrderNotification(event.data)
}
break
case 'products':
if (event.operation === 'update') {
await invalidateProductCache(event.data.id)
}
break
case 'posts':
revalidatePath('/blog')
if (event.data.slug) {
revalidatePath(`/blog/${event.data.slug}`)
}
break
}
})
}Practical Examples
Order Notification
const handleOrderWebhook = createTypedWebhookHandler(
'orders',
async (event) => {
if (event.operation === 'create') {
await sendEmail({
to: event.data.email,
subject: `Order Confirmation - ${event.data.orderNumber}`,
body: `Your order has been received.`
})
await sendSlackNotification({
channel: '#orders',
message: `New order: ${event.data.orderNumber}`
})
}
}
)Cache Invalidation
import { revalidatePath, revalidateTag } from 'next/cache'
const handlePostWebhook = createTypedWebhookHandler(
'posts',
async (event) => {
revalidatePath('/blog')
revalidatePath(`/blog/${event.data.slug}`)
revalidateTag('posts')
}
)Inventory Sync
const handleProductWebhook = createTypedWebhookHandler(
'products',
async (event) => {
if (event.operation === 'update') {
await syncInventory({
sku: event.data.sku,
stock: event.data.stock
})
}
}
)Security
Signature Verification
The SDK's handleWebhook supports built-in HMAC-SHA256 signature verification via the secret option. The server signs the payload using PAYLOAD_SECRET and sends it in the x-webhook-signature header.
export async function POST(request: Request) {
return handleWebhook(request, handler, {
secret: process.env.WEBHOOK_SECRET!,
})
}IP Whitelist
export async function POST(request: Request) {
const ip = request.headers.get('x-forwarded-for')
if (!allowedIPs.includes(ip)) {
return new Response('Forbidden', { status: 403 })
}
return handleWebhook(request, handler)
}Testing
curl -X POST https://your-app.com/api/webhook \
-H "Content-Type: application/json" \
-d '{
"collection": "orders",
"operation": "create",
"data": {
"id": "order_123",
"orderNumber": "260107123456",
"email": "test@example.com"
}
}'Error Handling
export async function POST(request: Request) {
return handleWebhook(request, async (event) => {
try {
await processEvent(event)
} catch (error) {
console.error('Webhook processing error:', error)
throw error // Throw error for retry
}
})
}Webhook handlers should process quickly. Offload long-running tasks to background jobs.
Response Format
The webhook handler automatically returns the appropriate response.
- Success:
{ "success": true, "message": "Webhook processed successfully" } - Failure:
{ "success": false, "error": "Invalid webhook event" }
Next Steps
- Error Handling - Error handling
- REST API - REST API reference