This document provides comprehensive documentation for the LAIGO REST API, including endpoint descriptions, authentication requirements, request/response formats, and example usage.
- Authentication
- Base URL
- Common Headers
- Error Responses
- Student Endpoints
- Instructor Endpoints
- Admin Endpoints
All API endpoints require authentication using AWS Cognito JWT tokens. The token must be included in the Authorization header of each request.
Users authenticate through AWS Cognito and receive an ID token. This token is used for all API requests.
// JavaScript example using AWS Amplify
import { fetchAuthSession } from "aws-amplify/auth";
const session = await fetchAuthSession();
const token = session.tokens?.idToken?.toString();The API uses role-based access control (RBAC) with three authorization levels. Each authorizer validates that the user has the specific role in the database:
- Admin: User must have
adminrole in database to access/admin/*endpoints - Instructor: User must have
instructorrole in database to access/instructor/*endpoints - Student: User must have
studentrole in database to access/student/*endpoints (with some shared endpoint exceptions)
Important: Users must explicitly have the role attached to access endpoints. Having an admin role does NOT automatically grant access to /instructor/* or /student/* endpoints - the user must also have those specific roles in their database record.
https://{api-id}.execute-api.{region}.amazonaws.com/prod
Replace {api-id} and {region} with your API Gateway deployment values.
All requests should include:
Authorization: {cognito-id-token}
Content-Type: application/json
{
"error": "Error message description"
}200- Success400- Bad Request (invalid parameters or request body)401- Unauthorized (missing or invalid token)403- Forbidden (insufficient permissions)404- Not Found (resource doesn't exist)429- Too Many Requests (rate limit exceeded)500- Internal Server Error
Student endpoints require the user to have the student role in the database. The student authorizer validates this role before allowing access to most /student/* endpoints.
Shared Endpoints: Some student endpoints are accessible to any authenticated user regardless of role:
GET /student/profileGET /student/role_labelsGET /student/get_disclaimerPOST /student/accept_disclaimer
Create a new case for the authenticated student.
Endpoint: POST /student/new_case
Query Parameters:
user_id(string, required): ID of the student
Request Body:
{
"case_title": "Employment Dispute",
"case_type": "Employment Law",
"jurisdiction": ["Provincial"],
"case_description": "Client was terminated without cause after 5 years of employment. Seeking wrongful dismissal damages.",
"province": "Ontario",
"statute": "Employment Standards Act, 2000"
}Parameters:
case_title(string, required): Title of the casecase_type(string, required): Broad area of lawjurisdiction(array, required): Array of jurisdiction values (Federal,Provincial, orUnknown)case_description(string, required): Detailed description (1-4000 characters)province(string, required): Province related to the casestatute(string, required): Statute related to the case
Response:
{
"case_id": "uuid",
"case_hash": "abc123def456",
"case_title": "Employment Dispute"
}Example (cURL):
curl -X POST "https://api-id.execute-api.us-east-1.amazonaws.com/prod/student/new_case?user_id=uuid" \
-H "Authorization: eyJraWQiOiJ..." \
-H "Content-Type: application/json" \
-d '{
"case_title": "Employment Dispute",
"case_type": "Employment Law",
"jurisdiction": [
"Provincial"
],
"case_description": "Client was terminated without cause after 5 years of employment. Seeking wrongful dismissal damages.",
"province": "Ontario",
"statute": "Employment Standards Act, 2000"
}'Update case details.
Endpoint: PUT /student/edit_case
Query Parameters:
case_id(string, required): The ID of the case
Request Body:
{
"case_title": "Employment Dispute - Updated",
"case_description": "Updated description...",
"case_type": "Employment Law",
"status": "in_progress",
"jurisdiction": ["Provincial", "Federal"],
"province": "Ontario",
"statute": "Employment Standards Act, 2000"
}Parameters:
case_title(string, required): Title of the casecase_description(string, required): Detailed description (1-4000 characters)case_type(string, required): Broad area of lawstatus(string, required): Case status (in_progress,submitted,reviewed, orarchived)jurisdiction(array, required): Jurisdiction listprovince(string, required): Province/Territorystatute(string, required): Relevant statute details
Response: 200 OK
Example (cURL):
curl -X PUT "https://api-id.execute-api.us-east-1.amazonaws.com/prod/student/edit_case?case_id=uuid" \
-H "Authorization: eyJraWQiOiJ..." \
-H "Content-Type: application/json" \
-d '{
"case_title": "Employment Dispute - Updated",
"case_description": "Updated description...",
"case_type": "Employment Law",
"status": "in_progress",
"jurisdiction": [
"Provincial",
"Federal"
],
"province": "Ontario",
"statute": "Employment Standards Act, 2000"
}'Get comprehensive case data including messages and summaries.
Endpoint: GET /student/case_page
Query Parameters:
case_id(string, required): The case ID
Response:
{
"caseData": {
"case_id": "uuid",
"case_hash": "abc123def456",
"case_title": "Employment Dispute",
"status": "in_progress",
"student_id": "uuid",
"completed_blocks": ["intake"],
"student_notes": "Student notes...",
"jurisdiction": ["Provincial"],
"province": "Ontario",
"statute": "Employment Standards Act, 2000",
"case_type": "Employment Law",
"case_description": "Client was terminated...",
"last_updated": "2024-01-20T14:22:00.000Z"
},
"messages": [
{
"message_id": "uuid",
"message_content": "Great work on the intake section.",
"time_sent": "2024-01-18T09:15:00.000Z",
"instructor_id": "uuid",
"first_name": "Jane",
"last_name": "Smith"
}
],
"summaries": [
{
"summary_id": "uuid",
"case_id": "uuid",
"scope": "block",
"block_context": "intake",
"title": "Intake Facts Summary",
"content": "Summary of intake facts...",
"time_created": "2024-01-16T12:00:00.000Z"
}
]
}Example (cURL):
curl -X GET "https://api-id.execute-api.us-east-1.amazonaws.com/prod/student/case_page?case_id=uuid" \
-H "Authorization: eyJraWQiOiJ..."Archive a case.
Endpoint: PUT /student/archive_case
Query Parameters:
case_id(string, required): The case ID
Response: 200 OK
Example (cURL):
curl -X PUT "https://api-id.execute-api.us-east-1.amazonaws.com/prod/student/archive_case?case_id=uuid" \
-H "Authorization: eyJraWQiOiJ..."Unarchive a case.
Endpoint: PUT /student/unarchive_case
Query Parameters:
case_id(string, required): The case ID
Response: 200 OK
Example (cURL):
curl -X PUT "https://api-id.execute-api.us-east-1.amazonaws.com/prod/student/unarchive_case?case_id=uuid" \
-H "Authorization: eyJraWQiOiJ..."Record that a student viewed a case (for analytics).
Endpoint: PUT /student/view_case
Query Parameters:
case_id(string, required): The case ID
Response: 200 OK
Example (cURL):
curl -X PUT "https://api-id.execute-api.us-east-1.amazonaws.com/prod/student/view_case?case_id=uuid" \
-H "Authorization: eyJraWQiOiJ..."Send a case to assigned instructors for review.
Endpoint: PUT /student/review_case
Query Parameters:
case_id(string, required): The case ID
Request Body (optional):
{
"reviewer_ids": ["instructor-uuid-1", "instructor-uuid-2"]
}Response: 200 OK
Example (cURL):
curl -X PUT "https://api-id.execute-api.us-east-1.amazonaws.com/prod/student/review_case?case_id=uuid" \
-H "Authorization: eyJraWQiOiJ..." \
-H "Content-Type: application/json" \
-d '{
"reviewer_ids": [
"instructor-uuid-1",
"instructor-uuid-2"
]
}'Get all cases for the authenticated student with server-side pagination, search, and status filtering.
Endpoint: GET /student/get_cases
Query Parameters:
page(integer, optional): Page number for pagination, 0-indexed (default: 0)limit(integer, optional): Number of cases per page (default: 12)search(string, optional): Search term for case title, jurisdiction, or case IDstatus(string, optional): Filter by case status (in_progress,submitted,reviewed,archived)
Response:
{
"cases": [
{
"case_id": "uuid",
"case_hash": "abc123def456",
"case_title": "Employment Dispute",
"status": "in_progress",
"jurisdiction": ["Provincial"],
"last_updated": "2024-01-20T14:22:00.000Z"
}
],
"totalCount": 5
}Example (cURL):
curl -X GET "https://api-id.execute-api.us-east-1.amazonaws.com/prod/student/get_cases?page=0&limit=12&search=employment&status=in_progress" \
-H "Authorization: eyJraWQiOiJ..."Save or update student notes for a case.
Endpoint: PUT /student/notes
Query Parameters:
case_id(string, required): The case ID
Request Body:
{
"notes": "Key points to remember:\n- Client was employed for 5 years\n- No written warning before termination\n- Seeking 6 months severance"
}Response: 200 OK
Example (cURL):
curl -X PUT "https://api-id.execute-api.us-east-1.amazonaws.com/prod/student/notes?case_id=uuid" \
-H "Authorization: eyJraWQiOiJ..." \
-H "Content-Type: application/json" \
-d '{
"notes": "Key points to remember:\n- Client was employed for 5 years\n- No written warning before termination\n- Seeking 6 months severance"
}'Get chat history for a case and section.
Endpoint: GET /student/get_messages
Query Parameters:
case_id(string, required): ID of the casesub_route(string, required): The section/block type- Valid values:
intake-facts,legal-analysis,contrarian-analysis,policy-context
- Valid values:
Response:
[
{
"type": "human",
"content": "What are the key legal issues in this employment dispute?"
},
{
"type": "ai",
"content": "Based on the facts you've provided, the key legal issues include:\n1. Wrongful dismissal\n2. Notice period calculation\n3. Mitigation of damages"
}
]Example (cURL):
curl -X GET "https://api-id.execute-api.us-east-1.amazonaws.com/prod/student/get_messages?case_id=uuid&sub_route=intake-facts" \
-H "Authorization: eyJraWQiOiJ..."Generate an AI response for a student message (synchronous, non-streaming).
Note: For real-time streaming responses, use the WebSocket API instead (see WebSocket documentation).
Endpoint: POST /student/text_generation
Query Parameters:
case_id(string, required): ID of the casesub_route(string, required): The section/block type- Valid values:
intake-facts,legal-analysis,contrarian-analysis,policy-context
- Valid values:
Request Body:
{
"message_content": "What are the key legal issues in this case?"
}Response:
{
"session_name": "Employment Dispute - Intake",
"llm_output": "Based on the facts you've provided, the key legal issues include:\n1. Wrongful dismissal\n2. Notice period calculation\n3. Mitigation of damages"
}Example (cURL):
curl -X POST "https://api-id.execute-api.us-east-1.amazonaws.com/prod/student/text_generation?case_id=uuid&sub_route=intake-facts" \
-H "Authorization: eyJraWQiOiJ..." \
-H "Content-Type: application/json" \
-d '{
"message_content": "What are the key legal issues in this case?"
}'Assess student progress and potentially unlock the next block.
Endpoint: POST /student/assess_progress
Request Body:
{
"case_id": "uuid",
"block_type": "intake"
}Parameters:
case_id(string, required): The case IDblock_type(string, required): The block type to assess
Response:
{
"progress": 5,
"reasoning": "You have done an excellent job gathering comprehensive facts and identifying the key parties. You are ready to move forward to issue identification.",
"unlocked": true
}Response Fields:
progress(integer): Score from 0-5 (5 = ready to advance)reasoning(string): Feedback addressing the user directlyunlocked(boolean): Whether the next block was unlocked
Example (cURL):
curl -X POST "https://api-id.execute-api.us-east-1.amazonaws.com/prod/student/assess_progress" \
-H "Authorization: eyJraWQiOiJ..." \
-H "Content-Type: application/json" \
-d '{
"case_id": "uuid",
"block_type": "intake"
}'Generate a summary for a case block or full case.
Endpoint: GET /student/generate_summary
Query Parameters:
case_id(string, required): The case IDsub_route(string, optional): The block type to summarize (default:full-case)- Block types:
intake-facts,legal-analysis,contrarian-analysis,policy-context full-case: Stitches together existing block summaries
- Block types:
Response:
{
"llm_output": "## Intake Facts Summary\n\nThe client was employed for 5 years before being terminated without cause. Key facts include:\n- No written warnings\n- Strong performance reviews\n- Seeking 6 months severance"
}Example (cURL):
curl -X GET "https://api-id.execute-api.us-east-1.amazonaws.com/prod/student/generate_summary?case_id=uuid" \
-H "Authorization: eyJraWQiOiJ..."Get all summaries for a case.
Endpoint: GET /student/get_summaries
Query Parameters:
case_id(string, required): The case ID
Response:
[
{
"summary_id": "uuid",
"case_id": "uuid",
"content": "## Intake Facts Summary\n\nThe client was employed...",
"scope": "block",
"block_context": "intake",
"title": "Intake Facts Summary",
"time_created": "2024-01-16T12:00:00.000Z"
}
]Example (cURL):
curl -X GET "https://api-id.execute-api.us-east-1.amazonaws.com/prod/student/get_summaries?case_id=uuid" \
-H "Authorization: eyJraWQiOiJ..."Delete a summary.
Endpoint: DELETE /student/delete_summary
Query Parameters:
summary_id(integer, required): The ID of the summary to delete
Response:
{
"message": "Summary deleted successfully"
}Example (cURL):
curl -X DELETE "https://api-id.execute-api.us-east-1.amazonaws.com/prod/student/delete_summary?summary_id=1" \
-H "Authorization: eyJraWQiOiJ..."Get all feedback messages for a case.
Endpoint: GET /student/feedback
Query Parameters:
case_id(string, required): The case ID
Response:
[
{
"message_id": "uuid",
"message_content": "Great work on identifying the key legal issues. Consider exploring the jurisdiction's specific statutes on employment law.",
"time_sent": "2024-01-20T14:22:00.000Z",
"first_name": "Jane",
"last_name": "Smith"
}
]Example (cURL):
curl -X GET "https://api-id.execute-api.us-east-1.amazonaws.com/prod/student/feedback?case_id=uuid" \
-H "Authorization: eyJraWQiOiJ..."Generate an S3 presigned URL for audio file upload.
Endpoint: GET /student/generate_presigned_url
Query Parameters:
audio_file_id(string, required): Unique ID for the audio filefile_name(string, required): Name of the filefile_type(string, required): MIME type (e.g.,audio/mpeg,audio/wav)
Response:
{
"presignedurl": "https://s3.amazonaws.com/bucket/path?signature=..."
}Example (cURL):
curl -X GET "https://api-id.execute-api.us-east-1.amazonaws.com/prod/student/generate_presigned_url?audio_file_id=uuid&file_name=interview.mp3&file_type=audio/mpeg" \
-H "Authorization: eyJraWQiOiJ..."Initialize an audio file record in the database.
Endpoint: POST /student/initialize_audio_file
Query Parameters:
audio_file_id(string, required): The audio file IDs3_file_path(string, required): S3 path to the filecase_id(string, required): The case IDtitle(string, required): Title for the audio file
Response: 200 OK
Example (cURL):
curl -X POST "https://api-id.execute-api.us-east-1.amazonaws.com/prod/student/initialize_audio_file?audio_file_id=uuid&s3_file_path=audio/uuid.mp3&case_id=uuid&title=Client Interview" \
-H "Authorization: eyJraWQiOiJ..."Trigger AWS Transcribe to transcribe an audio file.
Note: Transcription results are delivered via WebSocket notification when complete.
Endpoint: GET /student/audio_to_text
Query Parameters:
audio_file_id(string, required): The audio file IDfile_name(string, required): Name of the filefile_type(string, required): File type (e.g.,mp3,wav,m4a)case_title(string, required): Title of the casecase_id(string, required): The case ID
Response: 200 OK (transcription starts asynchronously)
Example (cURL):
curl -X GET "https://api-id.execute-api.us-east-1.amazonaws.com/prod/student/audio_to_text?audio_file_id=uuid&file_name=interview.mp3&file_type=audio/mpeg&case_title=Employment Dispute&case_id=uuid" \
-H "Authorization: eyJraWQiOiJ..."Get all transcriptions for a case.
Endpoint: GET /student/get_transcriptions
Query Parameters:
case_id(string, required): The case ID
Response:
[
{
"audio_file_id": "uuid",
"file_title": "Client Interview",
"timestamp": "2024-01-16T15:30:00.000Z"
}
]Example (cURL):
curl -X GET "https://api-id.execute-api.us-east-1.amazonaws.com/prod/student/get_transcriptions?case_id=uuid" \
-H "Authorization: eyJraWQiOiJ..."Get all instructors assigned to the authenticated student.
Endpoint: GET /student/instructors
Query Parameters:
user_id(string, required): The student's user ID
Response:
[
{
"instructor_name": "Jane Smith"
}
]Example (cURL):
curl -X GET "https://api-id.execute-api.us-east-1.amazonaws.com/prod/student/instructors?user_id=uuid" \
-H "Authorization: eyJraWQiOiJ..."Get the active disclaimer and user's acceptance status.
Endpoint: GET /student/get_disclaimer
Query Parameters: None
Response:
{
"disclaimer_text": "This is a legal disclaimer...",
"last_updated": "2024-01-15T10:30:00.000Z",
"has_accepted": false
}Example (cURL):
curl -X GET "https://api-id.execute-api.us-east-1.amazonaws.com/prod/student/get_disclaimer" \
-H "Authorization: eyJraWQiOiJ..."Mark the disclaimer as accepted by the user.
Endpoint: PUT /student/accept_disclaimer
Query Parameters: None
Request Body: None
Response: 200 OK
Example (cURL):
curl -X PUT "https://api-id.execute-api.us-east-1.amazonaws.com/prod/student/accept_disclaimer" \
-H "Authorization: eyJraWQiOiJ..."Get the current audio file size limit.
Endpoint: GET /student/file_size_limit
Query Parameters: None
Response:
{
"value": "500"
}Example (cURL):
curl -X GET "https://api-id.execute-api.us-east-1.amazonaws.com/prod/student/file_size_limit" \
-H "Authorization: eyJraWQiOiJ..."Get configurable role display labels.
Endpoint: GET /student/role_labels
Query Parameters: None
Response:
{
"student": {
"singular": "Advocate",
"plural": "Advocates"
},
"instructor": {
"singular": "Supervisor",
"plural": "Supervisors"
},
"admin": {
"singular": "Administrator",
"plural": "Administrators"
}
}Instructor endpoints require the user to have the instructor role in the database. The instructor authorizer validates this role before allowing access to any /instructor/* endpoint.
Example (cURL):
curl -X GET "https://api-id.execute-api.us-east-1.amazonaws.com/prod/student/role_labels" \
-H "Authorization: eyJraWQiOiJ..."Get all cases for students assigned to the instructor with server-side pagination, search, and status filtering.
Endpoint: GET /instructor/view_students
Query Parameters:
page(integer, optional): Page number for pagination, 0-indexed (default: 0)limit(integer, optional): Number of cases per page (default: 12)search(string, optional): Search term for case title, student name, jurisdiction, or case IDstatus(string, optional): Filter by case status (in_progress,submitted,reviewed,archived)
Response:
{
"cases": [
{
"case_id": "uuid",
"case_title": "Employment Dispute",
"student_id": "uuid",
"first_name": "John",
"last_name": "Doe",
"status": "in_progress",
"time_created": "2024-01-15T10:30:00.000Z",
"last_updated": "2024-01-20T14:22:00.000Z"
}
],
"totalCount": 15
}Example (cURL):
curl -X GET "https://api-id.execute-api.us-east-1.amazonaws.com/prod/instructor/view_students?page=0&limit=12&search=john&status=submitted" \
-H "Authorization: eyJraWQiOiJ..."Get the name of an instructor by email.
Endpoint: GET /instructor/name
Query Parameters:
user_email(string, required): The email of the instructor
Response:
{
"name": "Jane Smith"
}Example (cURL):
curl -X GET "https://api-id.execute-api.us-east-1.amazonaws.com/prod/instructor/name?user_email=user@example.com" \
-H "Authorization: eyJraWQiOiJ..."Get all students assigned to the authenticated instructor.
Endpoint: GET /instructor/students
Query Parameters: None
Response:
[
{
"student_id": "uuid",
"first_name": "John",
"last_name": "Doe"
}
]Example (cURL):
curl -X GET "https://api-id.execute-api.us-east-1.amazonaws.com/prod/instructor/students" \
-H "Authorization: eyJraWQiOiJ..."Get all cases that have been submitted for review.
Endpoint: GET /instructor/cases_to_review
Query Parameters: None
Response:
[
{
"case_id": "uuid",
"case_title": "Employment Dispute",
"student_id": "uuid",
"student_name": "John Doe",
"submitted_at": "2024-01-20T14:22:00.000Z"
}
]Example (cURL):
curl -X GET "https://api-id.execute-api.us-east-1.amazonaws.com/prod/instructor/cases_to_review" \
-H "Authorization: eyJraWQiOiJ..."Send feedback on a student's case.
Endpoint: PUT /instructor/send_feedback
Query Parameters:
case_id(string, required): The case IDinstructor_id(string, required): The instructor's user ID
Request Body:
{
"message_content": "Great work on identifying the key legal issues. Consider exploring the jurisdiction's specific statutes on employment law."
}Response: 200 OK
Example (cURL):
curl -X PUT "https://api-id.execute-api.us-east-1.amazonaws.com/prod/instructor/send_feedback?case_id=uuid&instructor_id=uuid" \
-H "Authorization: eyJraWQiOiJ..." \
-H "Content-Type: application/json" \
-d '{
"message_content": "Great work on identifying the key legal issues. Consider exploring specific statutes on employment law."
}'Delete a feedback message.
Endpoint: DELETE /instructor/delete_feedback
Query Parameters:
message_id(string, required): The ID of the feedback message to delete
Response:
{
"message": "Feedback deleted successfully"
}Example (cURL):
curl -X DELETE "https://api-id.execute-api.us-east-1.amazonaws.com/prod/instructor/delete_feedback?message_id=uuid" \
-H "Authorization: eyJraWQiOiJ..."Archive a student's case.
Endpoint: PUT /instructor/archive_case
Query Parameters:
case_id(string, required): The ID of the case to archive
Response:
{
"message": "Case archived successfully"
}Example (cURL):
curl -X PUT "https://api-id.execute-api.us-east-1.amazonaws.com/prod/instructor/archive_case?case_id=uuid" \
-H "Authorization: eyJraWQiOiJ..."Unarchive a student's case.
Endpoint: PUT /instructor/unarchive_case
Query Parameters:
case_id(string, required): The ID of the case to unarchive
Response:
{
"message": "Case unarchived successfully"
}Admin endpoints require the user to have the admin role in the database. The admin authorizer validates this role before allowing access to any /admin/* endpoint.
Example (cURL):
curl -X PUT "https://api-id.execute-api.us-east-1.amazonaws.com/prod/instructor/unarchive_case?case_id=uuid" \
-H "Authorization: eyJraWQiOiJ..."Add or remove a single role from a user.
Endpoint: PUT /admin/user_role
Request Body:
{
"email": "user@example.com",
"operation": "add",
"role": "instructor"
}Parameters:
email(string, required): User's email addressoperation(string, required): Eitheraddorremoverole(string, required): Role to add/remove (admin,instructor, orstudent)
Response: 200 OK
Example (cURL):
curl -X PUT "https://api-id.execute-api.us-east-1.amazonaws.com/prod/admin/user_role" \
-H "Authorization: eyJraWQiOiJ..." \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"operation": "add",
"role": "instructor"
}'Create an instructor-student relationship.
Endpoint: POST /admin/assign_instructor_to_student
Request Body:
{
"instructor_id": "instructor-uuid",
"student_id": "student-uuid"
}Response: 200 OK
Example (cURL):
curl -X POST "https://api-id.execute-api.us-east-1.amazonaws.com/prod/admin/assign_instructor_to_student" \
-H "Authorization: eyJraWQiOiJ..." \
-H "Content-Type: application/json" \
-d '{
"instructor_id": "instructor-uuid",
"student_id": "student-uuid"
}'Remove an instructor-student relationship.
Endpoint: DELETE /admin/assign_instructor_to_student
Query Parameters:
instructor_id(string, required): Instructor's user IDstudent_id(string, required): Student's user ID
Response: 200 OK
Example (cURL):
curl -X DELETE "https://api-id.execute-api.us-east-1.amazonaws.com/prod/admin/assign_instructor_to_student?instructor_id=uuid&student_id=uuid" \
-H "Authorization: eyJraWQiOiJ..."Get all students assigned to a specific instructor.
Endpoint: GET /admin/instructorStudents
Query Parameters:
instructor_id(string, required): The instructor's user ID
Response:
[
{
"user_id": "uuid",
"first_name": "John",
"last_name": "Doe",
"user_email": "john.doe@example.com"
}
]Example (cURL):
curl -X GET "https://api-id.execute-api.us-east-1.amazonaws.com/prod/admin/instructorStudents?instructor_id=uuid" \
-H "Authorization: eyJraWQiOiJ..."Get a paginated list of all users with optional search and role filtering.
Endpoint: GET /admin/users
Query Parameters:
page(integer, optional): Page number for pagination (default: 0)limit(integer, optional): Number of items per page (default: 10)search(string, optional): Search term for first name, last name, or emailrole(string, optional): Filter by role (admin,instructor,student, orall)
Response:
{
"users": [
{
"user_id": "uuid",
"first_name": "John",
"last_name": "Doe",
"user_email": "john.doe@example.com",
"roles": ["student"],
"time_account_created": "2024-01-15T10:30:00.000Z",
"last_sign_in": "2024-01-20T14:22:00.000Z"
}
],
"totalCount": 42
}Example (cURL):
curl -X GET "https://api-id.execute-api.us-east-1.amazonaws.com/prod/admin/users" \
-H "Authorization: eyJraWQiOiJ..."Get a list of all users with the instructor role.
Endpoint: GET /admin/instructors
Query Parameters: None
Response:
[
{
"user_id": "uuid",
"first_name": "Jane",
"last_name": "Smith",
"user_email": "jane.smith@example.com"
}
]Example (cURL):
curl -X GET "https://api-id.execute-api.us-east-1.amazonaws.com/prod/admin/instructors" \
-H "Authorization: eyJraWQiOiJ..."Get a list of all users with the student role.
Endpoint: GET /admin/students
Query Parameters: None
Response:
[
{
"user_id": "uuid",
"first_name": "John",
"last_name": "Doe",
"user_email": "john.doe@example.com"
}
]Example (cURL):
curl -X GET "https://api-id.execute-api.us-east-1.amazonaws.com/prod/admin/students" \
-H "Authorization: eyJraWQiOiJ..."Get only the currently active prompt versions.
Endpoint: GET /admin/prompt/active
Query Parameters: None
Response:
[
{
"prompt_version_id": "uuid",
"category": "reasoning",
"prompt_scope": "block",
"block_type": "intake",
"version_number": 1,
"version_name": "Initial Version",
"prompt_text": "You are a helpful legal assistant...",
"time_created": "2024-01-15T10:30:00.000Z"
}
]Example (cURL):
curl -X GET "https://api-id.execute-api.us-east-1.amazonaws.com/prod/admin/prompt/active" \
-H "Authorization: eyJraWQiOiJ..."Create a new prompt version.
Endpoint: POST /admin/prompt
Request Body:
{
"category": "summary",
"prompt_scope": "full_case",
"block_type": null,
"prompt_text": "Synthesize all block summaries into one full-case legal summary...",
"version_name": "Full Case Synthesis v1",
"author_id": "uuid"
}{
"category": "summary",
"prompt_scope": "block",
"block_type": "intake",
"prompt_text": "Generate an intake summary from interview notes...",
"version_name": "Intake Summary v2",
"author_id": "uuid"
}Parameters:
category(string, required): Prompt category (reasoning,assessment, orsummary)prompt_scope(string, optional): Prompt scope (blockorfull_case). Defaults toblock.block_type(string, conditionally required): Required whenprompt_scope=block; omit/null whenprompt_scope=full_caseprompt_text(string, required): The prompt contentversion_name(string, optional): Human-friendly version nameauthor_id(string, optional): Author's user ID
Response:
{
"prompt_version_id": "uuid",
"category": "summary",
"prompt_scope": "full_case",
"block_type": null,
"version_number": 2,
"version_name": "Full Case Synthesis v1",
"prompt_text": "Synthesize all block summaries into one full-case legal summary...",
"author_id": "uuid",
"is_active": false
}Example (cURL):
curl -X POST "https://api-id.execute-api.us-east-1.amazonaws.com/prod/admin/prompt" \
-H "Authorization: eyJraWQiOiJ..." \
-H "Content-Type: application/json" \
-d '{
"category": "summary",
"prompt_scope": "full_case",
"block_type": null,
"prompt_text": "Synthesize all block summaries into one full-case legal summary...",
"version_name": "Full Case Synthesis v1",
"author_id": "uuid"
}'Update an existing prompt version.
Endpoint: PUT /admin/prompt
Request Body:
{
"prompt_version_id": "2",
"prompt_text": "Updated prompt text...",
"version_name": "Version 2.1"
}Parameters:
prompt_version_id(string, required): The ID of the prompt version to updateprompt_text(string, required): Updated prompt contentversion_name(string, required): Updated version name
Response: 200 OK
Example (cURL):
curl -X PUT "https://api-id.execute-api.us-east-1.amazonaws.com/prod/admin/prompt" \
-H "Authorization: eyJraWQiOiJ..." \
-H "Content-Type: application/json" \
-d '{
"prompt_version_id": "2",
"prompt_text": "Updated prompt text...",
"version_name": "Version 2.1"
}'Set a prompt version as the active version for its scope slot.
- For
prompt_scope=block: one active prompt per(category, block_type). - For
prompt_scope=full_case: one active prompt percategory.
Endpoint: POST /admin/prompt/activate
Request Body:
{
"prompt_version_id": 2
}Response:
{
"message": "Prompt activated successfully",
"category": "summary",
"prompt_scope": "full_case",
"block_type": null
}Example (cURL):
curl -X POST "https://api-id.execute-api.us-east-1.amazonaws.com/prod/admin/prompt/activate" \
-H "Authorization: eyJraWQiOiJ..." \
-H "Content-Type: application/json" \
-d '{
"prompt_version_id": 2
}'Delete a prompt version (cannot delete active prompts).
Endpoint: DELETE /admin/prompt
Query Parameters:
prompt_version_id(integer, required): The ID of the prompt version to delete
Response:
{
"message": "Prompt deleted successfully",
"category": "summary",
"prompt_scope": "full_case",
"block_type": null
}Example (cURL):
curl -X DELETE "https://api-id.execute-api.us-east-1.amazonaws.com/prod/admin/prompt?prompt_version_id=1" \
-H "Authorization: eyJraWQiOiJ..."Get all prompt versions across all categories and block types.
Endpoint: GET /admin/prompt
Query Parameters:
category(string, optional): Filter by prompt categoryblock_type(string, optional): Filter by block type (for block-scope prompts)prompt_scope(string, optional): Filter by scope (blockorfull_case)
Response:
[
{
"prompt_version_id": "uuid",
"category": "reasoning",
"prompt_scope": "block",
"block_type": "intake",
"version_number": 1,
"version_name": "Initial Version",
"prompt_text": "You are a helpful legal assistant...",
"author_id": "uuid",
"time_created": "2024-01-15T10:30:00.000Z",
"is_active": true
}
]Example (cURL):
curl -X GET "https://api-id.execute-api.us-east-1.amazonaws.com/prod/admin/prompt" \
-H "Authorization: eyJraWQiOiJ..."Example (full-case summary prompt):
curl -X GET "https://api-id.execute-api.us-east-1.amazonaws.com/prod/admin/prompt?category=summary&prompt_scope=full_case" \
-H "Authorization: eyJraWQiOiJ..."Retrieve current AI model configuration parameters.
Endpoint: GET /admin/ai_config
Query Parameters: None
Response:
{
"bedrock_llm_id": "meta.llama3-70b-instruct-v1:0",
"model_options": [
{
"label": "Claude 3 Sonnet",
"value": "anthropic.claude-3-sonnet-20240229-v1:0",
"constraints": {
"maxOutputTokens": 2048,
"defaultMaxOutputTokens": 1500,
"temperatureRange": [0, 1.0],
"topPRange": [0, 1.0]
}
},
{
"label": "Llama 3 70b Instruct",
"value": "meta.llama3-70b-instruct-v1:0",
"constraints": {
"maxOutputTokens": 8192,
"defaultMaxOutputTokens": 2000,
"temperatureRange": [0, 1.0],
"topPRange": [0, 1.0]
}
}
],
"temperature": "0.7",
"top_p": "0.9",
"max_tokens": "2048",
"message_limit": "50",
"file_size_limit": "500"
}Example (cURL):
curl -X GET "https://api-id.execute-api.us-east-1.amazonaws.com/prod/admin/ai_config" \
-H "Authorization: eyJraWQiOiJ..."Update AI model configuration parameters.
Endpoint: POST /admin/ai_config
Request Body:
{
"bedrock_llm_id": "meta.llama3-70b-instruct-v1:0",
"temperature": 0.7,
"top_p": 0.9,
"max_tokens": 2048,
"message_limit": "50",
"file_size_limit": "500"
}Parameters:
bedrock_llm_id(string, optional): AWS Bedrock model IDtemperature(number, optional): Controls randomness (0.0 to 1.0)top_p(number, optional): Controls diversity (0.0 to 1.0)max_tokens(integer, optional): Maximum tokens in response (minimum: 1)message_limit(string, optional): Daily message limit per user (>= 10 or "Infinity")file_size_limit(string, optional): Max audio file size in MB (1-500)
Validation note: If bedrock_llm_id is provided, it must match one of the configured model options. If temperature, top_p, or max_tokens are provided, they are validated against the selected model's constraints.
Model constraints note: max_tokens is the maximum output tokens. It does not limit input tokens.
Response: 200 OK
Example (cURL):
curl -X POST "https://api-id.execute-api.us-east-1.amazonaws.com/prod/admin/ai_config" \
-H "Authorization: eyJraWQiOiJ..." \
-H "Content-Type: application/json" \
-d '{
"bedrock_llm_id": "meta.llama3-70b-instruct-v1:0",
"temperature": 0.7,
"top_p": 0.9,
"max_tokens": 2048,
"message_limit": "50",
"file_size_limit": "500"
}'Get the current daily message limit.
Endpoint: GET /admin/message_limit
Query Parameters: None
Response:
{
"value": "50"
}Example (cURL):
curl -X GET "https://api-id.execute-api.us-east-1.amazonaws.com/prod/admin/message_limit" \
-H "Authorization: eyJraWQiOiJ..."Update the daily message limit per user.
Endpoint: PUT /admin/message_limit
Request Body:
{
"limit": "100"
}Parameters:
limit(string, required): Message limit value (number >= 10 or "Infinity")
Response: 200 OK
Example (cURL):
curl -X PUT "https://api-id.execute-api.us-east-1.amazonaws.com/prod/admin/message_limit" \
-H "Authorization: eyJraWQiOiJ..." \
-H "Content-Type: application/json" \
-d '{
"limit": "100"
}'Get the current audio file size limit.
Endpoint: GET /admin/file_size_limit
Query Parameters: None
Response:
{
"value": "500"
}Example (cURL):
curl -X GET "https://api-id.execute-api.us-east-1.amazonaws.com/prod/admin/file_size_limit" \
-H "Authorization: eyJraWQiOiJ..."Update the audio file size limit.
Endpoint: POST /admin/file_size_limit
Request Body:
{
"value": "500"
}Parameters:
value(string, required): File size limit in MB (1-500)
Response: 200 OK
Example (cURL):
curl -X POST "https://api-id.execute-api.us-east-1.amazonaws.com/prod/admin/file_size_limit" \
-H "Authorization: eyJraWQiOiJ..." \
-H "Content-Type: application/json" \
-d '{
"value": "500"
}'Create a new disclaimer version.
Endpoint: POST /admin/disclaimer
Request Body:
{
"disclaimer_text": "This is a legal disclaimer...",
"version_name": "Version 2.0",
"author_id": "uuid"
}Parameters:
disclaimer_text(string, required): The disclaimer contentversion_name(string, optional): Human-friendly version nameauthor_id(string, optional): Author's user ID
Response: 200 OK
Example (cURL):
curl -X POST "https://api-id.execute-api.us-east-1.amazonaws.com/prod/admin/disclaimer" \
-H "Authorization: eyJraWQiOiJ..." \
-H "Content-Type: application/json" \
-d '{
"disclaimer_text": "This is a legal disclaimer...",
"version_name": "Version 2.0",
"author_id": "uuid"
}'Update an existing disclaimer version.
Endpoint: PUT /admin/disclaimer
Request Body:
{
"disclaimer_id": "uuid",
"disclaimer_text": "Updated disclaimer text...",
"version_name": "Version 2.1"
}Response: 200 OK
Example (cURL):
curl -X PUT "https://api-id.execute-api.us-east-1.amazonaws.com/prod/admin/disclaimer" \
-H "Authorization: eyJraWQiOiJ..." \
-H "Content-Type: application/json" \
-d '{
"disclaimer_id": "uuid",
"disclaimer_text": "Updated disclaimer text...",
"version_name": "Version 2.1"
}'Set a disclaimer version as the active version.
Endpoint: POST /admin/disclaimer/activate
Request Body:
{
"disclaimer_id": "uuid"
}Response:
{
"message": "Disclaimer activated successfully"
}Example (cURL):
curl -X POST "https://api-id.execute-api.us-east-1.amazonaws.com/prod/admin/disclaimer/activate" \
-H "Authorization: eyJraWQiOiJ..." \
-H "Content-Type: application/json" \
-d '{
"disclaimer_id": "uuid"
}'Delete a disclaimer version (cannot delete active disclaimer).
Endpoint: DELETE /admin/disclaimer
Query Parameters:
disclaimer_id(string, required): The ID of the disclaimer version to delete
Response:
{
"message": "Disclaimer deleted successfully"
}Example (cURL):
curl -X DELETE "https://api-id.execute-api.us-east-1.amazonaws.com/prod/admin/disclaimer?disclaimer_id=uuid" \
-H "Authorization: eyJraWQiOiJ..."Get all disclaimer versions.
Endpoint: GET /admin/disclaimer
Query Parameters: None
Response:
[
{
"disclaimer_id": "uuid",
"disclaimer_text": "This is a legal disclaimer...",
"version_number": 1,
"version_name": "Initial Version",
"author_id": "uuid",
"author_name": "John Doe",
"time_created": "2024-01-15T10:30:00.000Z",
"last_updated": "2024-01-15T10:30:00.000Z",
"is_active": true
}
]Example (cURL):
curl -X GET "https://api-id.execute-api.us-east-1.amazonaws.com/prod/admin/disclaimer" \
-H "Authorization: eyJraWQiOiJ..."Update configurable role display labels for the UI.
Endpoint: PUT /admin/role_labels
Request Body:
{
"student": {
"singular": "Advocate",
"plural": "Advocates"
},
"instructor": {
"singular": "Supervisor",
"plural": "Supervisors"
},
"admin": {
"singular": "Administrator",
"plural": "Administrators"
}
}Parameters:
- Each role requires
singularandplurallabels (max 64 characters each)
Response:
{
"message": "Role labels updated successfully"
}Example (cURL):
curl -X PUT "https://api-id.execute-api.us-east-1.amazonaws.com/prod/admin/role_labels" \
-H "Authorization: eyJraWQiOiJ..." \
-H "Content-Type: application/json" \
-d '{
"student": {
"singular": "Advocate",
"plural": "Advocates"
},
"instructor": {
"singular": "Supervisor",
"plural": "Supervisors"
},
"admin": {
"singular": "Administrator",
"plural": "Administrators"
}
}'Retrieve the current signup mode from SSM.
Endpoint: GET /admin/signup_mode
Query Parameters: None
Response:
{
"mode": "public"
}Modes: public (anyone can sign up) or whitelist (only whitelisted emails can sign up).
Example (cURL):
curl -X GET "https://api-id.execute-api.us-east-1.amazonaws.com/prod/admin/signup_mode" \
-H "Authorization: eyJraWQiOiJ..."Set the signup mode in SSM.
Endpoint: PUT /admin/signup_mode
Request Body:
{
"mode": "whitelist"
}Parameters:
mode(string, required): Eitherpublicorwhitelist.
Response:
{
"mode": "whitelist"
}Example (cURL):
curl -X PUT "https://api-id.execute-api.us-east-1.amazonaws.com/prod/admin/signup_mode" \
-H "Authorization: eyJraWQiOiJ..." \
-H "Content-Type: application/json" \
-d '{
"mode": "whitelist"
}'Retrieve all emails currently in the whitelist.
Endpoint: GET /admin/whitelist
Query Parameters: None
Response:
{
"count": 1,
"entries": [
{
"email": "student@example.com",
"canonical_role": "student",
"uploaded_label": "Law Student"
}
]
}Example (cURL):
curl -X GET "https://api-id.execute-api.us-east-1.amazonaws.com/prod/admin/whitelist" \
-H "Authorization: eyJraWQiOiJ..."Generate a presigned upload URL, upload your CSV to S3, then process it into whitelist entries.
Endpoint: GET /admin/whitelist/upload
Query Parameters: None
Response:
{
"uploadUrl": "https://bucket.s3.ca-central-1.amazonaws.com/whitelist-1711122334455.csv?...",
"s3Key": "whitelist-1711122334455.csv",
"expiresIn": 3600
}Example (cURL):
curl -X GET "https://api-id.execute-api.us-east-1.amazonaws.com/prod/admin/whitelist/upload" \
-H "Authorization: eyJraWQiOiJ..."Parse and apply an uploaded CSV to the whitelist.
Endpoint: POST /admin/whitelist/upload
Request Body:
{
"s3Key": "whitelist-1711122334455.csv"
}Request Body Parameters:
s3Key(string, required): Key of a CSV previously uploaded to S3 using the presigned URL
CSV Format:
- Column 1: Email address
- Column 2: Role (either canonical name or singular label defined in Role Label Configuration)
- Header row is optional (skipped if second column is literally "role")
Response:
{
"processed": 2,
"invalid": 0,
"invalidRows": []
}Example (cURL):
curl -X POST "https://api-id.execute-api.us-east-1.amazonaws.com/prod/admin/whitelist/upload" \
-H "Authorization: eyJraWQiOiJ..." \
-H "Content-Type: application/json" \
-d '{
"s3Key": "whitelist-1234567891022.csv"
}'Remove an email from the whitelist.
Endpoint: DELETE /admin/whitelist
Query Parameters:
email(string, required): The email to remove
Response:
{
"message": "Entry removed",
"email": "student1@example.com"
}Example (cURL):
curl -X DELETE "https://api-id.execute-api.us-east-1.amazonaws.com/prod/admin/whitelist?email=student1@example.com" \
-H "Authorization: eyJraWQiOiJ..."import { fetchAuthSession } from "aws-amplify/auth";
// 1. Get authentication token
const session = await fetchAuthSession();
const token = session.tokens?.idToken?.toString();
const userId = session.tokens?.idToken?.payload?.sub;
// 2. Create a new case
const createResponse = await fetch(
`${API_ENDPOINT}/student/new_case?user_id=${userId}`,
{
method: "POST",
headers: {
Authorization: token,
"Content-Type": "application/json",
},
body: JSON.stringify({
case_title: "Employment Dispute",
case_type: "Employment Law",
jurisdiction: ["Provincial"],
case_description: "Client was terminated without cause after 5 years of employment.",
province: "Ontario",
statute: "Employment Standards Act, 2000",
}),
}
);
const { case_id } = await createResponse.json();
// 3. Send a message to the AI assistant
const messageResponse = await fetch(
`${API_ENDPOINT}/student/text_generation?case_id=${case_id}&sub_route=intake-facts`,
{
method: "POST",
headers: {
Authorization: token,
"Content-Type": "application/json",
},
body: JSON.stringify({
message_content: "What are the key legal issues in this case?",
}),
}
);
const { llm_output } = await messageResponse.json();
console.log("AI Response:", llm_output);
// 4. Get chat history
const messagesResponse = await fetch(
`${API_ENDPOINT}/student/get_messages?case_id=${case_id}&sub_route=intake-facts`,
{
headers: { Authorization: token },
}
);
const messages = await messagesResponse.json();
console.log("Chat History:", messages);
// 5. Generate a summary
const summaryResponse = await fetch(
`${API_ENDPOINT}/student/generate_summary?case_id=${case_id}&sub_route=intake-facts`,
{
headers: { Authorization: token },
}
);
const summary = await summaryResponse.json();
console.log("Summary:", summary.llm_output);import requests
API_ENDPOINT = "https://api-id.execute-api.us-east-1.amazonaws.com/prod"
token = "eyJraWQiOiJ..." # Cognito ID token
# 1. Create a new case
create_response = requests.post(
f"{API_ENDPOINT}/student/new_case",
params={"user_id": "cognito-user-uuid"},
headers={"Authorization": token},
json={
"case_title": "Employment Dispute",
"case_type": "Employment Law",
"jurisdiction": ["Provincial"],
"case_description": "Client was terminated without cause after 5 years.",
"province": "Ontario",
"statute": "Employment Standards Act, 2000"
}
)
case_id = create_response.json()["case_id"]
# 2. Send a message to the AI assistant
message_response = requests.post(
f"{API_ENDPOINT}/student/text_generation",
params={"case_id": case_id, "sub_route": "intake-facts"},
headers={"Authorization": token},
json={"message_content": "What are the key legal issues?"}
)
print("AI Response:", message_response.json()["llm_output"])
# 3. Assess progress
assess_response = requests.post(
f"{API_ENDPOINT}/student/assess_progress",
headers={"Authorization": token},
json={"case_id": case_id, "block_type": "intake"}
)
assessment = assess_response.json()
print(f"Progress: {assessment['progress']}/5")
print(f"Feedback: {assessment['reasoning']}")
# 4. Generate a summary
summary_response = requests.get(
f"{API_ENDPOINT}/student/generate_summary",
params={"case_id": case_id, "sub_route": "intake-facts"},
headers={"Authorization": token}
)
print("Summary:", summary_response.json()["llm_output"])
# 5. Submit for review
requests.put(
f"{API_ENDPOINT}/student/review_case",
params={"case_id": case_id},
headers={"Authorization": token},
json={"reviewer_ids": ["instructor-uuid"]}
)// 1. Generate presigned URL
const audioFileId = crypto.randomUUID();
const urlResponse = await fetch(
`${API_ENDPOINT}/student/generate_presigned_url?audio_file_id=${audioFileId}&file_name=interview.mp3&file_type=audio/mpeg`,
{ headers: { Authorization: token } }
);
const { presignedurl } = await urlResponse.json();
// 2. Upload file to S3
await fetch(presignedurl, {
method: "PUT",
body: audioFile,
headers: { "Content-Type": "audio/mpeg" },
});
// 3. Initialize audio file record
await fetch(
`${API_ENDPOINT}/student/initialize_audio_file?audio_file_id=${audioFileId}&s3_file_path=audio/${audioFileId}.mp3&case_id=${caseId}&title=Client Interview`,
{ method: "POST", headers: { Authorization: token } }
);
// 4. Trigger transcription (results delivered via WebSocket)
await fetch(
`${API_ENDPOINT}/student/audio_to_text?audio_file_id=${audioFileId}&file_name=interview&file_type=mp3&case_title=Employment Dispute&case_id=${caseId}`,
{ headers: { Authorization: token } }
);// 1. List all users with search and filtering
const usersResponse = await fetch(
`${API_ENDPOINT}/admin/users?page=0&limit=20&search=john&role=student`,
{ headers: { Authorization: token } }
);
const { users, totalCount } = await usersResponse.json();
// 2. Add instructor role to a user
await fetch(`${API_ENDPOINT}/admin/user_role`, {
method: "PUT",
headers: {
Authorization: token,
"Content-Type": "application/json",
},
body: JSON.stringify({
email: "john.doe@example.com",
operation: "add",
role: "instructor",
}),
});
// 3. Get all instructors
const instructorsResponse = await fetch(
`${API_ENDPOINT}/admin/instructors`,
{ headers: { Authorization: token } }
);
const instructors = await instructorsResponse.json();
// 4. Assign instructor to student
await fetch(`${API_ENDPOINT}/admin/assign_instructor_to_student`, {
method: "POST",
headers: {
Authorization: token,
"Content-Type": "application/json",
},
body: JSON.stringify({
instructor_id: instructors[0].user_id,
student_id: users[0].user_id,
}),
});
// 5. Get students assigned to instructor
const studentsResponse = await fetch(
`${API_ENDPOINT}/admin/instructorStudents?instructor_id=${instructors[0].user_id}`,
{ headers: { Authorization: token } }
);
const assignedStudents = await studentsResponse.json();# 1. Get cases pending review
cases_response = requests.get(
f"{API_ENDPOINT}/instructor/cases_to_review",
headers={"Authorization": token}
)
cases = cases_response.json()
# 2. Send feedback on a case
case_id = cases[0]["case_id"]
requests.put(
f"{API_ENDPOINT}/instructor/send_feedback",
params={
"case_id": case_id,
"instructor_id": instructor_id
},
headers={"Authorization": token},
json={
"message_content": "Great work on identifying the key legal issues. Consider exploring the jurisdiction's specific statutes on employment law."
}
)
# 3. Archive the case after review
requests.put(
f"{API_ENDPOINT}/instructor/archive_case",
params={"case_id": case_id},
headers={"Authorization": token}
)The API implements rate limiting at multiple levels:
- Per IP: 2000 requests per 5 minutes
- Per User: 200 requests per 5 minutes (based on Authorization header)
- Daily Message Limit: Configurable per-user daily message limit (default: 50 messages)
- Applies to AI chat interactions
- Returns
429 Too Many Requestswhen exceeded - Resets daily at midnight UTC
- Implement exponential backoff for retries
- Cache responses when appropriate
- Use WebSocket for real-time streaming instead of polling
- Monitor rate limit headers in responses
- ID tokens expire after 1 hour
- Use refresh tokens to obtain new ID tokens
- Never expose tokens in logs or client-side code
- Store tokens securely (use AWS Amplify for automatic secure storage)
All endpoints support CORS with the following headers:
Access-Control-Allow-Origin: *Access-Control-Allow-Methods: *Access-Control-Allow-Headers: Content-Type,X-Amz-Date,Authorization,X-Api-Key
All responses include security headers:
X-Content-Type-Options: nosniffX-Frame-Options: DENYContent-Security-Policy: default-src 'none'; frame-ancestors 'none';Strict-Transport-Security: max-age=31536000; includeSubDomains
- All request bodies are validated against schemas
- Query parameters are type-checked
- File uploads are validated for size and type
- PII detection via AWS Bedrock Guardrails
For real-time streaming AI responses, notifications, and bidirectional communication, use the WebSocket API. See the WebSocket Implementation Guide for detailed documentation.
WebSocket URL:
wss://{websocket-api-id}.execute-api.{region}.amazonaws.com/prod
Key Features:
- Real-time AI chat streaming
- Progress assessment with streaming feedback
- Summary generation with streaming output
- Audio transcription status updates
- Real-time notifications
Cause: Missing or invalid JWT token
Solution:
- Verify token is included in
Authorizationheader - Check token hasn't expired (1 hour lifetime)
- Refresh token using AWS Amplify
import { fetchAuthSession } from "aws-amplify/auth";
const session = await fetchAuthSession({ forceRefresh: true });
const token = session.tokens?.idToken?.toString();Cause: User doesn't have the required role in the database
Solution:
- Verify user has the specific role required for the endpoint in the database
- Admin endpoints require
adminrole - Instructor endpoints require
instructorrole - Student endpoints require
studentrole (except shared endpoints) - Note: Having
adminrole does NOT automatically grant access to instructor or student endpoints - Use
/admin/user_roleendpoint to add required roles to users
Cause: Resource doesn't exist or user doesn't have access
Solution:
- Verify resource ID is correct
- Check user owns the resource (for student endpoints)
- Verify instructor-student relationship (for instructor endpoints)
Cause: Rate limit exceeded
Solution:
- Implement exponential backoff
- Check daily message limit hasn't been reached
- Wait before retrying
async function fetchWithRetry(url, options, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
const response = await fetch(url, options);
if (response.status === 429) {
const delay = Math.pow(2, i) * 1000; // Exponential backoff
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
return response;
}
throw new Error("Max retries exceeded");
}Cause: Server-side error
Solution:
- Check CloudWatch logs for detailed error information
- Verify request body matches expected schema
- Contact system administrator if issue persists
- Enable verbose logging:
// Log all requests and responses
const originalFetch = window.fetch;
window.fetch = async (...args) => {
console.log("Request:", args);
const response = await originalFetch(...args);
console.log("Response:", response.status, await response.clone().text());
return response;
};- Validate request bodies:
// Ensure all required fields are present
const validateCaseCreation = (data) => {
const required = ["case_title", "case_type", "jurisdiction", "case_description", "province", "statute"];
const missing = required.filter(field => !data[field]);
if (missing.length > 0) {
throw new Error(`Missing required fields: ${missing.join(", ")}`);
}
};- Check token expiration:
import { jwtDecode } from "jwt-decode";
const isTokenExpired = (token) => {
const decoded = jwtDecode(token);
return decoded.exp * 1000 < Date.now();
};- Product Overview - Core features and user roles
- Technology Stack - AWS services and frameworks
- Authentication & Authorization - Cognito integration and RBAC
- WebSocket Implementation - Real-time streaming and notifications
- Project Structure - File organization and naming conventions
- Initial API release
- Admin, Instructor, and Student endpoints
- Case management
- AI chat integration
- Audio transcription
- Summary generation
- Feedback system
- Prompt management
- Disclaimer management
- Role-based access control
For API support or to report issues:
- Check CloudWatch logs for detailed error information
- Review this documentation for endpoint specifications
- Verify authentication and authorization requirements
- Contact your system administrator
- Use pagination for list endpoints to reduce response size
- Cache responses when data doesn't change frequently (e.g., role labels, disclaimers)
- Use WebSocket for real-time features instead of polling REST endpoints
- Batch operations when possible to reduce number of requests
- Always check response status before parsing JSON
- Implement retry logic with exponential backoff for transient errors
- Log errors with context for debugging
- Provide user-friendly error messages in the UI
async function apiRequest(url, options) {
try {
const response = await fetch(url, options);
if (!response.ok) {
const error = await response.json();
throw new Error(error.error || `HTTP ${response.status}`);
}
return await response.json();
} catch (error) {
console.error("API request failed:", error);
throw error;
}
}- Never log tokens or sensitive data
- Validate input on client-side before sending to API
- Use HTTPS for all requests
- Implement CSRF protection for state-changing operations
- Sanitize user input to prevent XSS attacks
Last Updated: March 2024
API Version: 1.0.0
Base URL: https://{api-id}.execute-api.{region}.amazonaws.com/prod