Cognitive Assessment
Overview
This page summarizes the Cognitive Assessment (HK-MoCA) APIs used in GOFA Next.js, including:
- Creating an assessment record (start test)
- Saving/updating results during the flow
- Fetching a single result or a list
- Fetching player history
- Correctly returning to the intended home page (not BaseURL
/)
API Summary
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/cognitive-assessment | Create a cognitive assessment record and return step URLs |
| GET | /api/cognitive-assessment-results | List cognitive assessment results (optional filters) |
| GET | /api/cognitive-assessment-results/[cognitiveAssessmentResultId] | Get a single cognitive assessment result |
| PATCH | /api/cognitive-assessment-results/[cognitiveAssessmentResultId] | Update progress or complete the assessment |
| GET | /api/client/[clientId]/analytics/player/[uid]/cognitive-assessment-history | Get a player’s assessment history (admin) |
Authentication & Access
- All endpoints use
authenticateRequest()validation. Common options:Authorization: Bearer <firebase_id_token>- Or existing Session Cookie (for example, after Kiosk login)
- If
userIdis omitted, the server creates/reuses an anonymous user and returnsfirebaseCustomTokenfor the assessment flow.
In Kiosk flows, you usually obtain a Session first, then call the create API. If firebaseCustomToken is returned, the client should sign in with it so that later PATCH requests can persist partial results.
1) Create an Assessment (POST)
Endpoint: POST /api/cognitive-assessment
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
userId | string | No | Assigns the assessment to a user; if omitted, an anonymous user is created and firebaseCustomToken is returned |
email | string | No | Optional email validation |
photoURL | string | No | Optional photo URL validation |
userInfo | object | No | User snapshot (name/age/gender/height/weight) |
returnUrl | string | No | Return path after completion (must start with / and not //) |
resultMode | string | No | Result display mode: qr (default) or direct |
Query Parameters (Optional)
| Field | Type | Description |
|---|---|---|
resultMode | string | Result display mode: qr (default) or direct |
Response
{
"cognitiveAssessmentResultId": "string",
"basicInfoUrl": "/cognitive-assessment/{id}/basic-info?returnUrl=...",
"memoryRecallUrl": "/cognitive-assessment/{id}/memory-recall?returnUrl=...",
"verbalFluencyUrl": "/cognitive-assessment/{id}/verbal-fluency?returnUrl=...",
"orientationUrl": "/cognitive-assessment/{id}/orientation?returnUrl=...",
"delayedRecallUrl": "/cognitive-assessment/{id}/delayed-recall?returnUrl=...",
"resultsUrl": "/cognitive-assessment/{id}/results?returnUrl=...",
"createdAt": "2026-02-04T08:30:00.000Z",
"returnUrl": "/kiosk/test-selection",
"resultMode": "direct",
"firebaseCustomToken": "<optional>"
}
Example
const response = await fetch('/api/cognitive-assessment', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify({
returnUrl: '/kiosk/test-selection?locale=zh-Hant',
resultMode: 'direct',
userInfo: {
name: 'Alex Chan',
age: 70,
gender: 'male',
heightInCm: 168,
weightInKg: 60,
},
}),
});
const data = await response.json();
// data.cognitiveAssessmentResultId
// data.resultsUrl, etc.
If resultMode is provided, the API appends it to the returned step URLs so clients can open any step and still respect the display mode.
resultMode=qr (default) will show the QR code screen after results are generated. The QR links to /cognitive-assessment/{id}/share, which is the shareable report UI. resultMode=direct skips the QR and opens that same share report UI directly.
resultMode can be passed either in the request body or as a query parameter on POST /api/cognitive-assessment. If both are present, the request body value takes precedence.
returnUrl must be a relative path that starts with / and does not start with //. Invalid values are ignored and the result screen will fall back to / (BaseURL home).
2) Launch the Assessment Page
You can use the returned basicInfoUrl / resultsUrl to jump to a specific step, or enter the main entry route directly:
/cognitive-assessment/{cognitiveAssessmentResultId}?returnUrl=...&resultMode=direct
Recommended Kiosk flow:
- Call
POST /api/cognitive-assessmentto get theid - Navigate to
/cognitive-assessment/{id}?returnUrl=...
This ensures every step and the result screen can return to Kiosk properly.
3) Update / Complete Results (PATCH)
Endpoint: PATCH /api/cognitive-assessment-results/[cognitiveAssessmentResultId]
- Only schema-defined fields are allowed; unknown fields return 400.
id/clientId/createdAtcannot be changed.- When
statusis set tocompleted,completedAtis automatically added.
{
"status": "completed",
"testVersion": "HK-MoCA-5min",
"userAge": 70,
"educationYears": 9,
"scores": {
"memory": 5,
"fluency": 7,
"orientation": 6,
"delayedMemory": 8,
"rawTotal": 26,
"adjustedTotal": 27
},
"educationBonus": 1,
"rawScore": 26,
"totalScore": 27,
"interpretation": "Mild",
"riskLevel": "INTERMEDIATE",
"percentile": 35
}
4) Get a Single Result (GET)
Endpoint: GET /api/cognitive-assessment-results/[cognitiveAssessmentResultId]
{
"data": {
"id": "string",
"clientId": "string",
"createdAt": "2026-02-04T08:30:00.000Z",
"assessmentType": "HK-MoCA",
"rawScore": 26,
"totalScore": 27,
"interpretation": "Mild",
"riskLevel": "INTERMEDIATE"
},
"resultsUrl": "/cognitive-assessment/{id}/results"
}
5) Get Result List (GET)
Endpoint: GET /api/cognitive-assessment-results
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
clientId | string | No | Filter by client ID |
userId | string | No | Filter by user ID |
6) Get Player History (GET)
Endpoint: GET /api/client/[clientId]/analytics/player/[uid]/cognitive-assessment-history
- Admin access (
accessRole: 'admin') - Used by B2B Player Report / admin dashboards
7) Correct Return Handling (Critical)
Why it Matters
If you omit returnUrl, the result page falls back to / (BaseURL home). In Kiosk scenarios, this breaks the kiosk flow.
Recommended Steps
- Pass
returnUrlwhen creating the assessment (prefer returning to Kiosk home or test selection) - Keep
returnUrlin the assessment entry URL (or use the API-provided URLs) - The “Finish Test” action uses
returnUrlto navigate back
When returning to Kiosk test selection, use /kiosk/test-selection?locale=... and ensure cognitiveResultId is included so the kiosk can mark the test as completed (this is auto-handled by the UI).
Kiosk Example
const { cognitiveAssessmentResultId } = await createCognitiveAssessment({
returnUrl: '/kiosk/test-selection?locale=zh-Hant',
});
router.push(
`/cognitive-assessment/${cognitiveAssessmentResultId}?returnUrl=${encodeURIComponent('/kiosk/test-selection?locale=zh-Hant')}&resultMode=direct`
);
Exit to Cognitive Assessment Home (Non-Kiosk)
If the caller wants the Exit/Finish action to go back to the Cognitive Assessment home (instead of gofa.app), set returnUrl to the app’s cognitive assessment entry page. In GOFA Next.js, this is /cognitive-assessment/new.
Do not pass a full URL like https://gofa.app, because it will be rejected by the safety validator.
const returnUrl = '/cognitive-assessment/new';
const { cognitiveAssessmentResultId } = await createCognitiveAssessment({ returnUrl });
router.push(
`/cognitive-assessment/${cognitiveAssessmentResultId}?returnUrl=${encodeURIComponent(returnUrl)}`
);
Return URL Safety Rules
| Rule | Description |
|---|---|
Must start with / | Prevents external redirects |
Must not start with // | Prevents protocol-relative redirects |
| Invalid values are cleared | Result screen falls back to / |
For extended fields or integration details, also see the existing Cognitive Assessment API.