Version 1.0.3
Release Date: June 11, 2026
Anti-Cheat Flag System
A new proctoring-oriented flag system allows clients to report suspicious behavior during quiz attempts.
Submit Flags
POST /api/v1/attempts/{attempt_id}/flags
{
"labels": ["TAB_SWITCH", "CLIPBOARD"],
"detail": { "window_title": "Chrome - Google Search" },
"question_id": "550e8400-e29b-41d4-a716-446655440000"
}
- Labels are free-form (max 50 chars), stored UPPERCASE.
- The
OXIDE_prefix is reserved for system-generated flags (returns400). - Limits: 20 labels/batch, 300 flags/attempt, 30s grace window after submit.
Flag Timeline & Summary
GET /api/v1/attempts/{attempt_id}/flags
GET /api/v1/quizzes/{quiz_id}/flags/summary
Owners can retrieve a chronological flag timeline per attempt and an aggregate summary (counts by label, top flagged participants) per quiz.
Attempt List Filter
GET /api/v1/info/attempts?isFlagged=true
New isFlagged query parameter filters the attempts list to only flagged entries.
Realtime attempt_flagged Event
Quiz owners subscribed to quiz:<id> receive live attempt_flagged events with labels[], participant_id, alias, and flagged_at. Detail payloads are REST-only.
Ticket History Query
The GET /api/v1/tickets endpoint now supports full history queries.
New Query Parameters
| Parameter | Type | Description |
|---|---|---|
include_inactive | bool | When true, includes revoked, expired, and fully-consumed tickets. Default: false (usable only). |
quiz_id | number | Filter tickets by quiz ID |
event_id | string | Filter tickets by event ID |
page | number | Page number (default: 1) |
per_page | number | Items per page (default: 100, max: 100) |
Before (v1.0.2)
Only active/usable tickets returned — no way to see revoked or consumed history.
After (v1.0.3)
GET /api/v1/tickets?participant_id=...&include_inactive=true&page=1&per_page=20
Returns paginated results including expired, revoked, and fully-consumed tickets.
Attempt Transfer
New endpoint to transfer an attempt from one participant to another.
POST /api/v1/attempts/{attempt_id}/transfer
Useful when a participant was registered under the wrong alias or needs to be merged.
Question Template Improvements
Explanation Field
Question templates now accept an optional explanation field, matching the behavior of regular questions.
Custom Keys on Options
Template options now support arbitrary extra fields via serde(flatten):
{
"label": "A",
"value": "Paris",
"icon": "🇫🇷",
"color": "#0055A4"
}
Custom keys are preserved alongside label and value.
Search & Filter Fixes
- Tag search: now matches questions containing any of the specified tags (OR logic) instead of requiring all tags (AND).
- BM25 fuzzy search: fixed query generation to inline as SQL literal, resolving edge-case parse errors.
- Event status filters: added
upcomingandendedfilters;status=availablecombined withfrom/tonow returnsVAL-001validation error. - Event
tofilter: corrected to properly return only ended/past items when used alone.
Ticket Force-Submit Notifications
When a ticket is issued and the system auto-submits open attempts for that participant, connected clients now receive attempt_finished WebSocket events with reason: "forced_by_owner" (previously silent).
WebSocket Documentation
Full client-facing documentation for the WebSocket realtime API is now available at /docs/websocket, covering:
- Connection authentication (
?token=/?session=) - Channel semantics (
quiz:<id>,notification:<attempt_id>) - All event types with field-level payload tables
- Heartbeat, reconnection guidance