Reference

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.

The Clerk ID is the User ID
Athenium's 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 from email_addresses[0].
  • firstName, lastName.
  • role — defaults to STUDENT; 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

  1. In the Clerk dashboard, open Webhooks → Add endpoint.
  2. Set the URL to https://your-athenium.app/api/webhooks/clerk.
  3. Subscribe to user.created, user.updated, and user.deleted.
  4. Copy the signing secret into your environment as CLERK_WEBHOOK_SECRET and 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.