Agent skills

Teach your AI coding assistant to build webhook routes correctly.

AI assistants happily hand-roll webhook verification, and they usually get at least one of the four steps wrong. A skill file fixes that: it loads the library's rules into the assistant, so generated routes use the built-in providers, keep the raw body intact, and return the status codes that drive retries.

For Claude Code, save this file in your project and it loads automatically whenever webhooks come up:

.claude/skills/next-webhooks/SKILL.md
---
name: next-webhooks
description: Build webhook receivers with the next-webhooks package. Use when adding webhook endpoints (Stripe, GitHub, Clerk, Resend, Polar, Slack, Paddle, Shopify, Lemon Squeezy, Vercel, Discord) to a Next.js App Router project.
---

# next-webhooks

Verified, typed, idempotent webhook receivers for the Next.js App Router.

## Rules

- Export the result of webhook() as POST from a route handler, or
  scaffold one with: npx next-webhooks init <provider>.
- Pick the built-in provider first: stripe(), github(), svix() for
  Clerk, Resend, and Polar, slack(), paddle(), shopify(),
  lemonsqueezy(), vercel(), discord(). Use hmac() for other HMAC
  schemes.
- Prefer events + on over an if/else chain: events maps event types
  to Standard Schema validators (zod, valibot, arktype) and on maps
  them to handlers. Payloads are validated at runtime and handler
  types are inferred from the schemas.
- Never read or parse the request body before webhook() runs; the
  signature is checked over the raw bytes.
- On serverless, pass a shared IdempotencyStore via the idempotency
  option; the default store is per-instance memory. The built-in
  upstash() store from next-webhooks/stores is zero-dependency.
- Do not catch handler errors just to return 200. A 500 makes the
  provider retry, and the event id is released automatically so the
  retry is processed.
- In tests, build signed headers with next-webhooks/testing
  (stripeHeaders, githubHeaders, svixHeaders, slackHeaders,
  paddleHeaders, shopifyHeaders, lemonsqueezyHeaders, vercelHeaders,
  discordHeaders with discordKeys, hmacHeaders) instead of
  hand-rolling crypto.

## Example

```ts
import { webhook, stripe } from "next-webhooks";
import { z } from "zod";

export const POST = webhook({
  provider: stripe({ secret: process.env.STRIPE_WEBHOOK_SECRET! }),
  events: {
    "invoice.paid": z.object({ id: z.string(), amount_due: z.number() }),
  },
  on: {
    "invoice.paid": async (event) => {
      // event.payload is validated and typed
    },
  },
});
```

Docs: https://next-webhooks.clawdiu.xyz

Other assistants

The same content works anywhere your assistant reads project instructions: a Cursor rule (.cursor/rules/next-webhooks.mdc), a Windsurf rule, or a section in AGENTS.md. Copy the block above and drop the frontmatter if the format does not use it.

llms.txt

This site also serves a plain-text summary of the library at /llms.txt, so AI tools that fetch documentation get the API surface without scraping HTML.