Webhooks
Athenium consumes Clerk webhooks to mirror identity events into its own database. This page documents the events Athenium listens for, how signatures are verified, and what to configure in the Clerk dashboard.
Why webhooks matter here
Athenium uses Clerk for authentication, but stores every domain object (classrooms, submissions, attendance) in its own Postgres database. To keep the two in sync, Athenium needs to know when a user is created in Clerk so it can create a matching row in User — using the Clerk ID as the primary key.
User.id column is set to the Clerk user identifier. Anything that bypasses this webhook (manual database inserts, rolled-your-own auth flow) will break the invariant and cause 404s on every authenticated route.Endpoint
The handler lives at POST /api/webhooks/clerk. It is unauthenticated by design — middleware lets /api/webhooks/(.*) through — but every payload is signature-verified before being processed.
Signature verification
Athenium uses svix to verify the webhook signature against the secret you set in CLERK_WEBHOOK_SECRET:
const wh = new Webhook(WEBHOOK_SECRET);
const evt = wh.verify(body, {
"svix-id": svix_id,
"svix-timestamp": svix_timestamp,
"svix-signature": svix_signature,
}) as WebhookEvent;If verification fails, the handler returns 400 and does not touch the database.
Events handled
user.created
Inserts a row in User with:
id— the Clerk user ID, used as the Athenium primary key.email— the primary email fromemail_addresses[0].firstName,lastName.role— defaults toSTUDENT; admins promote professors and admins from the admin panel afterwards.
user.updated
Mirrors profile changes (email, name) back into the database. Role changes are not driven from Clerk — they live in Athenium's admin panel.
user.deleted
Currently a no-op. Deleting a Clerk user does not cascade to Athenium records, because submissions and grades may still need to be retained for institutional reasons. Soft-deletion is on the roadmap.
Configuring in Clerk
- In the Clerk dashboard, open Webhooks → Add endpoint.
- Set the URL to
https://your-athenium.app/api/webhooks/clerk. - Subscribe to
user.created,user.updated, anduser.deleted. - Copy the signing secret into your environment as
CLERK_WEBHOOK_SECRETand redeploy.
Local development
Clerk can't reach localhost directly. Use ngrok http 3000 (or the tunnel of your choice) and point the dashboard at the public URL. Remember to swap it back to your prod URL before going live.
Outbound webhooks
Athenium does not yet emit its own outbound webhooks for events like new submissions or attendance changes. If you need that for an LMS or SIS integration, watch the changelog or ping the team — it's on the list.