AgentSkillsCN

clerk-webhooks

Clerk Webhook 用于实时事件与数据同步。监听用户创建、更新、删除,以及组织相关事件。构建基于事件的特性,例如数据库同步、通知推送、各类集成。

SKILL.md
--- frontmatter
name: clerk-webhooks
description: Clerk webhooks for real-time events and data syncing. Listen for user creation, updates, deletion, and organization events. Build event-driven features like database sync, notifications, integrations.
allowed-tools: WebFetch
license: MIT
metadata:
  author: clerk
  version: "1.0.0"

Webhooks

Prerequisite: Webhooks are asynchronous. Use for background tasks (sync, notifications), not synchronous flows.

Documentation Reference

Quick Start

  1. Create endpoint at app/api/webhooks/route.ts
  2. Use verifyWebhook(req) from @clerk/nextjs/webhooks
  3. Dashboard → Webhooks → Add Endpoint
  4. Set CLERK_WEBHOOK_SIGNING_SECRET in env
  5. Make route public (not protected by middleware)

Supported Events

User: user.created user.updated user.deleted

Organization: organization.created organization.updated organization.deleted

Organization Domain: organizationDomain.created organizationDomain.updated organizationDomain.deleted

Organization Invitation: organizationInvitation.created organizationInvitation.accepted organizationInvitation.revoked

Organization Membership: organizationMembership.created organizationMembership.updated organizationMembership.deleted

Roles: role.created role.updated role.deleted

Permissions: permission.created permission.updated permission.deleted

Session: session.created session.updated session.ended session.removed session.revoked session.pending

Communication: email.created sms.created

Invitations: invitation.created invitation.accepted invitation.revoked

Waitlist: waitlistEntry.created waitlistEntry.updated

Full catalog: Dashboard → Webhooks → Event Catalog

When to Sync

Do sync when:

  • Need other users' data (social features, profiles)
  • Storing extra custom fields (birthday, country, bio)
  • Building notifications or integrations

Don't sync when:

  • Only need current user data (use session token)
  • No custom fields (Clerk has everything)
  • Need immediate access (webhooks are eventual consistency)

Key Patterns

Make Route Public

Webhooks come unsigned. Route must be public:

Ensure clerkMiddleware() doesn't protect /api/webhooks(.*) path.

Verify Webhook

Use correct import and single parameter:

typescript
import { verifyWebhook } from '@clerk/nextjs/webhooks'
const evt = await verifyWebhook(req)  // Pass request directly

Type-Safe Events

Narrow to specific event:

typescript
if (evt.type === 'user.created') {
  // TypeScript knows evt.data structure
}

Handle All Three Events

Don't only listen to user.created. Also handle user.updated and user.deleted.

Queue Async Work

Return 200 immediately, queue long operations:

typescript
await queue.enqueue('process-webhook', evt)
return new Response('Received', { status: 200 })

Webhook Reliability

Retries: Svix retries failed webhooks for up to 3 days. Return 2xx to succeed, 4xx/5xx to retry.

Replay: Failed webhooks can be replayed from Dashboard.

Common Pitfalls

SymptomCauseFix
Verification failsWrong import or usageUse @clerk/nextjs/webhooks, pass req directly
Route not found (404)Wrong pathUse /api/webhooks
Not authorized (401)Route is protectedMake route public
No data in DBAsync job pendingWait/check logs
Duplicate entriesOnly handling user.createdAlso handle user.updated
TimeoutsHandler too slowQueue async work

Testing & Deployment

Local: Use ngrok to tunnel localhost:3000 to internet. Add ngrok URL to Dashboard endpoint.

Production: Update webhook endpoint URL to production domain. Copy signing secret to production env vars.