We also have a Next.js example ready to deploy on Vercel.

Deploy with Vercel

If you don’t have a Next.js app yet, you can create one with the following command:

npm create next-app@latest


Now install the @unkey/nextjs package

  npm install @unkey/nextjs

Creating a protected route

Create a new route and add the following code

import { NextRequestWithUnkeyContext, withUnkey } from '@unkey/nextjs';
import { NextResponse } from 'next/server';

export const POST = withUnkey(async (req) => {
  if (!req.unkey.valid) {
    return new NextResponse('unauthorized', { status: 403 });

  // Process the request here
  // You have access to the verification response using `req.unkey`
  return new NextResponse('Your API key is valid!');

Running it

  bun run dev

Try it out

Go to and create a new key. Then verify it with our new server:

curl -XPOST 'http://localhost:3000/protected' \
  -H "Authorization: Bearer <KEY>"

It should return "Your API key is valid!" and log more information about the key, depending on what you set up in the dashboard.


The withUnkey wrapper takes a configuration object as a second optional argument to configure the request handling. These are optional and the defaults should be fine for most use cases.

export const POST = withUnkey(handler, {
  getKey: ...,
  handleInvalidKey: ...,
  onError: ...,
(NextRequest) => string | null | NextResponse

How to get the key from the request. Usually the key is provided in an Authorization header, but you can do what you want.

Return the key as string, or null if it doesn’t exist. You can also directly return a NextResponse which will be sent to the client without invoking the handler function.

Defaults to: req => req.headers.get("Authorization")?.replace("Bearer ", "") ?? null

(NextRequest, UnkeyContext) => NextResponse | Promise<NextResponse>)

Return a custom response when a key is invalid.

(NextRequest, UnkeyError) => NextResponse | Promise<NextResponse>

What to do if things go wrong. This could be a network error for example. The SDK will automatically retry the request up to 5 times, but if it still fails, this function will be called.