FeedForward's API is built with FastHTML, providing server-side rendered HTML with HTMX for dynamic updates. While not a traditional REST API, the endpoints follow RESTful conventions where appropriate. All endpoints return HTML responses unless otherwise noted.
FeedForward uses session-based authentication with secure cookies:
# Session cookie configuration
SESSION_COOKIE_NAME = "feedforward_session"
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SECURE = True # HTTPS only in production
SESSION_COOKIE_SAMESITE = "Lax"
1. User submits login credentials
2. Server validates and creates session
3. Session cookie set with user email
4. Subsequent requests include cookie
5. Decorators check session['auth'] for access
Three authorization decorators protect endpoints:
@admin_required # Admins only
@instructor_required # Instructors (verified + approved)
@student_required # Students only
Create new instructor account.
Request Body:
name: string (required)
email: string (required, valid email)
password: string (required, min 8 chars)
confirm_password: string (required, must match)
tos_accepted: boolean (required, must be true)
privacy_accepted: boolean (required, must be true)
Response:
- Success: Redirect to /register/confirmation
- Error: Form with validation messages
Notes: - Students cannot self-register - Domain whitelist may auto-approve instructors - Email verification required
Authenticate user and create session.
Request Body:
email: string (required)
password: string (required)
Response: - Success: Redirect to role-specific dashboard - Error: Form with "Invalid credentials"
Verify email address with token.
Query Parameters:
token: string (required, verification token)
Response: - Success: Redirect to login with success message - Error: Error page with invalid token message
Request password reset email.
Request Body:
email: string (required)
Response: - Always shows success message (security) - Email sent if account exists
Reset password with token.
Request Body:
token: string (required, from email)
email: string (required)
password: string (required, min 8 chars)
confirm_password: string (required)
Response: - Success: Redirect to login - Error: Form with validation messages
Display current Terms of Service.
Response: HTML page with ToS content
Display current Privacy Policy.
Response: HTML page with privacy policy
All admin endpoints require @admin_required decorator.
Admin dashboard with system overview.
Response Data: - Total users by role - Pending instructor approvals - System health metrics - Recent activity
View pending instructor approvals.
Response: List of unverified/unapproved instructors
Approve instructor account.
Path Parameters:
email: string (instructor email)
Response: Redirect with success message
Reject instructor account.
Path Parameters:
email: string (instructor email)
Response: Redirect with success message
Manage all instructor accounts.
Response: Table of all instructors with actions
Soft delete instructor account.
Path Parameters:
email: string (instructor email)
Response: Redirect with success message
Manage email domain whitelist.
Response: List of whitelisted domains
Add domain to whitelist.
Request Body:
domain: string (required, e.g., "university.edu")
auto_approve: boolean (auto-approve instructors)
Response: Redirect with success/error message
Toggle auto-approve for domain.
Path Parameters:
id: integer (domain ID)
Response: Redirect with success message
View all system AI models.
Response: List of configured AI models
Create new AI model configuration.
Request Body:
name: string (required)
provider: string (required, e.g., "openai")
model_id: string (required, e.g., "gpt-4")
api_key: string (required for most providers)
base_url: string (optional, custom endpoint)
capabilities: array (optional, ["text", "vision"])
max_context: integer (optional, token limit)
Response: Redirect to models list or form with errors
Test AI model connection.
Request Body:
provider: string (required)
api_key: string (required)
base_url: string (optional)
Response: JSON with test results
{
"success": true,
"message": "Connection successful",
"models": ["gpt-4", "gpt-3.5-turbo"]
}
Delete AI model configuration.
Path Parameters:
id: integer (model ID)
Response: 200 OK or error status
All instructor endpoints require @instructor_required decorator.
Instructor dashboard overview.
Response Data: - Active courses - Recent submissions - Pending feedback reviews - Student activity
View all instructor's courses.
Query Parameters:
status: string (optional, filter by status)
Response: List of courses with management actions
Create new course.
Request Body:
code: string (required, e.g., "CS101")
title: string (required)
description: string (optional)
term: string (optional, e.g., "Fall 2024")
Response: Redirect to course page or form with errors
Update course details.
Path Parameters:
course_id: integer
Request Body:
title: string
description: string
status: string (active, closed, archived)
Response: Redirect with success message
View course assignments.
Path Parameters:
course_id: integer
Response: List of assignments with actions
Create new assignment.
Path Parameters:
course_id: integer
Request Body:
title: string (required)
description: string (required)
due_date: datetime (required)
max_drafts: integer (default: 3)
Response: Redirect to assignment or form with errors
Toggle assignment status (active/inactive).
Path Parameters:
assignment_id: integer
Response: Redirect with status update
Create assignment rubric.
Path Parameters:
assignment_id: integer
Response: Redirect to rubric management
Add rubric category.
Path Parameters:
assignment_id: integer
Request Body:
name: string (required)
description: string (optional)
weight: float (required, 0-1)
Response: HTML partial for HTMX update
Get rubric template structure.
Path Parameters:
assignment_id: integer
template_type: string (essay, report, presentation, creative)
Response: JSON with template structure
{
"categories": [
{
"name": "Thesis Statement",
"description": "Clear and arguable thesis",
"weight": 0.2
}
]
}
View course students.
Path Parameters:
course_id: integer
Response: Student roster with management actions
Send student invitations.
Request Body:
course_id: integer (required)
emails: string (required, comma-separated)
Response: Success/error messages for each email
Remove student from course.
Request Body:
student_email: string (required)
course_id: integer (required)
Response: Redirect with success message
View all submissions for assignment.
Path Parameters:
assignment_id: integer
Query Parameters:
status: string (optional, filter by feedback status)
Response: List of submissions grouped by status
Review AI-generated feedback.
Path Parameters:
draft_id: integer
Response: Feedback review interface
Approve or edit feedback.
Path Parameters:
draft_id: integer
Request Body:
action: string (required, "approve" or "save_edits")
category_{id}_score: float (for each category)
category_{id}_feedback: string (for each category)
instructor_notes: string (optional)
Response: Redirect with success message
All student endpoints require @student_required decorator.
Complete student registration from invitation.
Request Body:
token: string (required, from invitation)
email: string (required)
name: string (required)
password: string (required, min 8 chars)
confirm_password: string (required)
tos_accepted: boolean (required)
privacy_accepted: boolean (required)
Response: Redirect to dashboard or form with errors
Student dashboard overview.
Response Data: - Enrolled courses - Recent feedback - Upcoming assignments - Submission statistics
View course details.
Path Parameters:
course_id: integer
Response: Course information and assignments
View course assignments.
Path Parameters:
course_id: integer
Response: List of available assignments
View assignment details.
Path Parameters:
assignment_id: integer
Response: Assignment info, rubric, submission status
Submit draft for feedback.
Path Parameters:
assignment_id: integer
Request Body (multipart/form-data):
submission_method: string ("text" or "file")
content: string (if method="text")
file: file (if method="file", PDF/DOCX/TXT)
version: integer (draft version)
Response: Redirect to feedback status page
View feedback for submitted draft.
Path Parameters:
draft_id: integer
Response: - If processing: Auto-refresh status page - If ready: Detailed feedback report
Check feedback generation status (AJAX).
Path Parameters:
draft_id: integer
Response: JSON status
{
"status": "processing|ready|error",
"message": "Feedback is being generated..."
}
View all submissions.
Query Parameters:
show_hidden: boolean (include hidden submissions)
Response: List of all drafts with actions
Hide a submission from view.
Path Parameters:
draft_id: integer
Response: Redirect with success message
Most endpoints return full HTML pages or HTMX partials:
<!-- Full page response -->
<html>
<head>...</head>
<body>
<div id="content">...</div>
</body>
</html>
<!-- HTMX partial response -->
<div id="rubric-categories" hx-swap-oob="true">
<div class="category">...</div>
</div>
Select endpoints return JSON for AJAX/API usage:
{
"success": true|false,
"message": "Operation result",
"data": { ... }
}
Errors are typically shown in-page:
<div class="error-message">
<p>Error: Invalid input provided</p>
</div>
HTTP status codes: - 200: Success - 302: Redirect - 400: Bad Request - 401: Unauthorized - 403: Forbidden - 404: Not Found - 500: Server Error
Many endpoints support HTMX for dynamic updates:
<!-- Example: Add rubric category -->
<button hx-post="/instructor/assignments/1/rubric/categories/add"
hx-target="#categories"
hx-swap="beforeend">
Add Category
</button>
<!-- Example: Check feedback status -->
<div hx-get="/api/feedback-status/123"
hx-trigger="every 5s"
hx-swap="innerHTML">
Checking status...
</div>
API rate limits (configurable):
Global Limits:
Requests per minute: 60
Burst allowance: 10
Per-Endpoint Limits:
AI model testing: 10 per hour
Draft submission: 5 per hour
Feedback generation: 20 per day
This API is designed for server-side rendered applications. For building separate frontends, consider adding dedicated JSON API endpoints.