Schemas & error contracts
Use this page together with the Executable contract cookbook. The cookbook identifies every operation; this registry gives the stable JSON and multipart shapes that a UI, agent, or generated client needs to encode and decode. Fields marked write are accepted from a caller. Fields marked read are produced by the service and must not be treated as writable simply because they appear in a response.
HTTP conventions
| Concern | Go API | AI indexer | Agent gateway |
|---|---|---|---|
| Base path | /api/v1/ | / and /v1/index/ | /health, /v1/proxy, /mcp |
| Auth header | Authorization: Bearer <access JWT> on protected routes | Authorization: Bearer <SERVICE_TOKEN> when configured | Optional gateway token on /v1/proxy; each protected downstream call also carries a user JWT in user_token |
| JSON content type | application/json for JSON writes | application/json for writes | application/json for /v1/proxy |
| Multipart | Upload file/class_obj; profile profile_image or image | Never | upload_file converts base64 to multipart internally |
| Trailing slash | Required | Not used by the FastAPI paths shown here | Downstream Go path retains its slash |
Shared response shapes
Go API envelope
Most Go resource operations return the following envelope. Check both the HTTP status and success: readiness can be 503 with a diagnostic object even where the envelope shape is still present.
{
"success": true,
"message": "Class created successfully",
"data": {},
"errors": null
}| Field | Type | Meaning |
|---|---|---|
success | boolean | Application-level result. |
message | string | Human-readable operation result. Do not use as a machine identifier. |
data | object, array, page, or null | Successful payload; selected error handlers also place a detail object here. |
errors | null, object, or validation collection | Structured validation or domain error data when supplied by the handler. |
Pagination
Class, upload, share, friendship, marketplace, library, notification, and similar list handlers use a page object. Send page and page_size where an endpoint advertises pagination; handlers default to page 1 and typically cap page size at 100.
{
"count": 42,
"next": "/api/v1/uploads/?page=2&page_size=20",
"previous": "",
"results": []
}Go error envelope
{
"success": false,
"message": "Invalid input",
"data": null,
"errors": {
"detail": "reason when the handler supplies one"
}
}The token refresh endpoint is intentionally different. Its invalid-token responses are a direct detail object:
{"detail":"Token is invalid or expired"}FastAPI error body
The AI indexer and FastMCP gateway use FastAPI exceptions for transport and validation errors:
{"detail":"Invalid service token"}Authentication schemas
RegistrationRequest — POST /auth/register/
{
"email": "learner@example.com",
"full_name": "Asha Mrema",
"user_type": "student",
"password": "SecurePass9",
"confirm_password": "SecurePass9"
}| Field | Type | Required | Constraints |
|---|---|---|---|
email | string | Yes | Trimmed and lowercased by the handler. |
full_name | string | Yes | Trimmed; cannot be blank. |
user_type | student or lecturer | No | Defaults to student. |
password | string | Yes | At least 8 characters and not entirely numeric. |
confirm_password | string | Yes | Must match password. |
LoginResponse
{
"success": true,
"message": "Login successful",
"data": {
"user": {
"id": 42,
"email": "learner@example.com",
"username": "Asha Mrema",
"user_type": "student",
"is_approved": true,
"university": "Kibegi University",
"phone_number": "+255712345678",
"phone_verified": true,
"profile_image": null,
"profile_image_url": null,
"date_joined": "2026-08-21T09:00:00Z"
},
"tokens": {"refresh":"<JWT>","access":"<JWT>"}
},
"errors": null
}Authentication error matrix
| Operation | HTTP status | Machine-relevant response condition |
|---|---|---|
| Register | 400 | Invalid registration details, duplicate email, or password violation. |
| Login | 401 | message is Invalid email or password. |
| Login | 403 | Lecturer is pending approval. |
| Login or token issue | 503 | Authentication dependency is unavailable. |
| Refresh | 400 | Direct { "detail": "refresh is required" }. |
| Refresh | 401 | Direct { "detail": "Token is invalid or expired" }. |
| Profile / password / phone | 401 | Missing or invalid access JWT. |
| Profile update | 400 | Blank username or malformed JSON. |
| Phone OTP send | 400 | Invalid or duplicate Tanzania number. |
| Phone OTP send | 429 | More than three recent OTP requests for the same number. |
| Phone OTP verify | 400 | Missing, expired, incorrect, or exhausted OTP. |
Core resource schemas
ClassWrite — POST /classes/ and PUT/PATCH /classes/{class_uuid}/
{
"name": "Distributed Systems",
"description": "Term 1 class space",
"is_public": false
}name is mandatory at creation. On update, each field is optional; the authenticated class creator is the only permitted writer.
ClassRead
{
"id": "11111111-2222-3333-4444-555555555555",
"name": "Distributed Systems",
"description": "Term 1 class space",
"class_code": "ABCD12",
"is_public": false,
"is_verified": false,
"creator": 42,
"creator_name": "Asha Mrema",
"member_count": 18,
"is_member": true,
"user_role": "lecturer",
"join_qr_payload": {
"type": "class_join",
"class_code": "ABCD12",
"class_name": "Distributed Systems",
"join_endpoint": "/api/v1/classes/join/"
},
"created_at": "2026-08-21T09:00:00Z",
"updated_at": "2026-08-21T09:00:00Z"
}UploadCreate — multipart POST /uploads/
| Part | Type | Required | Notes |
|---|---|---|---|
file | file bytes | Yes | Maximum 50 MiB. |
class_obj | UUID string | Yes | Target class UUID. |
file_name | string | No | Overrides the client file name used for classification/storage naming. |
UploadRead
{
"id": "11111111-2222-3333-4444-555555555555",
"file_name": "week-01-notes.pdf",
"file_type": "document",
"file_size": 248010,
"file_code": "ABC123",
"file": "uploads/42/week-01-notes.pdf",
"file_url": "https://media.example.com/uploads/42/week-01-notes.pdf",
"uploader": 42,
"uploader_name": "Asha Mrema",
"class_obj": "11111111-2222-3333-4444-555555555555",
"class_name": "Distributed Systems",
"is_deleted": false,
"deleted_at": null,
"created_at": "2026-08-21T09:00:00Z",
"updated_at": "2026-08-21T09:00:00Z"
}ShareCreate and ShareRead
{"file_code":"ABC123","shared_with_id":42,"message":"Please review"}POST /sharing/bulk/ changes shared_with_id to user_ids, an array whose length must be between 1 and 50. A share detail includes id, file metadata, sender/recipient names and IDs, status, message, shared_at, accepted_at, rejected_at, and can_access.
ScheduleEventWrite
{
"title": "Lecture",
"description": "Optional agenda",
"location": "Room A",
"start_at": "2026-09-01T08:00:00Z",
"end_at": "2026-09-01T10:00:00Z",
"event_type": "class",
"recurrence": "weekly",
"days": ["monday"],
"reminder_minutes": 30
}title, start_at, and end_at are the meaningful required event values. start_at and end_at use RFC3339. The recurrence handler understands daily, weekly, and monthly values.
AssignmentWrite
{
"title": "Network report",
"description": "Research a protocol",
"instructions": "Submit a concise report",
"attachment": "uploads/42/brief.pdf",
"due_date": "2026-09-10T16:00:00Z",
"max_score": 100,
"is_active": true,
"allow_late_submission": false
}The request decoder accepts the assignment resource. The path class UUID is authoritative and replaces a caller-supplied class_obj. Read objects also include id, assignment_code, class_obj, created_by, submission_count, my_submission_status, and timestamps.
SubmissionWrite and GradeWrite
{"response_text":"My completed answer","attachment":"uploads/42/answer.pdf","status":"submitted"}{"score":85,"feedback":"Strong reasoning","action":"grade"}status may only be draft or submitted. Grade action may only be grade or return.
AI, search, SMS, and agent schemas
AI Go API
| Operation | Exact request body | Notable validation/error |
|---|---|---|
| Save settings | {"api_key":"provider-key","chat_model":"model-name"} | chat_model is optional; read responses mask keys. |
| Chat | {"message":"Summarize the class","conversation_id":"optional UUID","class_id":"optional UUID"} | message is mandatory and at most 2,000 characters. |
| Upload status | No body. | Returns an existing job or { "status":"not_started", "chunks_created":0 }. |
| Global search | No body; send q, optional categories, and limit as query parameters. | Main q needs at least 2 characters; categories are limited to users, classes, files, friends, and library; limit caps at 50. |
| Suggestions | No body; q and optional limit query parameters. | Suggestion limit caps at 10. |
| SMS top-up | {"amount":100} | Invalid amount or missing account is a handler error; delivery list limit caps at 100. |
AI indexer request and error schema
// POST /v1/index/uploads/{upload_id}
{"force":false}
// POST /v1/index/process-due
{"limit":100,"include_done":false}| Endpoint | Error status | FastAPI body |
|---|---|---|
| Protected indexer route | 401 | { "detail":"Invalid service token" } |
| Job status with unknown upload | 404 | { "detail":"AI processing job not found" } |
| Job/status operation with unavailable database | 503 | { "detail":"<runtime dependency message>" } |
process-due invalid limit | 422 | FastAPI validation detail; limit must be 1–1000. |
Agent proxy and MCP schemas
{
"method": "POST",
"path": "/api/v1/classes/join/",
"user_token": "<end-user Kibegi access JWT>",
"params": null,
"body": {"class_code":"ABCD12"},
"confirm": true
}| Condition | Status | Response |
|---|---|---|
| Gateway ingress token is wrong | 401 | { "detail":"Invalid gateway token" } |
| Path falls outside the migrated allowlist | 400 | { "detail":"Path is outside the exposed Kibegi API namespace" } |
| Non-GET proxy or tool call lacks confirmation | 400 | { "detail":"Mutation requires confirm=true" } |
| Downstream Go response, including error | 200 from gateway transport | { "http_status": <Go status>, "response": <Go payload> } |
Typed upload_file content is invalid base64 | Tool validation failure | content_base64 is invalid before downstream traffic. |
Typed upload_file bytes exceed 50 MiB | Tool validation failure | File exceeds the 50MB Go API limit before downstream traffic. |
Status-code guide for UI states
| Status | UI or agent behavior |
|---|---|
200 | Render the returned detail, state transition, or list. |
201 | Treat as a newly-created record; update local lists from data. |
202 | Show a queued/processing state; for bulk shares, use the returned processing metadata. |
400 | Present field/domain validation from the message, errors, or FastAPI detail; do not retry unchanged input. |
401 | Refresh/re-authenticate the end user, or correct the private service token. |
403 | Preserve the current UI state and show a permissions response; retries will not help until role/access changes. |
404 | Remove or refresh stale route/resource state. |
405 | Client used an unsupported method; treat as an integration bug. |
409 | Resolve duplicate/conflicting state rather than blindly retrying. |
422 | AI indexer/FastAPI body or path failed schema validation. |
429 | Back off; respect the operation’s OTP or global API rate limit. |
500, 502, 503 | Show a recoverable dependency/server error and retry with bounded backoff only for safe operations. |