16 KiB
API Design and Integration
API Integration Strategy
API Integration Strategy: Extend existing DocuSeal API v1 with new cohort-specific endpoints under /api/v1/cohorts/*. All endpoints follow existing RESTful patterns, authentication mechanisms, and response formats.
Authentication: Reuse existing Devise + JWT authentication. No changes to auth flow required. New endpoints will require the same bearer token authentication as existing endpoints.
Versioning: No new API version required. New endpoints extend v1 following existing patterns. All new endpoints return consistent JSON response formats matching existing endpoints.
New API Endpoints
Cohort Management Endpoints
Create Cohort
- Method:
POST - Endpoint:
/api/v1/cohorts - Purpose: Create new cohort with templates and configuration
- Integration: Uses existing Template APIs for template management
Request:
{
"cohort": {
"name": "Q1 2025 Learnership",
"program_type": "learnership",
"sponsor_email": "sponsor@company.com",
"student_count": 50,
"main_template_id": 123,
"supporting_template_ids": [124, 125],
"start_date": "2025-02-01",
"end_date": "2025-07-31"
}
}
Response:
{
"id": 1,
"name": "Q1 2025 Learnership",
"state": "draft",
"created_at": "2025-01-02T10:00:00Z",
"links": {
"self": "/api/v1/cohorts/1",
"enrollments": "/api/v1/cohorts/1/enrollments"
}
}
List Cohorts
- Method:
GET - Endpoint:
/api/v1/cohorts - Purpose: Get paginated list of cohorts for current institution
- Integration: Filters by current user's institution
Response:
{
"data": [
{
"id": 1,
"name": "Q1 2025 Learnership",
"program_type": "learnership",
"state": "active",
"completion_percentage": 65,
"student_count": 50,
"completed_students": 32
}
],
"meta": {
"page": 1,
"per_page": 20,
"total": 1
}
}
Get Cohort Details
- Method:
GET - Endpoint:
/api/v1/cohorts/:id - Purpose: Get detailed cohort information with enrollment status
- Integration: Aggregates data from existing Submission APIs
Response:
{
"id": 1,
"name": "Q1 2025 Learnership",
"program_type": "learnership",
"state": "active",
"sponsor_email": "sponsor@company.com",
"admin_signed_at": "2025-01-02T10:30:00Z",
"templates": {
"main": { "id": 123, "name": "Learnership Agreement" },
"supporting": [{ "id": 124, "name": "Code of Conduct" }]
},
"enrollments": {
"waiting": 5,
"in_progress": 13,
"complete": 32
}
}
Invite Students
- Method:
POST - Endpoint:
/api/v1/cohorts/:id/invitations - Purpose: Generate invite links or send email invitations
- Integration: Uses existing email system and user creation
Request:
{
"students": [
{ "email": "student1@example.com", "first_name": "John", "last_name": "Doe" },
{ "email": "student2@example.com", "first_name": "Jane", "last_name": "Smith" }
],
"send_email": true
}
Response:
{
"invitations_sent": 2,
"invite_links": [
{ "email": "student1@example.com", "link": "https://flo.doc/invite/abc123" },
{ "email": "student2@example.com", "link": "https://flo.doc/invite/def456" }
]
}
Export Cohort Data (FR23)
- Method:
GET - Endpoint:
/api/v1/cohorts/:id/export - Purpose: Export cohort data to Excel format
- Integration: Uses existing rubyXL gem for Excel generation
Query Parameters:
format=xlsxinclude=student_demographics,program_details,sponsor_info
Response: Excel file download with columns: cohort_name, student_name, student_surname, student_age, student_race, student_city, program_type, sponsor_company_name, disability_status, gender
Web Portal Routes
Admin Portal Routes
| Route | Method | Purpose | Authentication | Component |
|---|---|---|---|---|
/cohorts/admin |
GET | Cohort dashboard | Devise + Role | AdminPortal.vue |
/cohorts/admin/new |
GET | Create cohort wizard | Devise + Role | CohortWizard.vue |
/cohorts/admin/:id |
GET | Cohort details | Devise + Role | CohortDashboard.vue |
/cohorts/admin/:id/verify |
GET | Document verification | Devise + Role | VerificationInterface.vue |
/cohorts/admin/:id/sponsors |
GET | Sponsor management | Devise + Role | SponsorCoordinator.vue |
/cohorts/admin/:id/analytics |
GET | Analytics view | Devise + Role | AnalyticsView.vue |
/cohorts/admin/:id/export |
GET | Excel export (FR23) | Devise + Role | ExcelExport.vue |
/cohorts/admin/:id/invite |
POST | Student invitations | Devise + Role | API call |
Student Portal Routes
| Route | Method | Purpose | Authentication | Component |
|---|---|---|---|---|
/cohorts/student/:token |
GET | Portal entry (token) | Token-based | StudentPortal.vue |
/cohorts/student/:token/welcome |
GET | Welcome screen | Token-based | CohortWelcome.vue |
/cohorts/student/:token/upload |
GET | Document upload | Token-based | DocumentUpload.vue |
/cohorts/student/:token/agreement |
GET | Main agreement | Token-based | AgreementForm.vue |
/cohorts/student/:token/supporting |
GET | Supporting docs | Token-based | AgreementForm.vue |
/cohorts/student/:token/status |
GET | Progress dashboard | Token-based | StatusDashboard.vue |
/cohorts/student/:token/resubmit |
GET | Re-submission flow | Token-based | ResubmissionFlow.vue |
Sponsor Portal Routes
| Route | Method | Purpose | Authentication | Component |
|---|---|---|---|---|
/cohorts/sponsor/:token |
GET | Sponsor dashboard | Token-based | SponsorPortal.vue |
/cohorts/sponsor/:token/overview |
GET | Cohort overview | Token-based | SponsorDashboard.vue |
/cohorts/sponsor/:token/student/:student_id |
GET | Student review | Token-based | StudentReview.vue |
/cohorts/sponsor/:token/bulk-sign |
POST | Bulk signing | Token-based | BulkSigning.vue |
/cohorts/sponsor/:token/finalize |
POST | Cohort finalization | Token-based | CohortFinalization.vue |
Enrollment Management Endpoints
List Enrollments
- Method:
GET - Endpoint:
/api/v1/cohorts/:id/enrollments - Purpose: Get all student enrollments with status
- Integration: Aggregates from CohortEnrollment + existing User/Submission data
Response:
{
"data": [
{
"id": 1,
"student": { "name": "John Doe", "email": "john@example.com" },
"state": "complete",
"verification_state": "verified",
"documents": { "uploaded": 5, "signed": 3 },
"created_at": "2025-01-01T10:00:00Z"
}
]
}
Verify Document
- Method:
POST - Endpoint:
/api/v1/enrollments/:id/verify - Purpose: Admin document verification (approve/reject)
- Integration: Creates DocumentVerification records
Request:
{
"action": "reject",
"document_type": "matric_certificate",
"reason": "Certificate is not certified by SAQA"
}
Sponsor Endpoints
Get Sponsor Cohort Overview
- Method:
GET - Endpoint:
/api/v1/sponsors/cohorts/:token - Purpose: Sponsor access to cohort overview (token-based auth)
- Integration: Validates token, checks all students complete
Response:
{
"cohort": { "name": "Q1 2025 Learnership", "student_count": 50 },
"students": [
{ "id": 1, "name": "John Doe", "state": "complete", "signed": true }
],
"can_sign": true,
"bulk_sign_available": true
}
Bulk Sign
Request:
{
"signature": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...",
"initials": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...",
"sign_all": true,
"timestamp": "2025-01-02T15:30:00Z"
}
Success Response (200):
{
"signed_count": 50,
"failed_count": 0,
"signatures_applied": [
{
"enrollment_id": 1,
"submission_id": 100,
"status": "signed",
"signed_at": "2025-01-02T15:30:00Z"
}
],
"cohort_finalized": true,
"next_step": "Admin can now finalize cohort and download documents"
}
Error Responses:
// 422 Validation Error
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Signature data is invalid or corrupted",
"timestamp": "2025-01-02T15:30:00Z"
}
}
// 403 Forbidden
{
"error": {
"code": "STATE_ERROR",
"message": "Cannot sign - some students are not ready",
"details": {
"ready": 32,
"total": 50,
"pending": 18
}
}
}
Complete API Response Schemas
Cohort Endpoints
POST /api/v1/cohorts - Request:
{
"cohort": {
"name": "Q1 2025 Learnership",
"program_type": "learnership",
"sponsor_email": "sponsor@company.com",
"student_count": 50,
"main_template_id": 123,
"supporting_template_ids": [124, 125],
"start_date": "2025-02-01",
"end_date": "2025-07-31"
}
}
POST /api/v1/cohorts - Success Response (201):
{
"id": 1,
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"name": "Q1 2025 Learnership",
"program_type": "learnership",
"state": "draft",
"sponsor_email": "sponsor@company.com",
"student_count": 50,
"main_template_id": 123,
"supporting_template_ids": [124, 125],
"start_date": "2025-02-01",
"end_date": "2025-07-31",
"admin_signed_at": null,
"created_at": "2025-01-02T10:00:00Z",
"updated_at": "2025-01-02T10:00:00Z",
"links": {
"self": "/api/v1/cohorts/1",
"enrollments": "/api/v1/cohorts/1/enrollments",
"invitations": "/api/v1/cohorts/1/invitations"
}
}
POST /api/v1/cohorts - Error Responses:
// 422 Validation Error
{
"errors": {
"name": ["can't be blank"],
"sponsor_email": ["is invalid"],
"main_template_id": ["must exist"]
}
}
// 403 Forbidden (wrong institution)
{
"error": {
"code": "AUTHORIZATION_ERROR",
"message": "Access denied"
}
}
GET /api/v1/cohorts/:id - Success Response (200):
{
"id": 1,
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"name": "Q1 2025 Learnership",
"program_type": "learnership",
"state": "active",
"sponsor_email": "sponsor@company.com",
"student_count": 50,
"admin_signed_at": "2025-01-02T10:30:00Z",
"created_at": "2025-01-02T10:00:00Z",
"updated_at": "2025-01-02T10:30:00Z",
"templates": {
"main": {
"id": 123,
"name": "Learnership Agreement",
"uuid": "abc123..."
},
"supporting": [
{
"id": 124,
"name": "Code of Conduct",
"uuid": "def456..."
}
]
},
"enrollment_summary": {
"total": 50,
"waiting": 5,
"in_progress": 13,
"complete": 32,
"rejected": 0
},
"completion_percentage": 64,
"links": {
"self": "/api/v1/cohorts/1",
"enrollments": "/api/v1/cohorts/1/enrollments",
"export": "/api/v1/cohorts/1/export"
}
}
GET /api/v1/cohorts/:id/enrollments - Success Response (200):
{
"data": [
{
"id": 1,
"uuid": "550e8400-e29b-41d4-a716-446655440001",
"student": {
"id": 100,
"name": "John Doe",
"email": "john@example.com",
"phone": "+27123456789"
},
"state": "complete",
"verification_state": "verified",
"rejection_reason": null,
"student_data": {
"age": 23,
"race": "Black",
"city": "Johannesburg",
"gender": "Male",
"disability": "None"
},
"documents": {
"uploaded": 5,
"signed": 3,
"rejected": 0
},
"created_at": "2025-01-01T10:00:00Z",
"updated_at": "2025-01-02T14:30:00Z",
"links": {
"self": "/api/v1/enrollments/1",
"verify": "/api/v1/enrollments/1/verify"
}
}
],
"meta": {
"page": 1,
"per_page": 20,
"total": 50,
"filters": {
"state": ["complete"],
"verification_state": ["verified"]
}
}
}
POST /api/v1/cohorts/:id/invitations - Request:
{
"students": [
{
"email": "student1@example.com",
"first_name": "John",
"last_name": "Doe",
"phone": "+27123456789",
"age": 23,
"race": "Black",
"city": "Johannesburg",
"gender": "Male",
"disability": "None"
}
],
"send_email": true,
"message": "Welcome to our Q1 2025 Learnership program!"
}
POST /api/v1/cohorts/:id/invitations - Success Response (201):
{
"invitations_sent": 1,
"invite_links": [
{
"email": "student1@example.com",
"token": "abc123def456",
"link": "https://flo.doc/cohorts/student/abc123def456",
"expires_at": "2025-02-01T10:00:00Z"
}
],
"errors": []
}
GET /api/v1/cohorts/:id/export - Query Parameters:
format=xlsx(required)include=student_demographics,program_details,sponsor_info(optional)
GET /api/v1/cohorts/:id/export - Response:
- Returns Excel file (.xlsx) as binary download
- Headers:
Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet Content-Disposition: attachment; filename="cohort_1_export_20250102.xlsx"
Excel Columns:
cohort_name | student_name | student_surname | student_age | student_race | student_city | program_type | sponsor_company_name | disability_status | gender
Enrollment Endpoints
POST /api/v1/enrollments/:id/verify - Request:
{
"action": "reject",
"document_type": "matric_certificate",
"reason": "Certificate is not certified by SAQA. Please provide SAQA verification letter.",
"metadata": {
"reviewed_by": "admin@institution.com",
"review_notes": "Checked against SAQA database"
}
}
POST /api/v1/enrollments/:id/verify - Success Response (200):
{
"id": 1,
"enrollment_id": 1,
"action": "rejected",
"document_type": "matric_certificate",
"reason": "Certificate is not certified by SAQA. Please provide SAQA verification letter.",
"admin_id": 50,
"created_at": "2025-01-02T15:00:00Z",
"metadata": {
"reviewed_by": "admin@institution.com",
"review_notes": "Checked against SAQA database"
}
}
POST /api/v1/enrollments/:id/verify - Error Responses:
// 422 Invalid State Transition
{
"error": {
"code": "STATE_ERROR",
"message": "Cannot reject enrollment that is already complete"
}
}
// 404 Not Found
{
"error": {
"code": "NOT_FOUND",
"message": "Enrollment not found"
}
}
Sponsor Endpoints
GET /api/v1/sponsors/cohorts/:token - Success Response (200):
{
"cohort": {
"id": 1,
"name": "Q1 2025 Learnership",
"program_type": "learnership",
"student_count": 50,
"sponsor_email": "sponsor@company.com"
},
"students": [
{
"id": 1,
"name": "John Doe",
"email": "john@example.com",
"state": "complete",
"verification_state": "verified",
"signed": true,
"signed_at": "2025-01-02T10:00:00Z",
"documents": {
"main_agreement": {
"id": 100,
"status": "signed",
"preview_url": "/api/v1/submissions/100/preview"
},
"supporting_docs": [
{
"id": 101,
"name": "Code of Conduct",
"status": "signed"
}
]
}
}
],
"summary": {
"total": 50,
"completed": 32,
"pending": 18,
"signed": 32
},
"can_sign": true,
"bulk_sign_available": true,
"token_expires_at": "2025-01-16T23:59:59Z"
}
GET /api/v1/sponsors/cohorts/:token - Error Responses:
// 403 Forbidden (students not complete)
{
"error": {
"code": "STATE_ERROR",
"message": "All students must complete their submissions before sponsor access",
"details": {
"completed": 32,
"total": 50,
"remaining": 18
}
}
}
// 401 Unauthorized (invalid/expired token)
{
"error": {
"code": "AUTHENTICATION_ERROR",
"message": "Invalid or expired sponsor token"
}
}
Bulk Sign
- Method:
POST - Endpoint:
/api/v1/sponsors/cohorts/:token/bulk-sign - Purpose: Sign all student agreements at once
- Integration: Uses existing submission signing APIs
Request:
{
"signature": "data:image/png;base64,...",
"initials": "data:image/png;base64,..."
}