What changed in v2.1. Case studies no longer carry a single
knowledge_base_id; they hold a list of document_ids instead, and the same document can be attached to multiple case studies. New endpoints under /{case_study_id}/documents cover upload, list, attach, detach, and reingest. The legacy knowledge_base_id field has been removed from create/update bodies and from response payloads. knowledge_base_document_count was renamed to document_count.See the Knowledge Base reference for how documents and collections work.Case studies can now also be scoped to specific programmes via the new programme_codes field. An empty list (the default) means the case study is open to all programmes — existing case studies keep working without any tagging.List Case Studies
Authentication
RequiresCASE_STUDIES.can_view permission.
Query parameters
Number of records to skip.
Max records to return (1-100).
Include inactive case studies.
Example request
Response
Get Case Study
Authentication
RequiresCASE_STUDIES.can_view permission.
Path parameters
The case study’s ID.
Example request
Response
Get Case Study Metrics
Authentication
RequiresCASE_STUDIES.can_view permission.
Path parameters
The case study’s ID.
Metric definitions
| Metric | Definition |
|---|---|
students_assigned | Distinct students with an explicit attempt record for this case study. A student becomes “assigned” the moment they’re added to the case study (via the Add Student flows) and given their base attempts. |
students_completed | Distinct students with at least one graded session for this case study. A session is graded when the rubric grader has produced a Grade document. |
average_session_minutes | Mean of elapsed_active_time across sessions for this case study, in minutes, rounded to 1 decimal. Sessions that never started talking (elapsed_active_time == 0) are excluded so abandoned-pre-conversation rows don’t drag the average down. 0.0 if no qualifying sessions exist. |
average_score_percent | Mean of final_score across all graded sessions for this case study, rounded to 1 decimal. Scores are 0–100. 0.0 if no graded sessions exist. |
Example request
Response
Errors
| Status | Code | Condition |
|---|---|---|
404 | NOT_FOUND | The case_study_id does not exist (or belongs to another tenant). |
403 | FORBIDDEN | Caller lacks CASE_STUDIES.can_view. |
Add Student to Case Study
user_created, attempt_record_created) tell the frontend what actually happened.
Student users created here are intended for CAS-SSO instances. They’re created with no password, no invite email, and
status=ACTIVE so they can sign in via CAS immediately. If your instance doesn’t use CAS, students won’t be able to log in until you add an invite/password flow on top.Authentication
RequiresCASE_STUDIES.can_edit permission.
Path parameters
The case study’s ID.
Request body
The student’s full name. Max 255 characters. Split into first/middle/last on save.
The student’s email. Validated as RFC-compliant email.
Programme code (e.g.
MPH). Must already exist for this tenant — see the Programmes endpoint to create one first.Example request
Response
Response fields
true if a new student record was created. false if the email already existed and we just associated them with the case study.true if this is the first time the student was assigned to this case study. false if they already had an attempt record (re-adds are no-ops).The student’s
max_attempts for this case study. Defaults to 3 for new assignments. If the student was previously granted extras, this reflects the current ceiling.Audit logging
Every successful call records anATTEMPT_GRANTED audit event with target_type: "case_study", target_id: <case_study_id>, and metadata including the actor, the target student’s id and email, the programme code, and both creation flags. Re-adds are still audited so the trail is complete.
Errors
| Status | Code | Condition |
|---|---|---|
404 | NOT_FOUND | The case_study_id does not exist (or belongs to another tenant). |
422 | VALIDATION_ERROR | The programme_code does not exist for this tenant, or no Student role is configured. |
403 | FORBIDDEN | Caller lacks CASE_STUDIES.can_edit. |
Bulk Upload Students
Authentication
RequiresCASE_STUDIES.can_edit permission.
Path parameters
The case study’s ID.
Request body
Content-Type: multipart/form-data
A
.csv file with the columns described below. Max size: 5 MiB (~50,000 student rows).CSV format
The file must include these three columns. Header names are case-insensitive and accept either spaces or underscores (Full Name, full_name, FULL NAME all work):
| Column | Required | Description |
|---|---|---|
Full Name | ✓ | The student’s full name. Split into first/middle/last on save. |
Email | ✓ | The student’s email. Validated as RFC-compliant. |
Programme Code | ✓ | Programme code (e.g. MPH). Must already exist for this tenant. |
Example request
Response
errors is an empty array.
Response fields
Total number of data rows in the CSV (excluding the header).
Rows that successfully resulted in a student being assigned (whether newly created or already existing).
Rows that failed validation or processing.
success_count + failure_count == total_records_processed.One entry per failed row. Each contains
row (1-indexed, with row 2 being the first data row — matches what Excel shows), email (the value from that row, or null if missing), and reason (a short human-readable explanation).Validation rules (per row)
The order below is the order checks fire. The first failure for a row wins:- Missing Full Name — empty after strip.
- Missing Email — empty after strip.
- Invalid Email format — fails RFC email validation.
- Missing Programme Code — empty after strip.
- Non-existent Programme: ‘CODE’ — programme code not found for this tenant.
- Duplicate email within file (first seen at row N) — same email appeared on an earlier row.
- Processing error: … — caught at save time (rare; usually a DB or schema issue).
Audit logging
OneATTEMPT_BULK_GRANT audit event is recorded per upload (not per row), with metadata including the actor, the case study id, and the total/success/failure counts. Per-row creates are visible in the user collection’s created_at timestamps if you need finer granularity.
Errors
| Status | Code | Condition |
|---|---|---|
400 | VALIDATION_ERROR | File is empty, missing required headers, malformed CSV, or no data rows. |
404 | NOT_FOUND | The case_study_id does not exist (or belongs to another tenant). |
413 | VALIDATION_ERROR | File exceeds the 5 MiB cap. |
422 | VALIDATION_ERROR | File extension isn’t .csv, or no Student role is configured for the tenant. |
403 | FORBIDDEN | Caller lacks CASE_STUDIES.can_edit. |
errors array of a 200 (or 201) response. The endpoint only returns 4xx when the entire upload can’t be processed.
Create Case Study
avatar field.
Authentication
RequiresCASE_STUDIES.can_create permission.
Request body
Case study title. Max 255 characters.
URL-safe slug. Auto-generated from the title if omitted.
Description. Max 5000 characters.
ID of a reusable case study avatar. Create avatars via the Avatars endpoints.
Media URL (image/video). Max 1000 characters.
Document URL (PDF). Max 1000 characters.
List of instruction strings. Max 20 items.
Session time limit (1-180 minutes).
Custom system prompt for the AI agent.
AI’s opening message. Max 2000 characters.
Override LLM model. Max 100 characters.
Override TTS voice. Max 100 characters.
Override STT language. Max 10 characters.
Programme codes (e.g.
["MPH", "MBA"]) that may access this case study. Validated against the Programmes list. Empty list (default) means open to all programmes — students with any or no programme affiliation will see it.Visible to students.
Documents are attached to a case study via the document endpoints below — not via this body. A newly created case study has
document_ids: [] and no RAG until at least one document is attached.Example request
Response
When
llm_model, tts_voice, or stt_language are null, the tenant’s AI config defaults are used at runtime.Update Case Study
Authentication
RequiresCASE_STUDIES.can_edit permission.
Path parameters
The case study’s ID.
Request body
Updated title.
Updated slug.
Updated description.
ID of a different reusable avatar.
Updated media URL.
Updated document URL.
Updated instructions list.
Updated time limit.
Updated system prompt.
Updated first message.
Override LLM model.
Override TTS voice.
Override STT language.
Replace the programme codes that may access this case study. Pass an empty list to open it to all programmes.
Active status.
Example request
Response
Returns the full updated case study object.Delete Case Study
Authentication
RequiresCASE_STUDIES.can_delete permission.
Path parameters
The case study’s ID.
Example request
Response
Returns the soft-deleted case study object withis_active: false.
Documents
Each case study holds a list ofdocument_ids referencing items in a knowledge base collection. The agent receives that list at session start and uses it to scope retrieval — empty list means no RAG.
The relationship is many-to-many:
- Many documents per case study. A single case study can attach as many documents as it needs — there’s no upper limit beyond what makes sense for retrieval quality. All attached documents are eligible for the agent’s retrieval pool on every user turn.
- Same document across many case studies. A document uploaded once can be attached to any number of case studies. Detaching it from one case study has no effect on the others; the underlying document is shared.
/v1/console/knowledge-base/....
Upload & Attach Document
document_ids in one shot. Requires CASE_STUDIES.can_edit.
By default the file lands in the configured KB_COLLECTION_NAME collection (default case-studies). Pass ?collection=<name> to upload into a different existing collection — useful if you’ve created collections for specific subject areas and want the upload to land there directly.
Path parameters
The case study’s id.
Query parameters
Optional. Target collection name. Must already exist (create it first via the knowledge base collections endpoint). Defaults to
KB_COLLECTION_NAME.Request body
Content-Type: multipart/form-data
The document file to upload.
Example requests
Default collection:Example response
case_study.document_ids and will be picked up by the agent at session start once ingestion finishes.
List Attached Documents
CASE_STUDIES.can_view.
Example response
Attach Existing Documents
CASE_STUDIES.can_edit.
Request body
One or more
KBDocument ids to attach. Every id must reference a non-deleted document in this tenant.Example request
Example response
Returns the full case study detail (same shape as Get Case Study) so the frontend can refresh the editor in one call.Errors
| Status | Code | Condition |
|---|---|---|
404 | NOT_FOUND | One or more document_ids do not exist (or belong to another tenant). The error details list the missing ids. |
Detach Document
document_ids. Detach only — the document is not deleted and remains attachable to other case studies. To hard-delete the document and remove its vectors entirely, use the knowledge base delete endpoint. Requires CASE_STUDIES.can_edit.
Example response
Re-ingest Document
pending, and re-queues ingestion. Useful after the source file has been replaced or you want to refresh the embeddings. The document stays attached to the case study throughout. Requires CASE_STUDIES.can_edit.
List Avatars
Authentication
RequiresCASE_STUDIES.can_view permission.
Query parameters
Number of records to skip.
Max records to return (1-100).
Example request
Response
Get Avatar
Authentication
RequiresCASE_STUDIES.can_view permission.
Path parameters
The avatar’s ID.
Example request
Response
Create Avatar
avatar field.
Authentication
RequiresCASE_STUDIES.can_create permission.
Request body
Avatar name. Max 255 characters.
Avatar image URL. Max 1000 characters.
Character background. Max 2000 characters.
Character role (e.g. “Patient”, “Client”). Max 255 characters.
Tags for categorization. Max 20 items.
Active status.
Example request
Response
Update Avatar
Authentication
RequiresCASE_STUDIES.can_edit permission.
Path parameters
The avatar’s ID.
Request body
Updated name.
Updated image URL.
Updated bio.
Updated role.
Updated tags.
Active status.
Example request
Response
Returns the full updated avatar object.Delete Avatar
Authentication
RequiresCASE_STUDIES.can_delete permission.
Path parameters
The avatar’s ID.