• QueueSaaS Team
Next.js Integration Guide
Learn how to integrate QueueSaaS with Next.js App Router. Handle webhooks securely, verify signatures, and build reliable serverless applications.
nextjs webhooks serverless tutorial
Next.js Integration Guide
QueueSaaS provides first-class support for Next.js App Router with built-in webhook signature verification, type-safe handlers, and seamless integration patterns. This guide will show you how to integrate QueueSaaS into your Next.js applications.
Installation
npm install @anlyonhq/scheduler
# or
pnpm add @anlyonhq/scheduler
Environment Setup
Add your QueueSaaS credentials to your .env.local:
ANLYON_API_KEY=live_your_api_key_here
ANLYON_SIGNING_SECRET=whsec_your_signing_secret_here
Sending Messages from Next.js
Server Actions
// app/actions/send-message.ts
'use server';
import { Client } from '@anlyonhq/scheduler';
const client = new Client({
apiKey: process.env.ANLYON_API_KEY!,
});
export async function sendWelcomeEmail(userId: string) {
await client.messages.publish({
url: `${process.env.NEXT_PUBLIC_APP_URL}/api/webhooks/welcome-email`,
method: 'POST',
body: { userId, type: 'welcome_email' },
});
}
API Routes
// app/api/send-notification/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { Client } from '@anlyonhq/scheduler';
const client = new Client({
apiKey: process.env.ANLYON_API_KEY!,
});
export async function POST(request: NextRequest) {
const { userId, message } = await request.json();
await client.messages.publish({
url: `${process.env.NEXT_PUBLIC_APP_URL}/api/webhooks/notify`,
method: 'POST',
body: { userId, message },
});
return NextResponse.json({ success: true });
}
Receiving Webhooks
Using serve() (Recommended)
The serve() function handles signature verification automatically:
// app/api/webhooks/order-processed/route.ts
import { serve } from '@anlyonhq/scheduler/nextjs';
export const { POST } = serve(async (request) => {
const data = await request.json();
// Signature is already verified
await processOrder(data.orderId);
return { success: true };
});
Using verifySignature() Middleware
For more control:
// app/api/webhooks/payment/route.ts
import { verifySignature } from '@anlyonhq/scheduler/nextjs';
export const POST = verifySignature(async (request) => {
const data = await request.json();
// Handle payment webhook
await handlePayment(data);
return Response.json({ ok: true });
});
Custom Configuration
import { serve } from '@anlyonhq/scheduler/nextjs';
export const { POST } = serve(
async (request) => {
const data = await request.json();
return { processed: true };
},
{
signingSecret: process.env.CUSTOM_SECRET, // Override default
clockTolerance: 600, // 10 minutes (default: 300)
onError: (error) =>
Response.json({ error: error.message }, { status: 400 }),
}
);
Real-World Examples
Example 1: User Registration Flow
// app/api/auth/register/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { Client } from '@anlyonhq/scheduler';
const client = new Client({
apiKey: process.env.ANLYON_API_KEY!,
});
export async function POST(request: NextRequest) {
const { email, name } = await request.json();
// Create user in database
const user = await createUser({ email, name });
// Send welcome email asynchronously
await client.messages.publish({
url: `${process.env.NEXT_PUBLIC_APP_URL}/api/webhooks/send-email`,
method: 'POST',
body: {
type: 'welcome',
userId: user.id,
email: user.email,
name: user.name,
},
});
return NextResponse.json({ user });
}
// app/api/webhooks/send-email/route.ts
import { serve } from '@anlyonhq/scheduler/nextjs';
import { sendEmail } from '@/lib/email';
export const { POST } = serve(async (request) => {
const { type, userId, email, name } = await request.json();
if (type === 'welcome') {
await sendEmail({
to: email,
subject: `Welcome, ${name}!`,
template: 'welcome',
data: { name },
});
}
return { success: true };
});
Example 2: Scheduled Tasks
// app/api/admin/setup-daily-report/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { Client } from '@anlyonhq/scheduler';
const client = new Client({
apiKey: process.env.ANLYON_API_KEY!,
});
export async function POST(request: NextRequest) {
// Create a daily report schedule
await client.schedules.create({
name: 'Daily Report',
cronExpression: '0 9 * * *', // 9 AM every day
timezone: 'America/New_York',
url: `${process.env.NEXT_PUBLIC_APP_URL}/api/webhooks/daily-report`,
method: 'POST',
body: { type: 'daily_report' },
});
return NextResponse.json({ success: true });
}
// app/api/webhooks/daily-report/route.ts
import { serve } from '@anlyonhq/scheduler/nextjs';
import { generateDailyReport } from '@/lib/reports';
export const { POST } = serve(async (request) => {
const report = await generateDailyReport();
// Send report to stakeholders
await sendReport(report);
return { success: true };
});
Example 3: Image Processing
// app/api/upload/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { Client } from '@anlyonhq/scheduler';
const client = new Client({
apiKey: process.env.ANLYON_API_KEY!,
});
export async function POST(request: NextRequest) {
const formData = await request.formData();
const file = formData.get('file') as File;
// Save file temporarily
const fileUrl = await saveFile(file);
// Process image asynchronously
await client.messages.publish({
url: `${process.env.NEXT_PUBLIC_APP_URL}/api/webhooks/process-image`,
method: 'POST',
body: {
fileUrl,
userId: request.headers.get('user-id'),
},
});
return NextResponse.json({ fileUrl });
}
// app/api/webhooks/process-image/route.ts
import { serve } from '@anlyonhq/scheduler/nextjs';
import { processImage } from '@/lib/image-processing';
export const { POST } = serve(async (request) => {
const { fileUrl, userId } = await request.json();
// Process image (resize, optimize, etc.)
const processedUrl = await processImage(fileUrl);
// Update user's profile with processed image
await updateUserProfile(userId, { imageUrl: processedUrl });
return { success: true };
});
Error Handling
import { serve } from '@anlyonhq/scheduler/nextjs';
import { AnlyonError } from '@anlyonhq/scheduler';
export const { POST } = serve(
async (request) => {
try {
const data = await request.json();
await processWebhook(data);
return { success: true };
} catch (error) {
if (error instanceof AnlyonError) {
console.error('QueueSaaS error:', error.message);
return Response.json(
{ error: error.message },
{ status: error.statusCode || 500 }
);
}
throw error;
}
},
{
onError: (error) => {
console.error('Webhook error:', error);
return Response.json(
{ error: 'Internal server error' },
{ status: 500 }
);
},
}
);
Type Safety
The SDK is fully typed for better developer experience:
import { serve } from '@anlyonhq/scheduler/nextjs';
interface WebhookPayload {
userId: string;
event: 'user.created' | 'order.completed';
data: Record<string, unknown>;
}
export const { POST } = serve(async (request) => {
const payload = await request.json() as WebhookPayload;
// TypeScript knows the shape of payload
if (payload.event === 'user.created') {
await handleUserCreated(payload.userId, payload.data);
} else if (payload.event === 'order.completed') {
await handleOrderCompleted(payload.userId, payload.data);
}
return { success: true };
});
Best Practices
- Always verify signatures: Use
serve()orverifySignature()for security - Handle errors gracefully: Return appropriate status codes
- Keep handlers idempotent: Webhooks may be delivered multiple times
- Use environment variables: Never hardcode API keys
- Log webhook events: Helpful for debugging
- Return quickly: Webhooks should respond within 30 seconds
Testing Webhooks Locally
Use tools like ngrok to test webhooks locally:
# Start your Next.js dev server
pnpm dev
# In another terminal, expose it via ngrok
ngrok http 3000
# Use the ngrok URL in your QueueSaaS webhook configuration
Next Steps
- Learn about CRON scheduling
- Explore URL Groups
- Check out our TypeScript SDK guide
Build reliable Next.js applications with QueueSaaS! ⚡