API Organization
Evaly’s backend API is organized by feature domain in theconvex/ directory. All functions are written in TypeScript and automatically type-checked.
Directory Structure
Function Types
- Query
- Mutation
- Action
- Internal
- Automatically cached
- Real-time reactive updates
- Cannot modify database
- Can be called from frontend with
useQuery()
Organizer API
Test Management
Test CRUD (convex/organizer/test.ts)
Test CRUD (convex/organizer/test.ts)
getTests({ paginationOpts, status?, search?, sort? })- List tests with filtering and paginationgetTestById({ testId })- Get single test by ID
createTest()- Create new draft testupdateTest({ testId, data })- Update test metadatadeleteTest({ testId })- Soft delete testduplicateTest({ testId })- Duplicate test with all sections/questionspublishTest({ testId, startOption, scheduledStartAt?, scheduledEndAt? })- Publish teststopTest({ testId, reason? })- Stop/unpublish testpauseTest({ testId })- Pause active testresumeTest({ testId })- Resume paused testextendTestTime({ testId, additionalMinutes?, newEndTime? })- Extend test durationupdateTestSchedule({ testId, scheduledEndAt? })- Update test scheduletoggleUseSectionDurations({ testId, useSectionDurations })- Toggle duration modetoggleResultsReleased({ testId, resultsReleased })- Toggle results visibility
checkTestOwnership(ctx, testId)- Verify user owns test
Section Management (convex/organizer/testSection.ts)
Section Management (convex/organizer/testSection.ts)
getTestSections({ testId })- Get all sections for a testgetSectionById({ sectionId })- Get single section
createSection({ testId, title, description?, order })- Create new sectionupdateSection({ sectionId, title?, description?, duration? })- Update sectiondeleteSection({ sectionId })- Delete sectionreorderSections({ testId, sectionIds })- Reorder sectionsupdateSectionDuration({ sectionId, duration })- Set section time limit
validateSectionDurationsAgainstTestWindow(ctx, testId)- Validate durations fit schedule
Question Management (convex/organizer/question.ts)
Question Management (convex/organizer/question.ts)
getQuestions({ referenceId })- Get questions for section/librarygetQuestionById({ questionId })- Get single question
createQuestion({ referenceId, question, type, options?, ... })- Create questionupdateQuestion({ questionId, question?, type?, options?, ... })- Update questiondeleteQuestion({ questionId })- Delete questionduplicateQuestion({ questionId })- Duplicate questionreorderQuestions({ referenceId, questionIds })- Reorder questionsduplicateQuestionsFromLibrary({ sourceLibraryId, targetSectionId, questionIds })- Copy from library
multiple-choice- Traditional multiple choiceyes-or-no- Boolean questionsimage-choice- Image-based optionsaudio-choice- Audio-based optionstext-field- Short/long text answersfile-upload- File submissionfill-the-blank- Fill-in-the-blankaudio-response- Audio recordingvideo-response- Video recordingmatching-pairs- Match itemsslider-scale- Numeric sliderlikert-scale- Agreement scaleranking- Rank items in order
Question Libraries (convex/organizer/questionLibrary.ts)
Question Libraries (convex/organizer/questionLibrary.ts)
getLibraries({ paginationOpts, search? })- List question librariesgetLibraryById({ libraryId })- Get single library
createLibrary({ name, description? })- Create question bankupdateLibrary({ libraryId, name?, description? })- Update librarydeleteLibrary({ libraryId })- Delete library
Test Access & Monitoring
Access Control (convex/organizer/testAccess.ts)
Access Control (convex/organizer/testAccess.ts)
getTestParticipants({ testId })- Get allowed participantsgetTestParticipantGroups({ testId })- Get allowed user groups
addParticipant({ testId, email })- Allow individual participantremoveParticipant({ testId, participantId })- Remove participantaddParticipantGroup({ testId, userGroupId })- Allow user groupremoveParticipantGroup({ testId, groupId })- Remove user groupupdateAccessControl({ testId, password?, allowedEmailDomains?, allowedIpAddresses? })- Set access restrictions
Live Monitoring (convex/organizer/testMonitoring.ts)
Live Monitoring (convex/organizer/testMonitoring.ts)
getLiveTestStatus({ testId })- Real-time test statusgetActiveParticipants({ testId })- Currently active participantsgetParticipantProgress({ testId, participantId })- Individual progressgetTestPresence({ testId })- Presence/heartbeat data
- Real-time participant join/leave
- Live progress tracking
- Section completion monitoring
- Heartbeat-based presence
Activity Logs (convex/organizer/testActivity.ts)
Activity Logs (convex/organizer/testActivity.ts)
getActivityLog({ testId, paginationOpts })- Get test activity history
test_started- Test begantest_ended- Test finishedtest_paused- Test pausedtest_resumed- Test resumedtime_extended- Duration extendedparticipant_joined- Participant started testparticipant_submitted- Participant submitted answers
Results & Grading
Test Results (convex/organizer/testResult.ts)
Test Results (convex/organizer/testResult.ts)
getTestResults({ testId, paginationOpts })- Get all participant resultsgetParticipantResult({ testId, participantId })- Individual resultgetResultsAnalytics({ testId })- Aggregate statisticsexportResults({ testId, format })- Export data
- Average scores
- Completion rates
- Question difficulty analysis
- Time-to-complete metrics
- Score distribution
Manual Grading (convex/organizer/grading.ts)
Manual Grading (convex/organizer/grading.ts)
getParticipantSubmission({ testId, participantId })- Get submission with answersgetUngradedSubmissions({ testId })- Find submissions needing grading
gradeAnswer({ testAttemptId, questionId, pointsAwarded, feedback? })- Grade single answerbulkGradeAnswers({ grades })- Grade multiple answers at once
- Text field responses
- File uploads
- Audio/video responses
- Subjective questions
Organization Management
Organizations (convex/organizer/organization.ts)
Organizations (convex/organizer/organization.ts)
getOrganization({ organizationId })- Get organization detailsgetUserOrganizations()- Get user’s organizations
createOrganization({ name, type, image? })- Create new organizationupdateOrganization({ organizationId, name?, image? })- Update orgswitchOrganization({ organizationId })- Switch active organizationdeleteOrganization({ organizationId })- Delete organization
Invitations (convex/organizer/invitation.ts)
Invitations (convex/organizer/invitation.ts)
getPendingInvitations({ organizationId })- List pending invitesgetInvitationByToken({ token })- Verify invitation token
createInvitation({ organizationId, email, role })- Invite memberacceptInvitation({ token })- Accept invitationrevokeInvitation({ invitationId })- Cancel invitationresendInvitation({ invitationId })- Resend email
- 7-day token expiration
- Email notifications via Plunk
- Role-based invitations (owner, admin, member)
User Groups (convex/organizer/userGroup.ts)
User Groups (convex/organizer/userGroup.ts)
getUserGroups({ paginationOpts, search? })- List groupsgetGroupById({ groupId })- Get single groupgetGroupMembers({ groupId })- Get group members
createGroup({ name })- Create user groupupdateGroup({ groupId, name })- Update groupdeleteGroup({ groupId })- Delete groupaddGroupMember({ groupId, email })- Add memberremoveGroupMember({ groupId, memberId })- Remove memberbulkAddMembers({ groupId, emails })- Add multiple members
Subscription & Billing
Subscription (convex/organizer/subscription.ts)
Subscription (convex/organizer/subscription.ts)
getCurrentPlan({ organizationId })- Get active plangetUsage({ organizationId, month? })- Get current usagegetAvailablePlans()- List available plans
free- Free tier with basic limitspro- Professional tier with higher limitsmax- Maximum tier with unlimited features
- AI question generation (monthly)
- AI translation (monthly)
- AI options generation (monthly)
- AI analysis (monthly)
- Test results (monthly)
- Team members (real-time)
- Active tests (real-time)
- Concurrent participants (real-time)
Billing (convex/organizer/billing.ts)
Billing (convex/organizer/billing.ts)
upgradePlan({ organizationId, plan })- Upgrade subscriptiondowngradePlan({ organizationId, plan })- Downgrade subscriptionsetCustomLimits({ organizationId, customLimits })- Override plan limits (admin)
- Polar.sh for payment processing
- Usage tracking and enforcement
- Automatic limit checks
AI Features
AI Question Generation (convex/organizer/aiQuestions.ts)
AI Question Generation (convex/organizer/aiQuestions.ts)
getAIThread({ referenceId })- Get conversation threadgetAIUsage({ organizationId })- Get AI usage stats
generateQuestions({ referenceId, prompt, count, type })- Generate questions with AIsuggestOptions({ questionText, count })- Generate answer optionstranslateQuestion({ questionId, targetLanguage })- Translate questionanalyzeResults({ testId })- AI analysis of test results
- Google Gemini integration
- Conversation context preservation
- Usage tracking and limits
- Multiple question types supported
AI Actions (convex/organizer/aiQuestionActions.ts)
AI Actions (convex/organizer/aiQuestionActions.ts)
acceptGeneratedQuestion({ threadId, questionData })- Accept AI suggestionrejectGeneratedQuestion({ threadId, questionId })- Reject suggestionrefineQuestion({ questionId, refinementPrompt })- Refine with AI
Dashboard & Profile
Dashboard (convex/organizer/dashboard.ts)
Dashboard (convex/organizer/dashboard.ts)
getDashboardStats()- Overview statistics- Total tests (draft, active, scheduled, finished)
- Total participants
- Total questions
- Recent activity
getRecentTests({ limit })- Recent test listgetActiveTestsSummary()- Active tests overviewgetTrendData({ metric, period })- Trend analysis
Profile (convex/organizer/profile.ts)
Profile (convex/organizer/profile.ts)
getProfile()- Get user profile
updateProfile({ name?, email?, avatar? })- Update profileupdatePreferences({ preferences })- Update user preferences
Notifications (convex/organizer/notifications.ts)
Notifications (convex/organizer/notifications.ts)
getNotifications({ paginationOpts })- Get notification batchesgetUnreadCount()- Get unread notification countgetNotificationPreferences()- Get notification settings
markAsRead({ batchKey })- Mark notification batch as readmarkAllAsRead()- Mark all as readupdatePreferences({ preferences })- Update notification preferences
- Participant joined test
- Participant completed test
- Test results available
- Manual grading needed
- Test limit reached
- Member joined organization
Editor & Media
Editor Media (convex/organizer/editorMedia.ts)
Editor Media (convex/organizer/editorMedia.ts)
generateUploadUrl({ filename, contentType })- Get upload URL for rich text imagesdeleteMedia({ url })- Delete uploaded media
- Images in question text
- Images in answer options
- Audio files
- Video files
- Documents
Participant API
Located inconvex/participant/ directory.
Test Taking
Test Taking
getTest({ testId, accessToken? })- Get test for participantgetTestSections({ testId })- Get sections for participantgetCurrentAttempt({ testId, sectionId })- Get active attempt
startTest({ testId, accessToken? })- Start test attemptstartSection({ testId, sectionId })- Start section attemptsubmitAnswer({ attemptId, questionId, answer })- Submit answerflagQuestion({ attemptId, questionId })- Flag for reviewfinishSection({ attemptId })- Complete sectionfinishTest({ testId })- Complete test
Results
Results
getMyResults({ testId })- Get participant’s results (if released)getMyAnswers({ testId })- Get participant’s submitted answers
Internal API
Located inconvex/internal/ directory. Only callable by backend.
Scheduled Functions
Scheduled Functions
activateTest({ testId })- Activate scheduled testfinishTest({ testId })- Finish test at scheduled timecleanupStalePresence()- Remove stale presence recordsresetMonthlyUsage()- Reset usage counters (monthly cron)
sendInvitationEmail({ email, token, organizationName })- Send invitesendTestReminderEmail({ testId, participantEmail })- Send reminder
Notifications
Notifications
createNotification({ organizationId, type, ... })- Create notification eventbatchNotifications({ organizationId })- Group notifications
Common Utilities
Located inconvex/common/ directory.
Permissions (convex/common/permissions.ts)
Permissions (convex/common/permissions.ts)
Storage (convex/common/storage.ts)
Storage (convex/common/storage.ts)
Usage (convex/common/usage.ts)
Usage (convex/common/usage.ts)
Email (convex/common/email.ts)
Email (convex/common/email.ts)
API Conventions
Input Validation
All function arguments are validated using Convex validators:Error Handling
Always useConvexError for throwing errors:
Pagination
Use Convex’s pagination pattern:Soft Deletes
Always filter out soft-deleted records:Type Safety
All Convex functions are fully type-safe:- Arguments are validated at runtime
- Return types are inferred automatically
- Frontend hooks are type-safe
- No manual type definitions needed
Rate Limiting
Plan limits are enforced automatically:- AI usage tracked per organization per month
- Active tests limited by plan
- Concurrent participants limited by plan
- Results generation limited by plan