You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
docuseal/docs/architecture/api-design-and-integration.md

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=xlsx
  • include=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,..."
}