client.getWebhookEvents().
Event 1 — assessment.sent
Fired from white-collar-assessment-portal-backend when an assessment is sent to candidates and emailNotificationsEnabled is false on the API key.
This event fires once per assessment, batching all candidates into a single payload. It tells your app “these people have been invited to take this assessment at this URL.”
Full JSON stored in Redis
Field reference
Source code (assessment.service.ts)
When this fires vs email
This event only fires whenemailNotificationsEnabled = false on the API key.
Event 2 — assessment.completed
Fired from record-assessment-backend when a candidate submits the exam. See What Gets Stored in Redis — Completed for the full payload.
When a candidate submits an assessment, the backend writes two things into Redis instantly, then your server reads them via client.getWebhookEvents().
Redis key structure (same for both events)
Two keys are written per event:keyId = your API key’s internal ID (from ApiKeyModel — not the VFN_TEST_xxx value itself, but the keyId field on the key document).
eventId = a randomUUID() generated at store time.
How the sorted set is used
getWebhookEvents({ since, limit }):
acknowledgeWebhookEvents([...ids]):
Required environment variable
REDIS_URI (fallback). If neither is set, Redis won’t connect and all webhook storage is silently skipped — assessments still complete, but no events are queued.
What triggers the write
InsidesubmitSession() in exam.controller.ts, after the session is saved:
storeEvent then adds two more fields automatically:
eventId→randomUUID()storedAt→new Date().toISOString()
Exact JSON stored in Redis
This is the complete object that getsJSON.stringify()-ed and written to webhook:events:{keyId}:{eventId}:
Field-by-field source mapping
⚠️ Known gaps
aiFeedback is almost always null when the event is first stored.AI feedback is generated asynchronously after the session is submitted. The webhook event is stored immediately — before the AI has finished. If you need the feedback, either:- Poll the result again later via
GET /exam/session/result - Accept that
aiFeedbackwill benullfor most events at polling time
recording.url may be null at polling time.The recording chunks are combined into a final .mp4 asynchronously after submission. The recording.status will be "processing" until the combine job finishes. The URL only appears once status reaches "ready".Redis connection setup (full .env)
What happens if Redis is not configured
IfREDIS_URL is not set:
- Redis client is
null storeEventthrows"Redis is not connected"- The throw is caught in the fire-and-forget block inside
submitSession - Assessments still complete normally — the session is saved to MongoDB
- No webhook events are queued
- Your poller gets
{ events: [], pendingCount: 0 }every time

