Skip to main content
This guide shows you how to add the two Ribaunt CAPTCHA API routes to a Next.js application — one to issue challenges and one to verify solutions. Both the App Router (app/ directory, Next.js 13+) and the Pages Router (pages/api/, Next.js 12 and below) are covered below.
Never prefix RIBAUNT_SECRET with NEXT_PUBLIC_. Variables prefixed that way are bundled into the client at build time and exposed to every browser. Keep this value server-only.

Environment setup

Add your secret to .env.local. Next.js loads this file automatically and keeps its values server-side only:

App Router (Next.js 13+)

Place these files at app/api/captcha/challenge/route.ts and app/api/captcha/verify/route.ts.
Create the two route handler files shown below. Each file exports a named HTTP-method function (GET or POST) — the App Router convention.
createChallenge({ difficulty: 5, amount: 4, ttlSeconds: 60 }) generates 4 signed challenge tokens at difficulty 5, each valid for 60 seconds. The function returns an array of JWT strings; wrapping it in { challenges } matches the response contract the Ribaunt widget expects.

Pages Router (Next.js 12 and below)

If you are using the pages/api/ directory, create the two handler files below. Each exports a default async function that receives NextApiRequest and NextApiResponse.

Serverless and edge deployments

The default replayPrevention: 'local' mode stores used token IDs in an in-process Map. When your application runs as serverless functions or across multiple instances, each cold start begins with an empty store, so a token solved against one instance can be replayed against another.To prevent cross-instance replays, pass replayPrevention: 'remote' together with a replayStore adapter backed by an atomic distributed store (for example Redis with a SET NX operation):
The replayStore must implement a consume(jti: string, expiresAt: number): Promise<boolean> method that atomically returns true the first time a given jti is seen and false on any subsequent call.