# Next.js



Next.js Route Handlers receive a Web `Request` and return a `Response`, so `@postel/nextjs` is a thin, typed facade over [`@postel/http`](/docs/reference/http): `NextjsWebAdapter(postel)` returns Route Handlers keyed by HTTP method — App Router route files export those directly.

## Inbound webhook route [#inbound-webhook-route]

```ts title="app/api/webhooks/vendor/route.ts"
import { NextjsWebAdapter } from "@postel/nextjs";
import { postel } from "@/lib/postel"; // Postel({ inbound: { vendor: { verify: Secret(...) } } })

const nwa = NextjsWebAdapter(postel);

export const { POST } = nwa.inbound.vendor.post((result) => {
  return Response.json({ ok: true, type: result.event.type });
});
```

The source key is type-checked against the sources you configured, and `result` is typed to that source's schema output. On failure the gate short-circuits with the mapped HTTP status and your handler never runs; a non-`PostelError` bubbles as a 5xx. Use `.on(method, handler, opts)` to gate a body-bearing method other than `POST` (`PUT` | `PATCH`).

## JWKS route [#jwks-route]

```ts title="app/.well-known/webhooks-keys/route.ts"
import { NextjsWebAdapter } from "@postel/nextjs";
import { postel } from "@/lib/postel";

export const { GET } = NextjsWebAdapter(postel).outbound.bindJwks();
```

## Admin route [#admin-route]

```ts title="app/admin/[...path]/route.ts"
import { NextjsWebAdapter } from "@postel/nextjs";
import { postel } from "@/lib/postel";

export const { GET, POST, PUT, PATCH, DELETE } = NextjsWebAdapter(postel).admin.bindAdminRoutes({
  authorize: (req) => check(req),
});
```

## Low-level primitive [#low-level-primitive]

The facade is sugar over `withWebhook(source, handler, opts?)` — use it to gate a route file by hand without the facade:

```ts
import { withWebhook } from "@postel/nextjs";
import { postel } from "@/lib/postel";

export const POST = withWebhook(postel.inbound.vendor, (result) =>
  Response.json({ ok: true, type: result.event.type }),
);
```
