clerk-webhooks
Original:🇺🇸 English
Translated
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.
13installs
Sourceclerk/skills
Added on
NPX Install
npx skill4agent add clerk/skills clerk-webhooksTags
Translated version includes tags in frontmatterSKILL.md Content
View Translation Comparison →Webhooks
Prerequisite: Webhooks are asynchronous. Use for background tasks (sync, notifications), not synchronous flows.
Documentation Reference
| Task | Link |
|---|---|
| Overview | https://clerk.com/docs/guides/development/webhooks/overview |
| Sync to database | https://clerk.com/docs/guides/development/webhooks/syncing |
| Debugging | https://clerk.com/docs/guides/development/webhooks/debugging |
| Event catalog | https://dashboard.clerk.com/~/webhooks (Event Catalog tab) |
Quick Start
- Create endpoint at
app/api/webhooks/route.ts - Use from
verifyWebhook(req)@clerk/nextjs/webhooks - Dashboard → Webhooks → Add Endpoint
- Set in env
CLERK_WEBHOOK_SIGNING_SECRET - Make route public (not protected by middleware)
Supported Events
User:
user.createduser.updateduser.deletedOrganization:
organization.createdorganization.updatedorganization.deletedOrganization Domain:
organizationDomain.createdorganizationDomain.updatedorganizationDomain.deletedOrganization Invitation:
organizationInvitation.createdorganizationInvitation.acceptedorganizationInvitation.revokedOrganization Membership:
organizationMembership.createdorganizationMembership.updatedorganizationMembership.deletedRoles:
role.createdrole.updatedrole.deletedPermissions:
permission.createdpermission.updatedpermission.deletedSession:
session.createdsession.updatedsession.endedsession.removedsession.revokedsession.pendingCommunication:
email.createdsms.createdInvitations:
invitation.createdinvitation.acceptedinvitation.revokedWaitlist:
waitlistEntry.createdwaitlistEntry.updatedFull 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 doesn't protect path.
clerkMiddleware()/api/webhooks(.*)Verify Webhook
Use correct import and single parameter:
typescript
import { verifyWebhook } from '@clerk/nextjs/webhooks'
const evt = await verifyWebhook(req) // Pass request directlyType-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 . Also handle and .
user.createduser.updateduser.deletedQueue 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
| Symptom | Cause | Fix |
|---|---|---|
| Verification fails | Wrong import or usage | Use |
| Route not found (404) | Wrong path | Use |
| Not authorized (401) | Route is protected | Make route public |
| No data in DB | Async job pending | Wait/check logs |
| Duplicate entries | Only handling | Also handle |
| Timeouts | Handler too slow | Queue async work |
Testing & Deployment
Local: Use ngrok to tunnel to internet. Add ngrok URL to Dashboard endpoint.
localhost:3000Production: Update webhook endpoint URL to production domain. Copy signing secret to production env vars.