Documentation Index
Fetch the complete documentation index at: https://mintlify.com/levinbaenninger/quest-hunter/llms.txt
Use this file to discover all available pages before exploring further.
Overview
The Users API contains internal mutations used by the Clerk webhook integration to synchronize user data between Clerk and Convex. These endpoints are not directly accessible from client code and can only be called internally by the Convex backend.User Schema
Users are stored with the following structure:Convex-generated unique identifier
The unique Clerk user ID (indexed for fast lookups)
User’s primary email address from Clerk
User’s first name (optional)
User’s last name (optional)
URL to the user’s profile image from Clerk (optional)
Internal Mutations
upsertUser
Creates a new user or updates an existing user based on Clerk webhook data. This mutation is called when Clerk sendsuser.created or user.updated events.
The unique Clerk user ID from the webhook payload
User’s primary email address
User’s first name from Clerk profile
User’s last name from Clerk profile
URL to user’s profile image hosted by Clerk
- User exists: Updates all fields (email, firstName, lastName, imageUrl) with new values from Clerk
- User doesn’t exist: Creates a new user record with all provided fields
user.createdevents - Creates new useruser.updatedevents - Updates existing user
deleteUser
Deletes a user from the Convex database when they are deleted from Clerk. This mutation is called when Clerk sends auser.deleted event.
The Clerk user ID to delete
- Looks up the user by their Clerk ID
- If found, deletes the user record
- If not found, silently succeeds (idempotent operation)
user.deletedevents
This mutation only deletes the user record itself. It does not cascade delete related records like userQuests or userLocations. You may want to implement cleanup logic for those tables separately.
Webhook Integration
These mutations are called from the Clerk webhook handler inconvex/http.ts:
Getting Current User
While there’s no publicgetCurrent query, you can get the current user using the requireUser utility function in your own queries and mutations:
requireUser function:
- Validates the user is authenticated (has valid JWT token)
- Looks up the user by their Clerk ID from the JWT
- Returns the full user object
- Throws
"Not authenticated"if no JWT token - Throws
"User not found"if user doesn’t exist in database
Data Flow
Best Practices
- Never call these mutations directly - They are internal and should only be invoked by the webhook handler
-
Use requireUser for authentication - All client-facing queries and mutations should use
requireUser(ctx)to enforce authentication and get the current user -
Handle missing users gracefully - If a user is authenticated but not found in the database, it means the webhook hasn’t synced yet. The
requireUserfunction will throw an error in this case - Monitor webhook delivery - Ensure Clerk webhooks are being delivered successfully. Failed webhooks will result in users being authenticated but not found in the database
-
Consider cascade deletions - When implementing
deleteUser, consider whether you want to delete or archive related records (quests, locations, etc.)