openapi: 3.0.3 info: title: 'Student Matching Platform APi API Documentation' description: '' version: 1.0.0 servers: - url: 'https://vps117355.serveur-vps.net' tags: - name: 'Academic Information Management' description: "\nEndpoints for managing academic informations of students" - name: 'Admin Notification Management' description: "\nEndpoints to handle admin-scoped notifications (listing, viewing and marking as read).\n\nThese endpoints return enriched information via the `AdminNotificationResource` and support\nfiltering by read/unread and pagination. They are scoped to the authenticated admin (results limited\nto notifications intended for the authenticated admin).\n\nExample: GET /api/admin/admin_notifications?status=unread&paginated=true" - name: 'Authentication Endpoints' description: "\nEndpoints to handle authentication." - name: 'Bundles Management' description: '' - name: 'Contact Management' description: "\nEndpoints for managing contacts" - name: 'Countries Management' description: "\nManage countries and their associations with study destinations (regions).\nCountries are categorized by region tier: emerging (Africa, Asia) and global (USA, UK, Europe, UAE)." - name: 'Credit Management' description: '' - name: 'Credit Purchases & Bundle Payments' description: '' - name: Currency description: "\nManage currencies" - name: 'Current Status Management' description: "\nManage the current status in the system" - name: 'Document Locker' description: "\nEndpoints to manage the document locker" - name: Endpoints description: '' - name: 'HighSchool Management' description: "\nEndpoints for managing highschools" - name: 'Majors Management' description: '' - name: 'Matching Suggestions' description: "\nAPIs for managing matching suggestions" - name: Miscellaneous description: '' - name: 'Payment Management' description: '' - name: 'Personal Information' description: "\nManage personal informations of a student" - name: 'Preferences and goals' description: "\nManage student preferences." - name: 'Special Needs Management' description: "\nEndpoints to manage special needs" - name: 'Staff Management' description: "\nManage staff members and their student assignments" - name: 'Student Conversations' description: "\nMessage box between students and uni staff. Students can start conversations with university staff.\nAssigned managers/advisers for the student and admins can participate and reply." - name: 'Student Language' description: "\nManage the languages spoken by the student." - name: 'Student Management' description: "\nEndpoint to manage the students" - name: 'Study destination' description: "\nManage study destination" - name: Universities description: "\nManage universities information, including descriptions, tuition, and gallery images." - name: 'University Applications Management' description: '' - name: 'User Management' description: "\nEndpoints to manage users (admin only for most operations)." - name: 'User Notification Management' description: "\nEndpoints to handle the authenticated user's notifications.\n\nFlexible endpoint that supports filtering by status, limiting results, and pagination." - name: 'Users roles' description: "\nManage users and student roles." components: securitySchemes: default: type: http scheme: bearer description: 'You can retrieve a user token by calling the login endpoint or register endpoint for new users.' security: - default: [] paths: /api/v1/ai: get: summary: "Get the current authenticated user's academic information." operationId: getTheCurrentAuthenticatedUsersAcademicInformation description: '' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: id: 1 current_status: id: 2 name: Undergraduate high_schools_attended: [] properties: id: type: integer example: 1 current_status: type: object properties: id: type: integer example: 2 name: type: string example: Undergraduate high_schools_attended: type: array example: [] 404: description: '' content: application/json: schema: type: object example: message: 'Academic information not found' academic_information: null properties: message: type: string example: 'Academic information not found' academic_information: type: string example: null tags: - 'Academic Information Management' post: summary: 'Create a new academic information entry.' operationId: createANewAcademicInformationEntry description: '' parameters: [] responses: { } tags: - 'Academic Information Management' requestBody: required: true content: application/json: schema: type: object properties: current_status: type: string description: 'the id of the current status of the student.' example: consequatur nullable: false user_id: type: string description: 'the id of the student this value is used to check and avoid creating redudant entries.' example: consequatur nullable: false required: - current_status - user_id '/api/v1/ai/{id}': put: summary: 'Update an academic information entry.' operationId: updateAnAcademicInformationEntry description: '' parameters: [] responses: { } tags: - 'Academic Information Management' requestBody: required: true content: application/json: schema: type: object properties: current_status: type: string description: 'the id of the current status of the student.' example: consequatur nullable: false user_id: type: string description: 'the id of the student this value is used to check and avoid creating redudant entries.' example: null nullable: false required: - current_status parameters: - in: path name: id description: 'The ID of the ai.' example: 1 required: true schema: type: integer /api/v1/admin/admin_notifications: get: summary: 'Display a listing of the resource.' operationId: displayAListingOfTheResource description: '' parameters: [] responses: 500: description: '' content: application/json: schema: type: object example: success: false errors: Unauthenticated. timestamp: '2026-04-18T17:44:14.345036Z' properties: success: type: boolean example: false errors: type: string example: Unauthenticated. timestamp: type: string example: '2026-04-18T17:44:14.345036Z' tags: - 'Admin Notification Management' '/api/v1/admin/admin_notifications/{id}': get: summary: 'Display the specified resource.' operationId: displayTheSpecifiedResource description: '' parameters: [] responses: 500: description: '' content: application/json: schema: type: object example: success: false errors: Unauthenticated. timestamp: '2026-04-18T17:44:14.348998Z' properties: success: type: boolean example: false errors: type: string example: Unauthenticated. timestamp: type: string example: '2026-04-18T17:44:14.348998Z' tags: - 'Admin Notification Management' parameters: - in: path name: id description: 'The ID of the admin notification.' example: 1 required: true schema: type: integer /api/v1/admin/admin_notifications/read-all: post: summary: '' operationId: postApiV1AdminAdmin_notificationsReadAll description: '' parameters: [] responses: { } tags: - 'Admin Notification Management' /api/v1/forgot_password: post: summary: 'Forgot Password (API Flow)' operationId: forgotPasswordAPIFlow description: 'Generates a 6-digit code and sends it via email.' parameters: [] responses: { } tags: - 'Authentication Endpoints' requestBody: required: true content: application/json: schema: type: object properties: email: type: string description: "The user's email." example: user@example.com nullable: false required: - email security: [] /api/v1/validate_reset_code: post: summary: 'Validate Reset Code' operationId: validateResetCode description: "Verifies if the 6-digit code is valid for the given email.\nUse this to allow the frontend to proceed to the \"New Password\" screen.\n* @bodyParam email string required. Example: user@example.com" parameters: [] responses: { } tags: - 'Authentication Endpoints' requestBody: required: true content: application/json: schema: type: object properties: email: type: string description: 'Must be a valid email address. The email of an existing record in the users table.' example: qkunze@example.com nullable: false code: type: string description: required. example: '123456' nullable: false required: - email security: [] /api/v1/reset_password: post: summary: 'Reset Password' operationId: resetPassword description: "The final step: Update the password using the validated code.\n* @bodyParam email string required." parameters: [] responses: { } tags: - 'Authentication Endpoints' requestBody: required: true content: application/json: schema: type: object properties: email: type: string description: 'Must be a valid email address. The email of an existing record in the users table.' example: qkunze@example.com nullable: false code: type: string description: required. example: consequatur nullable: false password: type: string description: required. example: 'O[2UZ5ij-e/dl4m{o,' nullable: false password_confirmation: type: string description: required. example: consequatur nullable: false required: - email security: [] /api/v1/register: post: summary: 'Register a new user' operationId: registerANewUser description: "This endpoint handles user registration. It accepts a name, email, and password,\ncreates a new user, and returns an authentication token." parameters: [] responses: { } tags: - 'Authentication Endpoints' requestBody: required: true content: application/json: schema: type: object properties: name: type: string description: 'The name of the user. Must not be greater than 255 characters.' example: 'John Doe' nullable: false email: type: string description: 'The email of the user. Must be a valid email address. Must not be greater than 255 characters.' example: john@ollav.com nullable: false password: type: string description: 'The password for the user. Must be at least 8 characters.' example: 'O[2UZ5ij-e/dl4m{o,' nullable: false required: - name - email - password security: [] /api/v1/login: post: summary: 'Login a new user' operationId: loginANewUser description: "This endpoint handles user signin process. It accepts an email and password,\nCheck the user, and returns an authentication token." parameters: [] responses: { } tags: - 'Authentication Endpoints' requestBody: required: true content: application/json: schema: type: object properties: email: type: string description: 'The email of the user. Must be a valid email address.' example: john@ollav.com nullable: false password: type: string description: 'The password for the user.' example: consequatur nullable: false required: - email - password security: [] /api/v1/logout: post: summary: 'Logout the authenticated user' operationId: logoutTheAuthenticatedUser description: 'This endpoint handles user signing out.' parameters: [] responses: { } tags: - 'Authentication Endpoints' /api/v1/admin/staff: post: summary: 'Create a new staff member' operationId: createANewStaffMember description: "This endpoint handles staff account creation. It accepts a name, email, password, and role_id,\ncreates a new staff user, and sends a welcome email notification." parameters: [] responses: { } tags: - 'Authentication Endpoints' requestBody: required: true content: application/json: schema: type: object properties: name: type: string description: 'The name of the staff member. Must not be greater than 255 characters.' example: 'Jane Smith' nullable: false email: type: string description: 'The email of the staff member. Must be a valid email address. Must not be greater than 255 characters.' example: jane@ollav.com nullable: false password: type: string description: 'The password for the staff member account. Must be at least 8 characters.' example: 'O[2UZ5ij-e/dl4m{o,' nullable: false role_id: type: integer description: 'The role ID for the staff member. The id of an existing record in the roles table.' example: 2 nullable: false required: - name - email - password - role_id security: [] get: summary: 'Show the list of all staff members in the system' operationId: showTheListOfAllStaffMembersInTheSystem description: "Get all staff members (non-student users) available in the system.\nResults are paginated with 10 staff members per page." parameters: [] responses: 200: description: '' content: text/plain: schema: type: string example: '{"data": [...], "links": {...}, "meta": {"total": 5, "per_page": 10, "current_page": 1}}' tags: - 'Staff Management' /api/v1/bundles: get: summary: 'List available bundles' operationId: listAvailableBundles description: '' parameters: [] responses: 200: description: 'List of active bundles with emerging and global prices' content: application/json: schema: type: object nullable: true tags: - 'Bundles Management' '/api/v1/bundles/{bundleId}': get: summary: 'Get bundle details' operationId: getBundleDetails description: '' parameters: [] responses: 200: description: 'Detailed bundle information' content: application/json: schema: type: object nullable: true tags: - 'Bundles Management' parameters: - in: path name: bundleId description: '' example: consequatur required: true schema: type: string /api/v1/admin/bundles: post: summary: 'Create new bundle (admin only)' operationId: createNewBundleadminOnly description: '' parameters: [] responses: { } tags: - 'Bundles Management' requestBody: required: true content: application/json: schema: type: object properties: name: type: string description: 'Bundle name' example: 'Premium Pack' nullable: false application_number: type: integer description: 'Number of applications included' example: 10 nullable: false emerging_price: type: number description: 'Price for emerging markets' example: 50.0 nullable: false global_price: type: number description: 'Price for global markets' example: 100.0 nullable: false currency_id: type: integer description: 'Currency ID' example: 1 nullable: false whats_included: type: array description: 'Array of features included' example: - '5 job applications' - 'Priority support' items: type: string ideal_for: type: string description: 'Who this bundle is ideal for' example: 'Active job seekers' nullable: false is_active: type: boolean description: 'Active status' example: true nullable: false required: - name - application_number - emerging_price - global_price - currency_id '/api/v1/admin/bundles/{bundleId}': get: summary: 'Get bundle details' operationId: getBundleDetails description: '' parameters: [] responses: 200: description: 'Detailed bundle information' content: application/json: schema: type: object nullable: true tags: - 'Bundles Management' patch: summary: 'Update bundle (admin only)' operationId: updateBundleadminOnly description: '' parameters: [] responses: { } tags: - 'Bundles Management' requestBody: required: false content: application/json: schema: type: object properties: name: type: string description: 'Must not be greater than 255 characters.' example: vmqeopfuudtdsufvyvddq nullable: false application_number: type: integer description: 'Must be at least 1.' example: 2 nullable: false emerging_price: type: number description: 'Price for emerging markets' example: 45.0 nullable: false global_price: type: number description: 'Price for global markets' example: 95.0 nullable: false currency_id: type: integer description: 'Currency ID' example: 2 nullable: false whats_included: type: array description: 'Array of features included' example: - consequatur items: type: string ideal_for: type: string description: 'Must not be greater than 255 characters.' example: mqeopfuudtdsufvyvddqa nullable: true is_active: type: boolean description: '' example: true nullable: false delete: summary: 'Delete bundle (admin only)' operationId: deleteBundleadminOnly description: '' parameters: [] responses: { } tags: - 'Bundles Management' parameters: - in: path name: bundleId description: '' example: consequatur required: true schema: type: string /api/v1/contacts: post: summary: 'Store a newly created contact.' operationId: storeANewlyCreatedContact description: '' parameters: [] responses: { } tags: - 'Contact Management' requestBody: required: true content: application/json: schema: type: object properties: email: type: string description: 'the email of the contact. Must be a valid email address.' example: qkunze@example.com nullable: false phone: type: string description: 'the phone number of the contact.' example: consequatur nullable: false address: type: string description: 'the address of the contact. Must be at least 6 characters.' example: mqeopfuudtdsufvyvddqamniihfqcoynlazghdtqtqxbajwbpilpmufinllwloauydlsmsjury nullable: false personal_information_id: type: integer description: 'the id of the personal information associated with the contact.' example: 17 nullable: false required: - phone - personal_information_id '/api/v1/contacts/{id}': put: summary: 'Update the specified contact.' operationId: updateTheSpecifiedContact description: '' parameters: [] responses: { } tags: - 'Contact Management' requestBody: required: false content: application/json: schema: type: object properties: email: type: string description: 'the email of the contact. Must be a valid email address.' example: qkunze@example.com nullable: false phone: type: string description: 'the phone number of the contact.' example: null nullable: false address: type: string description: 'the address of the contact. Must be at least 6 characters.' example: opfuudtdsufvyvddqamniihfqcoynlazghdtqtqxbajwbpilpmufinllwloauydlsmsjuryvoj nullable: false delete: summary: 'Delete the specified contact.' operationId: deleteTheSpecifiedContact description: 'this must be done by the owning user or an admin.' parameters: [] responses: { } tags: - 'Contact Management' parameters: - in: path name: id description: 'The ID of the contact.' example: 1 required: true schema: type: integer /api/v1/countries: get: summary: 'List countries with filters' operationId: listCountriesWithFilters description: "Returns paginated list of countries with their associated region information.\nSupports filtering by region name, market tier, and search queries." parameters: - in: query name: region description: 'Filter by region name. One of: Africa, Asia, Europe, USA, UK, UAE.' example: Africa required: false schema: type: string description: 'Filter by region name. One of: Africa, Asia, Europe, USA, UK, UAE.' example: Africa nullable: false - in: query name: tier description: 'Filter by market tier. One of: emerging, global.' example: emerging required: false schema: type: string description: 'Filter by market tier. One of: emerging, global.' example: emerging nullable: false - in: query name: search description: 'Search by country code or name (English/French).' example: Burundi required: false schema: type: string description: 'Search by country code or name (English/French).' example: Burundi nullable: false - in: query name: sort_by description: 'Field to sort by. One of: code, name, created_at. Default: created_at.' example: code required: false schema: type: string description: 'Field to sort by. One of: code, name, created_at. Default: created_at.' example: code nullable: false - in: query name: sort_order description: 'Sort direction. One of: asc, desc. Default: desc.' example: asc required: false schema: type: string description: 'Sort direction. One of: asc, desc. Default: desc.' example: asc nullable: false - in: query name: per_page description: 'Items per page (1-100). Default: 15.' example: 20 required: false schema: type: integer description: 'Items per page (1-100). Default: 15.' example: 20 nullable: false responses: 200: description: 'Paginated list of countries' content: application/json: schema: type: object nullable: true tags: - 'Countries Management' requestBody: required: false content: application/json: schema: type: object properties: region: type: string description: '' example: UK nullable: true enum: - Africa - Asia - Europe - USA - UK - UAE tier: type: string description: '' example: global nullable: true enum: - emerging - global search: type: string description: 'Must be at least 2 characters. Must not be greater than 50 characters.' example: vmqeopfuudtdsufvyvddq nullable: true sort_by: type: string description: '' example: code nullable: true enum: - code - name - created_at sort_order: type: string description: '' example: desc nullable: true enum: - asc - desc per_page: type: integer description: 'Must be at least 1. Must not be greater than 100.' example: 1 nullable: true '/api/v1/countries/{id}': get: summary: 'Get country details' operationId: getCountryDetails description: '' parameters: [] responses: 200: description: 'Country details with region' content: application/json: schema: type: object nullable: true tags: - 'Countries Management' parameters: - in: path name: id description: 'The ID of the country.' example: 002e58d3-68bd-4d41-80b0-eb9e97919daf required: true schema: type: string - in: path name: country description: 'Optional parameter. uuid required The UUID of the country.' required: true schema: type: integer examples: omitted: summary: 'When the value is omitted' value: '' present: summary: 'When the value is present' value: 9 /api/v1/admin/countries: post: summary: 'Create new country' operationId: createNewCountry description: 'Creates a new country with localized names and associates it with a study destination region.' parameters: [] responses: 201: description: 'Country created successfully' content: application/json: schema: type: object nullable: true tags: - 'Countries Management' requestBody: required: true content: application/json: schema: type: object properties: code: type: string description: 'ISO country code (2 characters).' example: BI nullable: false flag: type: string description: 'Flag emoji or image URL.' example: 🇧🇮 nullable: false dial_code: type: string description: 'International dialing code.' example: '+257' nullable: false name: type: object description: 'Localized country names.' example: [] nullable: false properties: en: type: string description: 'English name.' example: Burundi nullable: false fr: type: string description: 'French name.' example: Burundi nullable: false required: - en - fr region_id: type: uuid description: 'The study destination region ID.' example: 9b1e967a-706d-4912-9c31 nullable: false required: - code - flag - dial_code - name - region_id '/api/v1/admin/countries/{id}': put: summary: 'Update country' operationId: updateCountry description: '' parameters: [] responses: 200: description: 'Country updated successfully' content: application/json: schema: type: object nullable: true tags: - 'Countries Management' requestBody: required: false content: application/json: schema: type: object properties: code: type: string description: 'optional ISO country code.' example: BI nullable: false flag: type: string description: 'optional Flag emoji or URL.' example: 🇧🇮 nullable: false dial_code: type: string description: 'optional Dialing code.' example: '+257' nullable: false name: type: object description: 'optional Localized names.' example: [] nullable: false properties: en: type: string description: 'optional English name.' example: Burundi nullable: false fr: type: string description: 'optional French name.' example: Burundi nullable: false region_id: type: uuid description: 'optional Study destination region ID.' example: 9b1e967a-706d-4912-9c31 nullable: false delete: summary: 'Delete country' operationId: deleteCountry description: '' parameters: [] responses: 204: description: 'Country deleted successfully' content: application/json: schema: type: object nullable: true tags: - 'Countries Management' parameters: - in: path name: id description: 'The ID of the country.' example: 002e58d3-68bd-4d41-80b0-eb9e97919daf required: true schema: type: string - in: path name: country description: 'Optional parameter. uuid required The UUID of the country.' required: true schema: type: integer examples: omitted: summary: 'When the value is omitted' value: '' present: summary: 'When the value is present' value: 9 '/api/v1/users/{user_id}/credits/deduct': post: summary: 'Deduct credits for application' operationId: deductCreditsForApplication description: '' parameters: [] responses: 200: description: 'Credits deducted successfully' content: application/json: schema: type: object nullable: true 400: description: 'Insufficient credits' content: application/json: schema: type: object nullable: true tags: - 'Credit Management' requestBody: required: false content: application/json: schema: type: object properties: quantity: type: integer description: 'Number of applications to deduct' example: 1 nullable: false preferred_bundle_id: type: string description: 'Specific bundle to use' example: consequatur nullable: false price_type: type: string description: 'Prefer emerging or global price credits' example: emerging nullable: false parameters: - in: path name: user_id description: 'The ID of the user.' example: 1 required: true schema: type: integer '/api/v1/users/{user_id}/credits/balance': get: summary: 'Get user credit balance' operationId: getUserCreditBalance description: '' parameters: [] responses: 200: description: 'Current credit balance with breakdown' content: application/json: schema: type: object nullable: true tags: - 'Credit Management' parameters: - in: path name: user_id description: 'The ID of the user.' example: 1 required: true schema: type: integer '/api/v1/users/{user_id}/credits/history': get: summary: 'Get user credit history' operationId: getUserCreditHistory description: '' parameters: [] responses: 200: description: 'Credit transaction history' content: application/json: schema: type: object nullable: true tags: - 'Credit Management' parameters: - in: path name: user_id description: 'The ID of the user.' example: 1 required: true schema: type: integer '/api/v1/users/{user_id}/transactions': post: summary: 'Record a transaction' operationId: recordATransaction description: 'Typically used when a user purchases credits or pays an application fee.' parameters: [] responses: 200: description: 'Transaction recorded successfully' content: application/json: schema: type: object nullable: true tags: - 'Credit Management' requestBody: required: true content: application/json: schema: type: object properties: transaction_type: type: string description: 'Type of transaction' example: credit_purchase nullable: false amount: type: integer description: 'Amount in credits or currency units' example: 100 nullable: false required: - transaction_type - amount get: summary: 'List user transaction history' operationId: listUserTransactionHistory description: 'Returns paginated list of all recorded transactions.' parameters: - in: query name: per_page description: 'Number of items per page' example: 20 required: false schema: type: integer description: 'Number of items per page' example: 20 nullable: false responses: 200: description: 'Paginated list of transactions' content: application/json: schema: type: object nullable: true tags: - 'Credit Management' parameters: - in: path name: user_id description: 'The ID of the user.' example: 1 required: true schema: type: integer '/api/v1/users/{user_id}/transactions/{transactionId}': get: summary: 'Show a transaction' operationId: showATransaction description: '' parameters: [] responses: 200: description: 'Transaction details' content: application/json: schema: type: object nullable: true 404: description: 'Transaction not found' content: application/json: schema: type: object nullable: true tags: - 'Credit Management' parameters: - in: path name: user_id description: 'The ID of the user.' example: 1 required: true schema: type: integer - in: path name: transactionId description: '' example: consequatur required: true schema: type: string '/api/v1/admin/universities/{university_id}/credits/add': post: summary: 'Add credits to university' operationId: addCreditsToUniversity description: '' parameters: [] responses: 200: description: 'Credits added successfully' content: application/json: schema: type: object nullable: true tags: - 'Credit Management' requestBody: required: true content: application/json: schema: type: object properties: amount: type: integer description: 'Amount of credits to add (minimum 1)' example: 100 nullable: false description: type: string description: 'Optional description' example: 'Bulk purchase' nullable: false required: - amount parameters: - in: path name: university_id description: 'The ID of the university.' example: 00ce85a9-6d2d-4be1-a0cd-274d7c063eac required: true schema: type: string '/api/v1/admin/universities/{university_id}/credits/deduct': post: summary: 'Deduct credits from university' operationId: deductCreditsFromUniversity description: '' parameters: [] responses: 200: description: 'Credits deducted successfully' content: application/json: schema: type: object nullable: true 400: description: 'Insufficient credits' content: application/json: schema: type: object nullable: true 404: description: 'No credit record found' content: application/json: schema: type: object nullable: true tags: - 'Credit Management' requestBody: required: true content: application/json: schema: type: object properties: amount: type: integer description: 'Amount of credits to deduct' example: 10 nullable: false description: type: string description: 'Optional description' example: 'Application processed' nullable: false required: - amount parameters: - in: path name: university_id description: 'The ID of the university.' example: 00ce85a9-6d2d-4be1-a0cd-274d7c063eac required: true schema: type: string '/api/v1/admin/universities/{university_id}/credits/balance': get: summary: 'Get university credit balance' operationId: getUniversityCreditBalance description: '' parameters: [] responses: 200: description: 'Current credit balance' content: application/json: schema: type: object nullable: true tags: - 'Credit Management' parameters: - in: path name: university_id description: 'The ID of the university.' example: 00ce85a9-6d2d-4be1-a0cd-274d7c063eac required: true schema: type: string '/api/v1/admin/majors/{major_id}/credits/add': post: summary: 'Add credits to major' operationId: addCreditsToMajor description: '' parameters: [] responses: 200: description: 'Credits added successfully' content: application/json: schema: type: object nullable: true tags: - 'Credit Management' requestBody: required: true content: application/json: schema: type: object properties: amount: type: integer description: 'Amount of credits to add (minimum 1)' example: 100 nullable: false description: type: string description: 'Optional description' example: 'Bulk purchase' nullable: false required: - amount parameters: - in: path name: major_id description: 'The ID of the major.' example: 6 required: true schema: type: integer '/api/v1/admin/majors/{major_id}/credits/deduct': post: summary: 'Deduct credits from major' operationId: deductCreditsFromMajor description: '' parameters: [] responses: 200: description: 'Credits deducted successfully' content: application/json: schema: type: object nullable: true 400: description: 'Insufficient credits' content: application/json: schema: type: object nullable: true 404: description: 'No credit record found' content: application/json: schema: type: object nullable: true tags: - 'Credit Management' requestBody: required: true content: application/json: schema: type: object properties: amount: type: integer description: 'Amount of credits to deduct' example: 10 nullable: false description: type: string description: 'Optional description' example: 'Application processed' nullable: false required: - amount parameters: - in: path name: major_id description: 'The ID of the major.' example: 6 required: true schema: type: integer '/api/v1/admin/majors/{major_id}/credits/balance': get: summary: 'Get major credit balance' operationId: getMajorCreditBalance description: '' parameters: [] responses: 200: description: 'Current credit balance' content: application/json: schema: type: object nullable: true tags: - 'Credit Management' parameters: - in: path name: major_id description: 'The ID of the major.' example: 6 required: true schema: type: integer /api/v1/credit_purchases: post: summary: 'Submit bundle purchase with payment proof' operationId: submitBundlePurchaseWithPaymentProof description: "Allows a user to buy a credit bundle via offline/manual payment (e.g., mobile money, bank transfer).\nUser selects a bundle and uploads a screenshot/receipt as proof.\nThe request becomes pending until an admin approves or rejects it." parameters: [] responses: 201: description: 'Proof submitted successfully. Awaiting admin approval.' content: application/json: schema: type: object nullable: true 422: description: 'Validation errors (invalid bundle, wrong file type, etc.)' content: application/json: schema: type: object nullable: true tags: - 'Credit Purchases & Bundle Payments' requestBody: required: true content: multipart/form-data: schema: type: object properties: bundle_id: type: string description: 'UUID of the selected bundle' example: 019b1de6-8c48-7396-9209-11c69db9e53b nullable: false amount: type: number description: 'Must be at least 0.01.' example: 56 nullable: false proof_image: type: string format: binary description: 'Image proof of payment (screenshot/receipt). Allowed: jpeg, png, jpg. Max 5MB.' nullable: false required: - bundle_id - amount - proof_image /api/v1/credit_purchases/pending: get: summary: 'List pending credit purchases (admin only)' operationId: listPendingCreditPurchasesadminOnly description: 'Returns paginated list of purchases awaiting approval, with user and bundle details.' parameters: [] responses: 200: description: 'Paginated list of pending purchases' content: application/json: schema: type: object nullable: true tags: - 'Credit Purchases & Bundle Payments' '/api/v1/credit_purchases/{purchaseId}/approve': post: summary: 'Approve credit purchase (admin only)' operationId: approveCreditPurchaseadminOnly description: "On approval:\n- Credits from the bundle are added to the user's balance\n- A transaction record is created (type: credit_purchase)\n- Purchase status changes to approved" parameters: [] responses: 200: description: 'Purchase approved and credits added successfully' content: application/json: schema: type: object nullable: true 400: description: 'Purchase already processed' content: application/json: schema: type: object nullable: true 404: description: 'Purchase not found' content: application/json: schema: type: object nullable: true tags: - 'Credit Purchases & Bundle Payments' parameters: - in: path name: purchaseId description: '' example: consequatur required: true schema: type: string '/api/v1/credit_purchases/{purchaseId}/reject': post: summary: 'Reject credit purchase (admin only)' operationId: rejectCreditPurchaseadminOnly description: 'Rejects the purchase and records an admin note (reason).' parameters: [] responses: 200: description: 'Purchase rejected successfully' content: application/json: schema: type: object nullable: true 400: description: 'Purchase already processed' content: application/json: schema: type: object nullable: true 422: description: 'Missing or invalid admin_note' content: application/json: schema: type: object nullable: true tags: - 'Credit Purchases & Bundle Payments' requestBody: required: true content: application/json: schema: type: object properties: admin_note: type: string description: 'Reason for rejection (visible to user)' example: 'Payment not received or proof unclear' nullable: false required: - admin_note parameters: - in: path name: purchaseId description: '' example: consequatur required: true schema: type: string /api/v1/admin/credit-purchases/pending: get: summary: 'List pending credit purchases (admin only)' operationId: listPendingCreditPurchasesadminOnly description: 'Returns paginated list of purchases awaiting approval, with user and bundle details.' parameters: [] responses: 200: description: 'Paginated list of pending purchases' content: application/json: schema: type: object nullable: true tags: - 'Credit Purchases & Bundle Payments' '/api/v1/admin/credit-purchases/{purchaseId}/approve': post: summary: 'Approve credit purchase (admin only)' operationId: approveCreditPurchaseadminOnly description: "On approval:\n- Credits from the bundle are added to the user's balance\n- A transaction record is created (type: credit_purchase)\n- Purchase status changes to approved" parameters: [] responses: 200: description: 'Purchase approved and credits added successfully' content: application/json: schema: type: object nullable: true 400: description: 'Purchase already processed' content: application/json: schema: type: object nullable: true 404: description: 'Purchase not found' content: application/json: schema: type: object nullable: true tags: - 'Credit Purchases & Bundle Payments' parameters: - in: path name: purchaseId description: '' example: consequatur required: true schema: type: string '/api/v1/admin/credit-purchases/{purchaseId}/reject': post: summary: 'Reject credit purchase (admin only)' operationId: rejectCreditPurchaseadminOnly description: 'Rejects the purchase and records an admin note (reason).' parameters: [] responses: 200: description: 'Purchase rejected successfully' content: application/json: schema: type: object nullable: true 400: description: 'Purchase already processed' content: application/json: schema: type: object nullable: true 422: description: 'Missing or invalid admin_note' content: application/json: schema: type: object nullable: true tags: - 'Credit Purchases & Bundle Payments' requestBody: required: true content: application/json: schema: type: object properties: admin_note: type: string description: 'Reason for rejection (visible to user)' example: 'Payment not received or proof unclear' nullable: false required: - admin_note parameters: - in: path name: purchaseId description: '' example: consequatur required: true schema: type: string /api/v1/currencies: get: summary: 'Display a listing of all the currencies.' operationId: displayAListingOfAllTheCurrencies description: '' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true data: - id: 0a2264e3-b4f0-4ebd-8d07-fcfb99ed1e42 code: GBP symbol: £ - id: 110ac3b9-d073-4e71-ac19-1c20a21ead1a code: EUR symbol: € - id: 134c1321-cfcb-4186-8732-0ed04440b595 code: AUD symbol: A$ - id: 6edd3a74-de48-4273-b307-3354cf7774b4 code: CAD symbol: CA$ - id: 861f0e7e-40fe-4b3f-9771-d3d4676ae8a6 code: USD symbol: $ timestamp: '2026-04-18T17:44:13.812495Z' properties: success: type: boolean example: true data: type: array example: - id: 0a2264e3-b4f0-4ebd-8d07-fcfb99ed1e42 code: GBP symbol: £ - id: 110ac3b9-d073-4e71-ac19-1c20a21ead1a code: EUR symbol: € - id: 134c1321-cfcb-4186-8732-0ed04440b595 code: AUD symbol: A$ - id: 6edd3a74-de48-4273-b307-3354cf7774b4 code: CAD symbol: CA$ - id: 861f0e7e-40fe-4b3f-9771-d3d4676ae8a6 code: USD symbol: $ items: type: object properties: id: type: string example: 0a2264e3-b4f0-4ebd-8d07-fcfb99ed1e42 code: type: string example: GBP symbol: type: string example: £ timestamp: type: string example: '2026-04-18T17:44:13.812495Z' tags: - Currency post: summary: 'Store a newly created currency.' operationId: storeANewlyCreatedCurrency description: '' parameters: [] responses: { } tags: - Currency requestBody: required: true content: application/json: schema: type: object properties: code: type: string description: 'Must not be greater than 10 characters.' example: vmqeopfuu nullable: false symbol: type: string description: 'Must not be greater than 10 characters.' example: dtdsufvyv nullable: true required: - code '/api/v1/currencies/{id}': get: summary: 'Display the specified currency.' operationId: displayTheSpecifiedCurrency description: '' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true data: id: 0a2264e3-b4f0-4ebd-8d07-fcfb99ed1e42 code: GBP symbol: £ created_at: '2026-01-30T15:31:20.000000Z' updated_at: null timestamp: '2026-04-18T17:44:13.819596Z' properties: success: type: boolean example: true data: type: object properties: id: type: string example: 0a2264e3-b4f0-4ebd-8d07-fcfb99ed1e42 code: type: string example: GBP symbol: type: string example: £ created_at: type: string example: '2026-01-30T15:31:20.000000Z' updated_at: type: string example: null timestamp: type: string example: '2026-04-18T17:44:13.819596Z' tags: - Currency put: summary: 'Update the specified currency.' operationId: updateTheSpecifiedCurrency description: '' parameters: [] responses: { } tags: - Currency requestBody: required: false content: application/json: schema: type: object properties: code: type: string description: '' example: null nullable: false symbol: type: string description: 'Must not be greater than 10 characters.' example: vmqeopfuu nullable: false delete: summary: 'Remove the specified resource from storage.' operationId: removeTheSpecifiedResourceFromStorage description: '' parameters: [] responses: { } tags: - Currency parameters: - in: path name: id description: 'The ID of the currency.' example: 0a2264e3-b4f0-4ebd-8d07-fcfb99ed1e42 required: true schema: type: string /api/v1/admin/current_status: get: summary: 'List of all the current status a student can have.' operationId: listOfAllTheCurrentStatusAStudentCanHave description: '' parameters: [] responses: 500: description: '' content: application/json: schema: type: object example: success: false errors: Unauthenticated. timestamp: '2026-04-18T17:44:14.325009Z' properties: success: type: boolean example: false errors: type: string example: Unauthenticated. timestamp: type: string example: '2026-04-18T17:44:14.325009Z' tags: - 'Current Status Management' post: summary: 'Store a newly created current status.' operationId: storeANewlyCreatedCurrentStatus description: '' parameters: [] responses: { } tags: - 'Current Status Management' requestBody: required: true content: application/json: schema: type: object properties: name: type: string description: 'the name of the current status.' example: consequatur nullable: false required: - name '/api/v1/admin/current_status/{id}': get: summary: 'Show one current status.' operationId: showOneCurrentStatus description: '' parameters: [] responses: 500: description: '' content: application/json: schema: type: object example: success: false errors: Unauthenticated. timestamp: '2026-04-18T17:44:14.330470Z' properties: success: type: boolean example: false errors: type: string example: Unauthenticated. timestamp: type: string example: '2026-04-18T17:44:14.330470Z' tags: - 'Current Status Management' put: summary: 'Update the specified resource in storage.' operationId: updateTheSpecifiedResourceInStorage description: '' parameters: [] responses: { } tags: - 'Current Status Management' requestBody: required: false content: application/json: schema: type: object properties: name: type: string description: '' example: consequatur nullable: false delete: summary: 'Remove the specified resource from storage.' operationId: removeTheSpecifiedResourceFromStorage description: '' parameters: [] responses: { } tags: - 'Current Status Management' parameters: - in: path name: id description: 'The ID of the current status.' example: 1 required: true schema: type: integer /api/v1/document_locker: get: summary: 'Show the content of the document locker' operationId: showTheContentOfTheDocumentLocker description: 'The document locker that is associated with authenticated user also the user has to be as student.' parameters: [] responses: 500: description: '' content: application/json: schema: type: object example: success: false errors: Unauthenticated. timestamp: '2026-04-18T17:44:13.972366Z' properties: success: type: boolean example: false errors: type: string example: Unauthenticated. timestamp: type: string example: '2026-04-18T17:44:13.972366Z' tags: - 'Document Locker' '/api/v1/document_locker/{id}': get: summary: 'Show one specific document locker by user id' operationId: showOneSpecificDocumentLockerByUserId description: 'can be used by the user owner of the token or an admin to fetch the document locker of a specific user' parameters: - in: query name: id description: 'The id of the user whose document locker you want to fetch.' example: '1' required: true schema: type: string description: 'The id of the user whose document locker you want to fetch.' example: '1' nullable: false responses: 500: description: '' content: application/json: schema: type: object example: success: false errors: Unauthenticated. timestamp: '2026-04-18T17:44:13.976135Z' properties: success: type: boolean example: false errors: type: string example: Unauthenticated. timestamp: type: string example: '2026-04-18T17:44:13.976135Z' tags: - 'Document Locker' parameters: - in: path name: id description: 'The ID of the document locker.' example: consequatur required: true schema: type: string /api/v1/exam_results: get: summary: "List all exam results for the authenticated user's locker." operationId: listAllExamResultsForTheAuthenticatedUsersLocker description: '' parameters: [] responses: 500: description: '' content: application/json: schema: type: object example: success: false errors: Unauthenticated. timestamp: '2026-04-18T17:44:13.980129Z' properties: success: type: boolean example: false errors: type: string example: Unauthenticated. timestamp: type: string example: '2026-04-18T17:44:13.980129Z' tags: - 'Document Locker' '/api/v1/exam_results/{id}': get: summary: "Show a specific exam result in the authenticated user's locker." operationId: showASpecificExamResultInTheAuthenticatedUsersLocker description: '' parameters: [] responses: 500: description: '' content: application/json: schema: type: object example: success: false errors: Unauthenticated. timestamp: '2026-04-18T17:44:13.984827Z' properties: success: type: boolean example: false errors: type: string example: Unauthenticated. timestamp: type: string example: '2026-04-18T17:44:13.984827Z' tags: - 'Document Locker' delete: summary: "Delete a specific exam result from the authenticated user's locker." operationId: deleteASpecificExamResultFromTheAuthenticatedUsersLocker description: '' parameters: [] responses: { } tags: - 'Document Locker' parameters: - in: path name: id description: 'The ID of the exam result.' example: consequatur required: true schema: type: string /api/v1/other_documents: get: summary: "List all other documents for the authenticated user's locker." operationId: listAllOtherDocumentsForTheAuthenticatedUsersLocker description: '' parameters: [] responses: 500: description: '' content: application/json: schema: type: object example: success: false errors: Unauthenticated. timestamp: '2026-04-18T17:44:13.991169Z' properties: success: type: boolean example: false errors: type: string example: Unauthenticated. timestamp: type: string example: '2026-04-18T17:44:13.991169Z' tags: - 'Document Locker' '/api/v1/other_documents/{id}': get: summary: "Show a specific other document in the authenticated user's locker." operationId: showASpecificOtherDocumentInTheAuthenticatedUsersLocker description: '' parameters: [] responses: 500: description: '' content: application/json: schema: type: object example: success: false errors: Unauthenticated. timestamp: '2026-04-18T17:44:13.995208Z' properties: success: type: boolean example: false errors: type: string example: Unauthenticated. timestamp: type: string example: '2026-04-18T17:44:13.995208Z' tags: - 'Document Locker' delete: summary: "Delete a specific other document from the authenticated user's locker." operationId: deleteASpecificOtherDocumentFromTheAuthenticatedUsersLocker description: '' parameters: [] responses: { } tags: - 'Document Locker' parameters: - in: path name: id description: 'The ID of the other document.' example: consequatur required: true schema: type: string /api/v1/document_locker/setup: post: summary: 'Setup or init a new document locker for the authenticated student' operationId: setupOrInitANewDocumentLockerForTheAuthenticatedStudent description: '' parameters: [] responses: { } tags: - 'Document Locker' /api/v1/document_locker/upload: post: summary: "Endpoint to upload documents to the authenticated student's locker." operationId: endpointToUploadDocumentsToTheAuthenticatedStudentsLocker description: "Supported upload types (send as `upload_type`):\n- transcript: requires `description` (string) and `transcript_file` (file: pdf, txt, docx)\n- exam_results: requires `exam_name` (string) and either `exam_result_file` (file) OR `exam_result_text` (string). Optional `score` and `description`.\n- recommendation_letter: requires `description` and `recommendation_letter_file` (file)\n- personal_statement: requires `description` and either `personal_statement_file` (file) or `personal_statement_text` (string)\n- resume: requires `resume_file` (file)\n- passport: requires `passport_file` (file)\n- id_document: requires `id_document_file` (file: pdf, jpg, png), `document_type` (string: passport, national_id, drivers_license, etc.), and `date_of_birth` (date: Y-m-d format)\n- others: requires `document_name`, optional `description`, and `other_document_file` (file: pdf, jpg, png)\n\nFiles are validated with extensions and size limits (see controller validation rules)." parameters: [] responses: { } tags: - 'Document Locker' requestBody: required: true content: application/json: schema: type: object properties: upload_type: type: string description: 'The type of upload.' example: transcript nullable: false required: - upload_type /api/v1/document_locker/replace: post: summary: 'Endpoint to replace a document already stored in the locker.' operationId: endpointToReplaceADocumentAlreadyStoredInTheLocker description: "Use `upload_type` and `doc_id` to select which document to replace, then send the same file param that\nwould be used for an upload of that type. Supported `upload_type` values and file params are the same as\nfor the upload endpoint (transcript, exam_results, recommendation_letter, personal_statement, resume, passport, others)." parameters: [] responses: { } tags: - 'Document Locker' requestBody: required: true content: application/json: schema: type: object properties: upload_type: type: string description: 'The type of upload.' example: transcript nullable: false doc_id: type: integer description: 'The id of the document to replace.' example: 17 nullable: false required: - upload_type - doc_id /api/v1/profile/grade: post: summary: "Submit or update the student's overall academic grade." operationId: submitOrUpdateTheStudentsOverallAcademicGrade description: "This endpoint allows a student to manually enter their academic average (e.g., moyenne générale from Diplôme d'État\nfor Burundian users, GPA for international users, etc.). The submitted grade is stored in the Document Locker\nsection and requires admin verification before it can be used in university/major recommendation matching." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: message: 'Grade submitted successfully' grade: id: 45 user_id: 123 grading_system: percentage_100 grade_value: 76.5 description: "Moyenne générale - Diplôme d'État 2024" status_id: 2 verified_at: null created_at: '2025-12-15T10:30:00.000000Z' updated_at: '2025-12-15T10:30:00.000000Z' properties: message: type: string example: 'Grade submitted successfully' grade: type: object properties: id: type: integer example: 45 user_id: type: integer example: 123 grading_system: type: string example: percentage_100 grade_value: type: number example: 76.5 description: type: string example: "Moyenne générale - Diplôme d'État 2024" status_id: type: integer example: 2 verified_at: type: string example: null created_at: type: string example: '2025-12-15T10:30:00.000000Z' updated_at: type: string example: '2025-12-15T10:30:00.000000Z' 403: description: '' content: application/json: schema: type: object example: error: 'Not a student' properties: error: type: string example: 'Not a student' 422: description: '' content: application/json: schema: type: object example: message: 'The given data was invalid.' errors: grading_system: - 'The selected grading system is invalid.' grade_value: - 'The grade value must be a number.' properties: message: type: string example: 'The given data was invalid.' errors: type: object properties: grading_system: type: array example: - 'The selected grading system is invalid.' items: type: string grade_value: type: array example: - 'The grade value must be a number.' items: type: string tags: - 'Document Locker' requestBody: required: true content: application/json: schema: type: object properties: grading_system: type: string description: "The grading system used. Must be one of:\n - \"percentage_100\" (default for Burundi users, e.g., 76.5)\n - \"gpa_4_0\" (US/international GPA, e.g., 3.2)\n - \"out_of_20\" (French-system score, e.g., 15.4)\n - \"other\" (for any non-standard format)" example: percentage_100 nullable: false grade_value: type: number description: "The numeric value of the grade (without symbols or units).\n Examples:\n - 76.5 for percentage_100\n - 3.2 for gpa_4_0\n - 15.4 for out_of_20" example: 11613.31890586 nullable: false description: type: string description: "nullable\n Optional description of the grade." example: '"Moyenne générale - Diplôme d''État 2024"' nullable: true required: - grading_system - grade_value /api/v1/admin/upload_validation: post: summary: 'Admin verification of a specific uploaded document' operationId: adminVerificationOfASpecificUploadedDocument description: '' parameters: [] responses: { } tags: - 'Document Locker' requestBody: required: true content: application/json: schema: type: object properties: document_locker_id: type: integer description: '' example: 17 nullable: false document_type: type: string description: 'One of: transcript, recommendation_letter, personal_statement, resume, passport, exam_results, id_document, others' example: consequatur nullable: false document_id: type: integer description: '' example: 17 nullable: false verdict: type: string description: 'Must be: approved or rejected' example: consequatur nullable: false feedback: type: string description: 'nullable Required if verdict is rejected' example: consequatur nullable: true required: - document_locker_id - document_type - document_id - verdict /api/v1/fetch-file: get: summary: 'File Proxy Route' operationId: fileProxyRoute description: '* @query url string The full public URL of the file (e.g., https://.../storage/uploads/file.docx)' parameters: [] responses: 400: description: '' content: application/json: schema: type: object example: error: 'No URL provided' properties: error: type: string example: 'No URL provided' tags: - Endpoints /api/v1/onboarding_data: get: summary: 'Retrieve onboarding data grouped by major category' operationId: retrieveOnboardingDataGroupedByMajorCategory description: '' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true data: message: 'Onboarding data retrieved successfully' categories: - id: 1 name: 'Agriculture, Food & Natural Resources' slug: agriculture-food-natural-resources icon: null created_at: '2026-04-14T07:44:08.000000Z' updated_at: '2026-04-14T07:44:08.000000Z' - id: 2 name: 'Architecture & Construction' slug: architecture-construction icon: null created_at: '2026-04-14T07:44:08.000000Z' updated_at: '2026-04-14T07:44:08.000000Z' - id: 3 name: 'Arts, Design & Media' slug: arts-design-media icon: null created_at: '2026-04-14T07:44:08.000000Z' updated_at: '2026-04-14T07:44:08.000000Z' - id: 4 name: 'Business, Management & Finance' slug: business-management-finance icon: null created_at: '2026-04-14T07:44:08.000000Z' updated_at: '2026-04-14T07:44:08.000000Z' - id: 5 name: 'Computer Science & Information Technology' slug: computer-science-information-technology icon: null created_at: '2026-04-14T07:44:08.000000Z' updated_at: '2026-04-14T07:44:08.000000Z' - id: 6 name: 'Education & Training' slug: education-training icon: null created_at: '2026-04-14T07:44:08.000000Z' updated_at: '2026-04-14T07:44:08.000000Z' - id: 7 name: 'Engineering & Manufacturing' slug: engineering-manufacturing icon: null created_at: '2026-04-14T07:44:08.000000Z' updated_at: '2026-04-14T07:44:08.000000Z' - id: 8 name: 'Health Sciences & Medicine' slug: health-sciences-medicine icon: null created_at: '2026-04-14T07:44:08.000000Z' updated_at: '2026-04-14T07:44:08.000000Z' - id: 9 name: 'Humanities & Culture' slug: humanities-culture icon: null created_at: '2026-04-14T07:44:08.000000Z' updated_at: '2026-04-14T07:44:08.000000Z' - id: 10 name: 'Law, Public Safety & Security' slug: law-public-safety-security icon: null created_at: '2026-04-14T07:44:08.000000Z' updated_at: '2026-04-14T07:44:08.000000Z' - id: 11 name: 'Social Sciences & Psychology' slug: social-sciences-psychology icon: null created_at: '2026-04-14T07:44:08.000000Z' updated_at: '2026-04-14T07:44:08.000000Z' - id: 12 name: 'Natural Sciences & Mathematics' slug: natural-sciences-mathematics icon: null created_at: '2026-04-14T07:44:08.000000Z' updated_at: '2026-04-14T07:44:08.000000Z' - id: 13 name: 'Tourism, Hospitality & Culinary Arts' slug: tourism-hospitality-culinary-arts icon: null created_at: '2026-04-14T07:44:08.000000Z' updated_at: '2026-04-14T07:44:08.000000Z' - id: 14 name: 'Communication & Journalism' slug: communication-journalism icon: null created_at: '2026-04-14T07:44:08.000000Z' updated_at: '2026-04-14T07:44:08.000000Z' timestamp: '2026-04-18T17:44:13.836548Z' properties: success: type: boolean example: true data: type: object properties: message: type: string example: 'Onboarding data retrieved successfully' categories: type: array example: - id: 1 name: 'Agriculture, Food & Natural Resources' slug: agriculture-food-natural-resources icon: null created_at: '2026-04-14T07:44:08.000000Z' updated_at: '2026-04-14T07:44:08.000000Z' - id: 2 name: 'Architecture & Construction' slug: architecture-construction icon: null created_at: '2026-04-14T07:44:08.000000Z' updated_at: '2026-04-14T07:44:08.000000Z' - id: 3 name: 'Arts, Design & Media' slug: arts-design-media icon: null created_at: '2026-04-14T07:44:08.000000Z' updated_at: '2026-04-14T07:44:08.000000Z' - id: 4 name: 'Business, Management & Finance' slug: business-management-finance icon: null created_at: '2026-04-14T07:44:08.000000Z' updated_at: '2026-04-14T07:44:08.000000Z' - id: 5 name: 'Computer Science & Information Technology' slug: computer-science-information-technology icon: null created_at: '2026-04-14T07:44:08.000000Z' updated_at: '2026-04-14T07:44:08.000000Z' - id: 6 name: 'Education & Training' slug: education-training icon: null created_at: '2026-04-14T07:44:08.000000Z' updated_at: '2026-04-14T07:44:08.000000Z' - id: 7 name: 'Engineering & Manufacturing' slug: engineering-manufacturing icon: null created_at: '2026-04-14T07:44:08.000000Z' updated_at: '2026-04-14T07:44:08.000000Z' - id: 8 name: 'Health Sciences & Medicine' slug: health-sciences-medicine icon: null created_at: '2026-04-14T07:44:08.000000Z' updated_at: '2026-04-14T07:44:08.000000Z' - id: 9 name: 'Humanities & Culture' slug: humanities-culture icon: null created_at: '2026-04-14T07:44:08.000000Z' updated_at: '2026-04-14T07:44:08.000000Z' - id: 10 name: 'Law, Public Safety & Security' slug: law-public-safety-security icon: null created_at: '2026-04-14T07:44:08.000000Z' updated_at: '2026-04-14T07:44:08.000000Z' - id: 11 name: 'Social Sciences & Psychology' slug: social-sciences-psychology icon: null created_at: '2026-04-14T07:44:08.000000Z' updated_at: '2026-04-14T07:44:08.000000Z' - id: 12 name: 'Natural Sciences & Mathematics' slug: natural-sciences-mathematics icon: null created_at: '2026-04-14T07:44:08.000000Z' updated_at: '2026-04-14T07:44:08.000000Z' - id: 13 name: 'Tourism, Hospitality & Culinary Arts' slug: tourism-hospitality-culinary-arts icon: null created_at: '2026-04-14T07:44:08.000000Z' updated_at: '2026-04-14T07:44:08.000000Z' - id: 14 name: 'Communication & Journalism' slug: communication-journalism icon: null created_at: '2026-04-14T07:44:08.000000Z' updated_at: '2026-04-14T07:44:08.000000Z' items: type: object properties: id: type: integer example: 1 name: type: string example: 'Agriculture, Food & Natural Resources' slug: type: string example: agriculture-food-natural-resources icon: type: string example: null created_at: type: string example: '2026-04-14T07:44:08.000000Z' updated_at: type: string example: '2026-04-14T07:44:08.000000Z' timestamp: type: string example: '2026-04-18T17:44:13.836548Z' tags: - Endpoints /api/v1/onboarding: post: summary: 'Complete the student onboarding process.' operationId: completeTheStudentOnboardingProcess description: '' parameters: [] responses: { } tags: - Endpoints requestBody: required: true content: multipart/form-data: schema: type: object properties: date_of_birth: type: string description: 'Must be a valid date. Must be a valid date in the format Y-m-d. Must be a date before today.' example: '2020-08-14' nullable: false gender: type: string description: '' example: Male nullable: false enum: - Male - Female - Other nationality: type: string description: 'Must not be greater than 100 characters.' example: mqeopfuudtdsufvyvddqa nullable: false profile_photo: type: string format: binary description: 'Must be a file. Must not be greater than 5120 kilobytes.' nullable: true email: type: string description: 'Must be a valid email address. Must not be greater than 255 characters.' example: eloisa.harber@example.com nullable: false phone: type: string description: 'Must not be greater than 20 characters.' example: fqcoynlazghdtqtqx nullable: false address: type: string description: 'Must not be greater than 500 characters.' example: bajwbpilpmufinllwloau nullable: false languages: type: array description: 'Must be at least 2 characters. Must not be greater than 50 characters.' example: - ydlsmsjuryvojcybzvrby items: type: string id_document_file: type: string format: binary description: 'Must be a file. Must not be greater than 5120 kilobytes.' nullable: false id_document_type: type: string description: 'Must be at least 3 characters. Must not be greater than 100 characters.' example: ickznkygloigmkwxphlva nullable: false study_destination_ids: type: array description: 'The id of an existing record in the study_destinations table.' example: - 17 items: type: integer intended_field_of_study: type: string description: 'Must not be greater than 255 characters.' example: mqeopfuudtdsufvyvddqa nullable: false min_budget: type: number description: 'Must be at least 0.' example: 45 nullable: false max_budget: type: number description: 'Must be at least 0.' example: 46 nullable: false currency: type: string description: '' example: CHF nullable: false enum: - USD - EUR - GBP - CAD - AUD - CHF - CNY - INR - JPY - KES - UGX - RWF - BIF scholarship_interest: type: boolean description: '' example: true nullable: false special_needs: type: array description: 'Must not be greater than 255 characters.' example: - iihfqcoynlazghdtqtqxb items: type: string category_ids: type: array description: 'The id of an existing record in the major_categories table.' example: - consequatur items: type: string required: - date_of_birth - gender - nationality - email - phone - address - id_document_file - id_document_type - intended_field_of_study - min_budget - max_budget - currency - scholarship_interest - category_ids /api/v1/document-packages: post: summary: 'Request a new document package (queued generation)' operationId: requestANewDocumentPackagequeuedGeneration description: '' parameters: [] responses: { } tags: - Endpoints requestBody: required: true content: application/json: schema: type: object properties: user_id: type: integer description: 'The id of an existing record in the users table.' example: 17 nullable: false required: - user_id get: summary: 'List all document packages' operationId: listAllDocumentPackages description: '' parameters: [] responses: 500: description: '' content: application/json: schema: type: object example: success: false errors: Unauthenticated. timestamp: '2026-04-18T17:44:14.240239Z' properties: success: type: boolean example: false errors: type: string example: Unauthenticated. timestamp: type: string example: '2026-04-18T17:44:14.240239Z' tags: - Endpoints '/api/v1/document-packages/{package_id}': get: summary: 'Get single package details' operationId: getSinglePackageDetails description: '' parameters: [] responses: 500: description: '' content: application/json: schema: type: object example: success: false errors: Unauthenticated. timestamp: '2026-04-18T17:44:14.244495Z' properties: success: type: boolean example: false errors: type: string example: Unauthenticated. timestamp: type: string example: '2026-04-18T17:44:14.244495Z' tags: - Endpoints delete: summary: 'Delete a package' operationId: deleteAPackage description: '' parameters: [] responses: { } tags: - Endpoints parameters: - in: path name: package_id description: 'The ID of the package.' example: consequatur required: true schema: type: string '/api/v1/document-packages/{package_id}/download': get: summary: 'Download a completed package - serves file through API with auth check' operationId: downloadACompletedPackageServesFileThroughAPIWithAuthCheck description: '' parameters: [] responses: 500: description: '' content: application/json: schema: type: object example: success: false errors: Unauthenticated. timestamp: '2026-04-18T17:44:14.248434Z' properties: success: type: boolean example: false errors: type: string example: Unauthenticated. timestamp: type: string example: '2026-04-18T17:44:14.248434Z' tags: - Endpoints parameters: - in: path name: package_id description: 'The ID of the package.' example: consequatur required: true schema: type: string '/api/v1/document-packages/{package_id}/retry': post: summary: 'Retry a failed package' operationId: retryAFailedPackage description: '' parameters: [] responses: { } tags: - Endpoints parameters: - in: path name: package_id description: 'The ID of the package.' example: consequatur required: true schema: type: string /api/v1/admin/totals: get: summary: 'basic metrics about totals' operationId: basicMetricsAboutTotals description: "Total applications\nTotal students\nTotal universities\nTotal majors" parameters: [] responses: 500: description: '' content: application/json: schema: type: object example: success: false errors: Unauthenticated. timestamp: '2026-04-18T17:44:14.295340Z' properties: success: type: boolean example: false errors: type: string example: Unauthenticated. timestamp: type: string example: '2026-04-18T17:44:14.295340Z' tags: - Endpoints /api/v1/admin/metrics: get: summary: 'Return precomputed dashboard metrics or a timeseries over a date range.' operationId: returnPrecomputedDashboardMetricsOrATimeseriesOverADateRange description: "Query params:\n- start YYYY-MM-DD (optional)\n- end YYYY-MM-DD (optional)" parameters: [] responses: 500: description: '' content: application/json: schema: type: object example: success: false errors: Unauthenticated. timestamp: '2026-04-18T17:44:14.395589Z' properties: success: type: boolean example: false errors: type: string example: Unauthenticated. timestamp: type: string example: '2026-04-18T17:44:14.395589Z' tags: - Endpoints /api/v1/admin/metrics/recompute: post: summary: '' operationId: postApiV1AdminMetricsRecompute description: '' parameters: [] responses: { } tags: - Endpoints /api/v1/admin/metrics/universities: get: summary: 'Return aggregated per-university metrics over a date range (or single day if start=end)' operationId: returnAggregatedPerUniversityMetricsOverADateRangeorSingleDayIfStartend description: '' parameters: [] responses: 500: description: '' content: application/json: schema: type: object example: success: false errors: Unauthenticated. timestamp: '2026-04-18T17:44:14.399954Z' properties: success: type: boolean example: false errors: type: string example: Unauthenticated. timestamp: type: string example: '2026-04-18T17:44:14.399954Z' tags: - Endpoints /api/v1/admin/metrics/events: get: summary: 'List metric events with optional filters' operationId: listMetricEventsWithOptionalFilters description: '' parameters: [] responses: 500: description: '' content: application/json: schema: type: object example: success: false errors: Unauthenticated. timestamp: '2026-04-18T17:44:14.403243Z' properties: success: type: boolean example: false errors: type: string example: Unauthenticated. timestamp: type: string example: '2026-04-18T17:44:14.403243Z' tags: - Endpoints /api/v1/admin/metrics/backfill: post: summary: 'Backfill metrics for a date range (admin-triggered)' operationId: backfillMetricsForADateRangeadminTriggered description: '' parameters: [] responses: { } tags: - Endpoints requestBody: required: true content: application/json: schema: type: object properties: start: type: string description: 'Must be a valid date.' example: '2026-04-18T17:44:14' nullable: false end: type: string description: 'Must be a valid date. Must be a date after or equal to start.' example: '2107-05-18' nullable: false required: - start - end /api/v1/haha: get: summary: '' operationId: getApiV1Haha description: '' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: status: success updated_count: 0 remaining_orphans: [] message: 'Migration parfaite : 100% des données sont catégorisées.' properties: status: type: string example: success updated_count: type: integer example: 0 remaining_orphans: type: array example: [] message: type: string example: 'Migration parfaite : 100% des données sont catégorisées.' tags: - Endpoints /api/v1/highschools: post: summary: 'Store a newly created highSchool.' operationId: storeANewlyCreatedHighSchool description: '' parameters: [] responses: { } tags: - 'HighSchool Management' requestBody: required: true content: application/json: schema: type: object properties: name: type: string description: 'Must not be greater than 255 characters.' example: vmqeopfuudtdsufvyvddq nullable: false country: type: string description: 'Must not be greater than 100 characters.' example: amniihfqcoynlazghdtqt nullable: false years: type: integer description: 'the amount of years spent there. Must be at least 1. Must not be greater than 30.' example: 16 nullable: false since: type: string description: 'the year he/she began studying at the highSchool,.' example: null nullable: false until: type: string description: 'the last year.' example: null nullable: false academic_information_id: type: string description: 'The id of an existing record in the academic_information table.' example: consequatur nullable: false required: - name - country - years - academic_information_id '/api/v1/highschools/{id}': put: summary: 'Update the specified highSchool.' operationId: updateTheSpecifiedHighSchool description: '' parameters: [] responses: { } tags: - 'HighSchool Management' requestBody: required: false content: application/json: schema: type: object properties: name: type: string description: 'Must not be greater than 255 characters.' example: vmqeopfuudtdsufvyvddq nullable: false country: type: string description: 'Must not be greater than 100 characters.' example: amniihfqcoynlazghdtqt nullable: false years: type: integer description: 'Must be at least 1. Must not be greater than 30.' example: 16 nullable: false since: type: string description: '' example: null nullable: false until: type: string description: '' example: null nullable: false academic_information_id: type: string description: 'The id of an existing record in the academic_information table.' example: null nullable: false delete: summary: 'Remove the specified highSchool.' operationId: removeTheSpecifiedHighSchool description: '' parameters: [] responses: { } tags: - 'HighSchool Management' parameters: - in: path name: id description: 'The ID of the highschool.' example: 1 required: true schema: type: integer /api/v1/majors: get: summary: 'Get all majors' operationId: getAllMajors description: "Returns a paginated list of majors.
\nYou can optionally filter by degree, university or category." parameters: - in: query name: degree description: 'Filter by degree level (Bachelor, Master, PHD).' example: Bachelor required: false schema: type: string description: 'Filter by degree level (Bachelor, Master, PHD).' example: Bachelor nullable: false - in: query name: university_id description: 'Filter by university id.' example: 42 required: false schema: type: integer description: 'Filter by university id.' example: 42 nullable: false - in: query name: major_category_id description: 'Filter by major category id.' example: 5 required: false schema: type: integer description: 'Filter by major category id.' example: 5 nullable: false - in: query name: page description: 'Page number for pagination.' example: 1 required: false schema: type: integer description: 'Page number for pagination.' example: 1 nullable: false responses: 500: description: '' content: application/json: schema: type: object example: success: false errors: Unauthenticated. timestamp: '2026-04-18T17:44:14.208365Z' properties: success: type: boolean example: false errors: type: string example: Unauthenticated. timestamp: type: string example: '2026-04-18T17:44:14.208365Z' tags: - 'Majors Management' '/api/v1/majors/{id}': get: summary: 'Get a single major' operationId: getASingleMajor description: '' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: id: 1 name: 'Computer Science' description: 'Software engineering & algorithms' degree: Bachelor major_category_id: 5 is_applications_open: true minimum_gpa_grades: '3.0 / 75%' budget_range: $8k–12k/year is_scholarship_available: true university: id: 42 name: 'Example University' category: id: 5 name: 'Computer Science & IT' properties: id: type: integer example: 1 name: type: string example: 'Computer Science' description: type: string example: 'Software engineering & algorithms' degree: type: string example: Bachelor major_category_id: type: integer example: 5 is_applications_open: type: boolean example: true minimum_gpa_grades: type: string example: '3.0 / 75%' budget_range: type: string example: $8k–12k/year is_scholarship_available: type: boolean example: true university: type: object properties: id: type: integer example: 42 name: type: string example: 'Example University' category: type: object properties: id: type: integer example: 5 name: type: string example: 'Computer Science & IT' tags: - 'Majors Management' parameters: - in: path name: id description: 'The ID of the major.' example: 6 required: true schema: type: integer /api/v1/admin/majors: post: summary: 'Create a new major' operationId: createANewMajor description: '' parameters: [] responses: 201: description: '' content: application/json: schema: type: object example: id: 11 name: 'Data Science' description: 'Machine learning & big-data analytics' degree: Master major_category_id: 5 is_applications_open: true minimum_gpa_grades: '3.5 / 80%' budget_range: $10k–15k/year is_scholarship_available: false university: id: 5 name: 'Tech University' properties: id: type: integer example: 11 name: type: string example: 'Data Science' description: type: string example: 'Machine learning & big-data analytics' degree: type: string example: Master major_category_id: type: integer example: 5 is_applications_open: type: boolean example: true minimum_gpa_grades: type: string example: '3.5 / 80%' budget_range: type: string example: $10k–15k/year is_scholarship_available: type: boolean example: false university: type: object properties: id: type: integer example: 5 name: type: string example: 'Tech University' 403: description: '' content: application/json: schema: type: object example: message: Forbidden properties: message: type: string example: Forbidden tags: - 'Majors Management' requestBody: required: true content: application/json: schema: type: object properties: name: type: string description: 'Must not be greater than 255 characters.' example: vmqeopfuudtdsufvyvddq nullable: false description: type: string description: '' example: 'Dolores dolorum amet iste laborum eius est dolor.' nullable: true degree: type: string description: '' example: Master nullable: false enum: - Bachelor - Master - PHD major_category_id: type: string description: 'The id of an existing record in the major_categories table.' example: consequatur nullable: false is_applications_open: type: boolean description: '' example: false nullable: true minimum_gpa_grades: type: string description: 'Must not be greater than 50 characters.' example: mqeopfuudtdsufvyvddqa nullable: true budget_range: type: string description: 'Must not be greater than 100 characters.' example: mniihfqcoynlazghdtqtq nullable: true is_scholarship_available: type: boolean description: '' example: true nullable: true university_id: type: string description: 'The id of an existing record in the universities table.' example: consequatur nullable: false application_deadline: type: string description: 'Must be a valid date.' example: '2026-04-18T17:44:14' nullable: true required: - name - degree - major_category_id - university_id '/api/v1/admin/majors/{major_id}': put: summary: 'Update an existing major' operationId: updateAnExistingMajor description: '' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: id: 7 name: 'Mechanical Engineering' description: 'Updated description' degree: Bachelor major_category_id: 7 is_applications_open: false minimum_gpa_grades: '3.2 / 78%' budget_range: $9k–13k/year is_scholarship_available: true university: id: 3 name: 'State University' properties: id: type: integer example: 7 name: type: string example: 'Mechanical Engineering' description: type: string example: 'Updated description' degree: type: string example: Bachelor major_category_id: type: integer example: 7 is_applications_open: type: boolean example: false minimum_gpa_grades: type: string example: '3.2 / 78%' budget_range: type: string example: $9k–13k/year is_scholarship_available: type: boolean example: true university: type: object properties: id: type: integer example: 3 name: type: string example: 'State University' 403: description: '' content: application/json: schema: type: object example: message: Forbidden properties: message: type: string example: Forbidden tags: - 'Majors Management' requestBody: required: false content: application/json: schema: type: object properties: name: type: string description: 'Must not be greater than 255 characters.' example: vmqeopfuudtdsufvyvddq nullable: false description: type: string description: '' example: null nullable: false degree: type: string description: '' example: Bachelor nullable: false enum: - Bachelor - Master - PHD major_category_id: type: string description: 'The id of an existing record in the major_categories table.' example: null nullable: false is_applications_open: type: boolean description: '' example: false nullable: false minimum_gpa_grades: type: string description: 'Must not be greater than 50 characters.' example: amniihfqcoynlazghdtqt nullable: false budget_range: type: string description: 'Must not be greater than 100 characters.' example: qxbajwbpilpmufinllwlo nullable: false is_scholarship_available: type: boolean description: '' example: false nullable: false university_id: type: string description: 'The id of an existing record in the universities table.' example: null nullable: false delete: summary: 'Delete a major' operationId: deleteAMajor description: '' parameters: [] responses: 204: description: '' content: application/json: schema: type: object example: { } properties: { } 403: description: '' content: application/json: schema: type: object example: message: Forbidden properties: message: type: string example: Forbidden tags: - 'Majors Management' parameters: - in: path name: major_id description: 'The ID of the major.' example: 6 required: true schema: type: integer /api/v1/admin/majorCategories: post: summary: 'Store a newly created major category' operationId: storeANewlyCreatedMajorCategory description: '' parameters: [] responses: { } tags: - 'Majors Management' requestBody: required: true content: application/json: schema: type: object properties: name: type: string description: 'Must not be greater than 255 characters.' example: vmqeopfuudtdsufvyvddq nullable: false required: - name get: summary: 'Get a list of all major categories' operationId: getAListOfAllMajorCategories description: '' parameters: [] responses: 500: description: '' content: application/json: schema: type: object example: success: false errors: Unauthenticated. timestamp: '2026-04-18T17:44:14.517820Z' properties: success: type: boolean example: false errors: type: string example: Unauthenticated. timestamp: type: string example: '2026-04-18T17:44:14.517820Z' tags: - 'Majors Management' '/api/v1/admin/majorCategories/{majorCategory_id}': put: summary: 'Update the name and slug of a major category' operationId: updateTheNameAndSlugOfAMajorCategory description: '' parameters: [] responses: { } tags: - 'Majors Management' requestBody: required: false content: application/json: schema: type: object properties: name: type: string description: '' example: null nullable: false get: summary: 'Get majors for a specific category' operationId: getMajorsForASpecificCategory description: '' parameters: [] responses: 500: description: '' content: application/json: schema: type: object example: success: false errors: Unauthenticated. timestamp: '2026-04-18T17:44:14.521814Z' properties: success: type: boolean example: false errors: type: string example: Unauthenticated. timestamp: type: string example: '2026-04-18T17:44:14.521814Z' tags: - 'Majors Management' parameters: - in: path name: majorCategory_id description: 'The ID of the majorCategory.' example: 1 required: true schema: type: integer /api/v1/my_suggestions: get: summary: 'List of all matching suggestions for a user' operationId: listOfAllMatchingSuggestionsForAUser description: '' parameters: [] responses: 500: description: '' content: application/json: schema: type: object example: success: false errors: Unauthenticated. timestamp: '2026-04-18T17:44:14.223703Z' properties: success: type: boolean example: false errors: type: string example: Unauthenticated. timestamp: type: string example: '2026-04-18T17:44:14.223703Z' tags: - 'Matching Suggestions' '/api/v1/my_suggestions/{id}': get: summary: 'Display one matching suggestion' operationId: displayOneMatchingSuggestion description: '' parameters: [] responses: 500: description: '' content: application/json: schema: type: object example: success: false errors: Unauthenticated. timestamp: '2026-04-18T17:44:14.227000Z' properties: success: type: boolean example: false errors: type: string example: Unauthenticated. timestamp: type: string example: '2026-04-18T17:44:14.227000Z' tags: - 'Matching Suggestions' parameters: - in: path name: id description: 'The ID of the my suggestion.' example: consequatur required: true schema: type: string /api/v1/admin/matchingSuggestions: post: summary: 'Store a new matching suggestion' operationId: storeANewMatchingSuggestion description: '' parameters: [] responses: { } tags: - 'Matching Suggestions' requestBody: required: true content: application/json: schema: type: object properties: suggested_user_id: type: integer description: 'The id of an existing record in the users table.' example: 17 nullable: false match_percentage: type: number description: 'Must be at least 0. Must not be greater than 100.' example: 13 nullable: false reason: type: string description: 'Must not be greater than 255 characters.' example: qeopfuudtdsufvyvddqam nullable: true major_id: type: integer description: 'The id of an existing record in the majors table.' example: 17 nullable: false required: - suggested_user_id - match_percentage - major_id '/api/v1/admin/matchingSuggestions/{id}': put: summary: 'Update one matching suggestion.' operationId: updateOneMatchingSuggestion description: '' parameters: [] responses: { } tags: - 'Matching Suggestions' requestBody: required: true content: application/json: schema: type: object properties: suggested_user_id: type: integer description: 'The id of an existing record in the users table.' example: 17 nullable: false match_percentage: type: number description: 'Must be at least 0. Must not be greater than 100.' example: 13 nullable: false reason: type: string description: 'Must not be greater than 255 characters.' example: qeopfuudtdsufvyvddqam nullable: true major_id: type: integer description: 'The id of an existing record in the majors table.' example: 17 nullable: false required: - suggested_user_id - match_percentage - major_id delete: summary: 'Delete one matching suggestion.' operationId: deleteOneMatchingSuggestion description: '' parameters: [] responses: { } tags: - 'Matching Suggestions' parameters: - in: path name: id description: 'The ID of the matchingSuggestion.' example: consequatur required: true schema: type: string /api/v1/user: get: summary: 'Get the user by the token' operationId: getTheUserByTheToken description: '' parameters: [] responses: 500: description: '' content: application/json: schema: type: object example: success: false errors: Unauthenticated. timestamp: '2026-04-18T17:44:13.736075Z' properties: success: type: boolean example: false errors: type: string example: Unauthenticated. timestamp: type: string example: '2026-04-18T17:44:13.736075Z' tags: - Miscellaneous /api/v1/health: get: summary: 'Check if the api is online' operationId: checkIfTheApiIsOnline description: '' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: status: OK properties: status: type: string example: OK tags: - Miscellaneous security: [] /api/v1/payment_proofs: get: summary: 'List payment proofs' operationId: listPaymentProofs description: '' parameters: - in: query name: status description: 'Filter by status (pending, approved, rejected)' example: pending required: false schema: type: string description: 'Filter by status (pending, approved, rejected)' example: pending nullable: false - in: query name: per_page description: 'Items per page' example: 15 required: false schema: type: integer description: 'Items per page' example: 15 nullable: false responses: 200: description: 'List of payment proofs retrieved successfully' content: application/json: schema: type: object nullable: true tags: - 'Payment Management' post: summary: 'Create payment proof' operationId: createPaymentProof description: '' parameters: [] responses: 201: description: 'Payment proof created successfully' content: application/json: schema: type: object nullable: true 403: description: 'Unauthorized - can only create proof for own payments' content: application/json: schema: type: object nullable: true 404: description: 'Payment not found' content: application/json: schema: type: object nullable: true tags: - 'Payment Management' requestBody: required: true content: multipart/form-data: schema: type: object properties: image: type: string format: binary description: 'Payment proof image (jpg, png, pdf)' nullable: false receipt_number: type: string description: 'Receipt number' example: REC-2024-001 nullable: false payer_name: type: string description: 'Name of the payer' example: 'John Doe' nullable: false amount: type: numeric description: 'Payment amount' example: 150.0 nullable: false payment_date: type: date description: 'Date of payment (Y-m-d)' example: '2024-01-15' nullable: false payment_method: type: string description: 'Payment method used' example: bank_transfer nullable: false payment_id: type: string description: "Payment ID (must be user's own payment)" example: 550e8400-e29b-41d4-a716-446655440000 nullable: false required: - image - receipt_number - payer_name - amount - payment_date - payment_method - payment_id '/api/v1/payment_proofs/{id}': get: summary: 'Get payment proof details' operationId: getPaymentProofDetails description: '' parameters: [] responses: 200: description: 'Payment proof retrieved successfully' content: application/json: schema: type: object nullable: true 403: description: 'Unauthorized to view this payment proof' content: application/json: schema: type: object nullable: true 404: description: 'Payment proof not found' content: application/json: schema: type: object nullable: true tags: - 'Payment Management' put: summary: 'Update payment proof' operationId: updatePaymentProof description: '' parameters: [] responses: 200: description: 'Payment proof updated successfully' content: application/json: schema: type: object nullable: true 403: description: Unauthorized content: application/json: schema: type: object nullable: true 404: description: 'Payment proof not found' content: application/json: schema: type: object nullable: true tags: - 'Payment Management' requestBody: required: false content: application/json: schema: type: object properties: status: type: string description: 'Status (pending, approved, rejected)' example: approved nullable: false admin_comment: type: string description: 'Admin comment on the payment proof' example: 'Payment verified successfully' nullable: false parameters: - in: path name: id description: 'The ID of the payment proof.' example: consequatur required: true schema: type: string '/api/v1/payment_proofs/{paymentProofId}/verify': post: summary: 'Admin verify payment proof' operationId: adminVerifyPaymentProof description: "On approval: Verifies proof file, auto-detects price type from payment amount,\napproves proof, approves payment, approves credit purchase, adds credits, records transaction.\nOn rejection: Requires comment explaining why, rejects proof/payment/credit purchase, records rejection." parameters: [] responses: 200: description: 'Payment proof processed successfully' content: application/json: schema: type: object nullable: true 400: description: 'Invalid action or missing required fields' content: application/json: schema: type: object nullable: true 403: description: 'Admin access required' content: application/json: schema: type: object nullable: true 404: description: 'Payment proof not found' content: application/json: schema: type: object nullable: true 422: description: 'Payment proof file verification failed' content: application/json: schema: type: object nullable: true tags: - 'Payment Management' requestBody: required: true content: application/json: schema: type: object properties: action: type: string description: 'Verification action: approve or reject' example: approve nullable: false admin_comment: type: string description: 'Required rejection reason when rejecting, optional note when approving' example: 'Payment proof unclear' nullable: false required: - action parameters: - in: path name: paymentProofId description: '' example: consequatur required: true schema: type: string /api/v1/payments: get: summary: 'List payments' operationId: listPayments description: '' parameters: - in: query name: status description: 'Filter by status (pending, paid, failed, cancelled, refunded)' example: paid required: false schema: type: string description: 'Filter by status (pending, paid, failed, cancelled, refunded)' example: paid nullable: false - in: query name: provider description: 'Filter by payment provider' example: stripe required: false schema: type: string description: 'Filter by payment provider' example: stripe nullable: false - in: query name: page description: 'Page number' example: 1 required: false schema: type: integer description: 'Page number' example: 1 nullable: false - in: query name: per_page description: 'Items per page' example: 15 required: false schema: type: integer description: 'Items per page' example: 15 nullable: false responses: 200: description: 'List of payments retrieved successfully' content: application/json: schema: type: object nullable: true tags: - 'Payment Management' '/api/v1/payments/{paymentId}': get: summary: 'Get payment details' operationId: getPaymentDetails description: '' parameters: [] responses: 200: description: 'Payment retrieved successfully' content: application/json: schema: type: object nullable: true 403: description: 'Unauthorized to view this payment' content: application/json: schema: type: object nullable: true 404: description: 'Payment not found' content: application/json: schema: type: object nullable: true tags: - 'Payment Management' parameters: - in: path name: paymentId description: '' example: consequatur required: true schema: type: string /api/v1/pi: get: summary: "Get the current authenticated user's personal information." operationId: getTheCurrentAuthenticatedUsersPersonalInformation description: '' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: id: 1 date_of_birth: '1995-06-01' gender: Female nationality: Kenya user_id: 5 properties: id: type: integer example: 1 date_of_birth: type: string example: '1995-06-01' gender: type: string example: Female nationality: type: string example: Kenya user_id: type: integer example: 5 404: description: '' content: application/json: schema: type: object example: message: 'Personal information not found' personal_information: null properties: message: type: string example: 'Personal information not found' personal_information: type: string example: null tags: - 'Personal Information' '/api/v1/pi/{user}': post: summary: 'Store a newly created Personal info.' operationId: storeANewlyCreatedPersonalInfo description: '' parameters: [] responses: { } tags: - 'Personal Information' requestBody: required: true content: application/json: schema: type: object properties: date_of_birth: type: string description: 'Must be a valid date.' example: '2026-04-18T17:44:13' nullable: false gender: type: string description: '' example: consequatur nullable: false nationality: type: string description: 'Must be at least 4 characters.' example: mqeopfuudtdsufvyvddqamniihfqcoynlazghdtqtqxbajwbpilpmufinllwloauydlsmsjury nullable: false user_id: type: string description: 'The id of an existing record in the users table.' example: consequatur nullable: false required: - date_of_birth - gender - nationality - user_id parameters: - in: path name: user description: '' example: consequatur required: true schema: type: string '/api/v1/pi/{id}': put: summary: 'Update the specified personal information.' operationId: updateTheSpecifiedPersonalInformation description: '' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: message: 'Personal Information updated successfully' personal_information: id: 1 date_of_birth: '1995-06-01' gender: Female nationality: Kenya properties: message: type: string example: 'Personal Information updated successfully' personal_information: type: object properties: id: type: integer example: 1 date_of_birth: type: string example: '1995-06-01' gender: type: string example: Female nationality: type: string example: Kenya tags: - 'Personal Information' requestBody: required: false content: application/json: schema: type: object properties: date_of_birth: type: string description: 'Must be a valid date.' example: '2026-04-18T17:44:13' nullable: false gender: type: string description: '' example: consequatur nullable: false nationality: type: string description: 'Must be at least 4 characters.' example: mqeopfuudtdsufvyvddqamniihfqcoynlazghdtqtqxbajwbpilpmufinllwloauydlsmsjury nullable: false parameters: - in: path name: id description: 'The ID of the pi.' example: consequatur required: true schema: type: string /api/v1/preferences: get: summary: "Get the current authenticated user's preferences." operationId: getTheCurrentAuthenticatedUsersPreferences description: '' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: id: 1 intended_field_of_study: 'Computer Science' min_budget: 5000 max_budget: 20000 currency: USD scholarship_interest: true study_destinations: [] properties: id: type: integer example: 1 intended_field_of_study: type: string example: 'Computer Science' min_budget: type: integer example: 5000 max_budget: type: integer example: 20000 currency: type: string example: USD scholarship_interest: type: boolean example: true study_destinations: type: array example: [] 404: description: '' content: application/json: schema: type: object example: message: 'Preferences not found' preferences: null properties: message: type: string example: 'Preferences not found' preferences: type: string example: null tags: - 'Preferences and goals' post: summary: 'Store a newly created preference.' operationId: storeANewlyCreatedPreference description: '' parameters: [] responses: { } tags: - 'Preferences and goals' requestBody: required: true content: application/json: schema: type: object properties: intended_field_of_study: type: string description: '' example: consequatur nullable: false min_budget: type: number description: 'the least/minimum amount of money he/she can afford.' example: 11613.31890586 nullable: false max_budget: type: number description: 'the maximum he/she can pay for school.' example: 11613.31890586 nullable: false currency: type: string description: 'Must be at least 3 characters.' example: opfuudtdsufvyvddqamniihfqcoynlazghdtqtqxbajwbpilpmufinllwloauydlsmsjuryvoj nullable: false user_id: type: string description: '' example: consequatur nullable: false scholarship_interest: type: string description: '' example: null nullable: false study_destination_ids: type: object description: 'the school study destination are to be created by the admins, provide with an id or an array of ids.' example: null nullable: false properties: { } required: - intended_field_of_study - min_budget - currency - user_id '/api/v1/preferences/{id}': put: summary: 'Update the specified preference.' operationId: updateTheSpecifiedPreference description: '' parameters: [] responses: { } tags: - 'Preferences and goals' requestBody: required: false content: application/json: schema: type: object properties: intended_field_of_study: type: string description: '' example: null nullable: false min_budget: type: number description: '' example: 11613.31890586 nullable: false max_budget: type: number description: '' example: 11613.31890586 nullable: false currency: type: string description: 'Must be at least 3 characters.' example: opfuudtdsufvyvddqamniihfqcoynlazghdtqtqxbajwbpilpmufinllwloauydlsmsjuryvoj nullable: false scholarship_interest: type: string description: '' example: null nullable: false study_destination_ids: type: object description: '' example: null nullable: false properties: { } parameters: - in: path name: id description: 'The ID of the preference.' example: consequatur required: true schema: type: string /api/v1/special_needs: post: summary: 'Store a newly created special need.' operationId: storeANewlyCreatedSpecialNeed description: '' parameters: [] responses: { } tags: - 'Special Needs Management' requestBody: required: true content: application/json: schema: type: object properties: needs: type: object description: 'the needs here is to be an array of needs. come up with a list of needs or let the user enter one Exemple: "needs": {"visa_support": "yes","disabilities": "eyes problems" }.' example: [] nullable: false properties: { } required: - needs '/api/v1/special_needs/{id}': put: summary: 'Update the specified special needs of a student.' operationId: updateTheSpecifiedSpecialNeedsOfAStudent description: '' parameters: [] responses: { } tags: - 'Special Needs Management' requestBody: required: false content: application/json: schema: type: object properties: needs: type: object description: 'the same as the store endpoints, but here the array that you send will replace the old one, it''s doesn''t updating only one but the whole object of needs with the one you provide here Exemple: "needs": {"visa_support": "yes","disabilities": "eyes problems" }.' example: null nullable: false properties: { } delete: summary: 'Remove the specified resource from storage.' operationId: removeTheSpecifiedResourceFromStorage description: '' parameters: [] responses: { } tags: - 'Special Needs Management' parameters: - in: path name: id description: 'The ID of the special need.' example: 1 required: true schema: type: integer /api/v1/my_staff: get: summary: 'Get the staff member assigned to a student' operationId: getTheStaffMemberAssignedToAStudent description: "Student can view their own staff member, admins can view any student's staff member.\nReturns paginated list of staff members assigned to a student." parameters: - in: query name: student_id description: 'The ID of the student (if not provided, uses authenticated user)' example: 17 required: false schema: type: integer description: 'The ID of the student (if not provided, uses authenticated user)' example: 17 nullable: false responses: 200: description: '' content: text/plain: schema: type: string example: '{"data": [{"id": 5, "name": "Staff Member", "email": "staff@example.com", ...}], "links": {...}, "meta": {"total": 1, "per_page": 15}}' 403: description: '' content: application/json: schema: type: object example: message: 'You can only view your own assigned staff' properties: message: type: string example: 'You can only view your own assigned staff' 404: description: '' content: application/json: schema: type: object example: message: 'Student not found' properties: message: type: string example: 'Student not found' tags: - 'Staff Management' '/api/v1/admin/staff/{id}': put: summary: 'Update a staff member' operationId: updateAStaffMember description: 'Update user-related information for a staff member. Password and role cannot be updated through this endpoint.' parameters: [] responses: 200: description: '' content: text/plain: schema: type: string example: '{"data": {...}, "message": "Staff member updated successfully"}' tags: - 'Staff Management' requestBody: required: false content: application/json: schema: type: object properties: name: type: string description: 'Must not be greater than 255 characters.' example: vmqeopfuudtdsufvyvddq nullable: true email: type: string description: 'Must be a valid email address. Must not be greater than 255 characters.' example: kunde.eloisa@example.com nullable: true profile_picture: type: string description: '' example: consequatur nullable: true first_time_login: type: boolean description: '' example: false nullable: true is_verified: type: boolean description: '' example: false nullable: true parameters: - in: path name: id description: 'The ID of the staff.' example: 1 required: true schema: type: integer /api/v1/admin/staff/assign-student: post: summary: 'Assign a student to a staff member' operationId: assignAStudentToAStaffMember description: "Only admins can assign students to staff members.\nA staff member cannot be a student (role_id must not be 1)." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: message: 'Student assigned to staff member successfully' staff_id: 5 student_id: 3 properties: message: type: string example: 'Student assigned to staff member successfully' staff_id: type: integer example: 5 student_id: type: integer example: 3 403: description: '' content: application/json: schema: type: object example: message: 'Only admins can assign students to staff' properties: message: type: string example: 'Only admins can assign students to staff' 404: description: '' content: application/json: schema: type: object example: message: 'Staff or student not found' properties: message: type: string example: 'Staff or student not found' 422: description: '' content: text/plain: schema: type: string example: '{"message": "User is not a staff member" or "User is not a student" or "Student is already assigned to this staff"}' tags: - 'Staff Management' requestBody: required: true content: application/json: schema: type: object properties: staff_id: type: integer description: 'The ID of the staff member user' example: 17 nullable: false student_id: type: integer description: 'The ID of the student user' example: 17 nullable: false required: - staff_id - student_id /api/v1/admin/staff/remove-student: post: summary: 'Remove a student from a staff member' operationId: removeAStudentFromAStaffMember description: 'Only admins can remove student assignments from staff members.' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: message: 'Student removed from staff member successfully' staff_id: 5 student_id: 3 properties: message: type: string example: 'Student removed from staff member successfully' staff_id: type: integer example: 5 student_id: type: integer example: 3 403: description: '' content: application/json: schema: type: object example: message: 'Only admins can remove student assignments' properties: message: type: string example: 'Only admins can remove student assignments' 404: description: '' content: text/plain: schema: type: string example: '{"message": "Staff or student not found" or "Assignment not found"}' tags: - 'Staff Management' requestBody: required: true content: application/json: schema: type: object properties: staff_id: type: integer description: 'The ID of the staff member user' example: 17 nullable: false student_id: type: integer description: 'The ID of the student user' example: 17 nullable: false required: - staff_id - student_id /api/v1/admin/staff/list: get: summary: 'List all staff members' operationId: listAllStaffMembers description: "Get a paginated list of all staff members in the system.\nResults are paginated with 15 staff members per page." parameters: [] responses: 200: description: '' content: text/plain: schema: type: string example: '{"data": [{"id": 5, "name": "Staff Member", "email": "staff@example.com", ...}], "links": {...}, "meta": {"total": 5, "per_page": 15}}' tags: - 'Staff Management' /api/v1/admin/staff/with-counts: get: summary: 'Get all staff members with their assigned students count' operationId: getAllStaffMembersWithTheirAssignedStudentsCount description: 'Retrieve a paginated list of all staff members in the system with the count of students assigned to each.' parameters: [] responses: 200: description: '' content: text/plain: schema: type: string example: '{"data": [{"user_id": 5, "name": "Staff Member", "email": "staff@example.com", "assigned_students_count": 3}, ...], "links": {...}, "meta": {"total": 5, "per_page": 10}}' tags: - 'Staff Management' /api/v1/admin/staff/unassigned/count: get: summary: 'Get count of unassigned students' operationId: getCountOfUnassignedStudents description: 'Retrieve the total count of students who are not assigned to any staff member.' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: data: unassigned_count: 5 properties: data: type: object properties: unassigned_count: type: integer example: 5 tags: - 'Staff Management' /api/v1/admin/staff/unassigned/students: get: summary: 'Get all unassigned students with count' operationId: getAllUnassignedStudentsWithCount description: 'Retrieve all students who are not assigned to any staff member, along with the total count.' parameters: [] responses: 200: description: '' content: text/plain: schema: type: string example: '{"data": [...], "links": {...}, "meta": {...}}' tags: - 'Staff Management' /api/v1/admin/staff/students: get: summary: 'Get all students assigned to a staff member' operationId: getAllStudentsAssignedToAStaffMember description: "Staff member can view their own students, admins can view any staff member's students.\nResults are paginated with 15 students per page." parameters: - in: query name: staff_id description: 'The ID of the staff member (if not provided, uses authenticated staff user)' example: 17 required: false schema: type: integer description: 'The ID of the staff member (if not provided, uses authenticated staff user)' example: 17 nullable: false responses: 200: description: '' content: text/plain: schema: type: string example: '{"data": [{"id": 3, "name": "John Doe", "email": "john@example.com", ...}], "links": {...}, "meta": {"total": 1, "per_page": 15}}' 403: description: '' content: application/json: schema: type: object example: message: 'You can only view your own assigned students' properties: message: type: string example: 'You can only view your own assigned students' 404: description: '' content: application/json: schema: type: object example: message: 'Staff member not found' properties: message: type: string example: 'Staff member not found' tags: - 'Staff Management' '/api/v1/admin/staff/{staff_id}': get: summary: 'Get a staff member with the count of assigned students' operationId: getAStaffMemberWithTheCountOfAssignedStudents description: 'Retrieve a specific staff member and include the total number of students assigned to them.' parameters: [] responses: 200: description: '' content: text/plain: schema: type: string example: '{"data": {..., "assigned_students_count": 3}}' 404: description: '' content: application/json: schema: type: object example: message: 'Staff member not found' properties: message: type: string example: 'Staff member not found' 422: description: '' content: application/json: schema: type: object example: message: 'User is not a staff member' properties: message: type: string example: 'User is not a staff member' tags: - 'Staff Management' parameters: - in: path name: staff_id description: 'The ID of the staff.' example: 1 required: true schema: type: integer /api/v1/admin/students/staff: get: summary: 'Get the staff member assigned to a student' operationId: getTheStaffMemberAssignedToAStudent description: "Student can view their own staff member, admins can view any student's staff member.\nReturns paginated list of staff members assigned to a student." parameters: - in: query name: student_id description: 'The ID of the student (if not provided, uses authenticated user)' example: 17 required: false schema: type: integer description: 'The ID of the student (if not provided, uses authenticated user)' example: 17 nullable: false responses: 200: description: '' content: text/plain: schema: type: string example: '{"data": [{"id": 5, "name": "Staff Member", "email": "staff@example.com", ...}], "links": {...}, "meta": {"total": 1, "per_page": 15}}' 403: description: '' content: application/json: schema: type: object example: message: 'You can only view your own assigned staff' properties: message: type: string example: 'You can only view your own assigned staff' 404: description: '' content: application/json: schema: type: object example: message: 'Student not found' properties: message: type: string example: 'Student not found' tags: - 'Staff Management' /api/v1/conversations: get: summary: 'List conversations.' operationId: listConversations description: "* Get a flat list of all conversations relevant to the user.\n- Admins: All conversations in the system.\n- Staff: Conversations they are part of OR involving their assigned students.\n- Students: Only conversations where they are a participant." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true data: - id: 1 subject: Inquiry initiator: id: 1 name: 'User Name' profile_picture: null role_id: 1 counter_part: id: 2 name: 'Staff Name' profile_picture: null role_id: 2 last_message: body: Hello! sender_id: 1 read_at: null created_at: '2026-03-27 12:00:00' updated_at: '2026-03-27 12:00:00' properties: success: type: boolean example: true data: type: array example: - id: 1 subject: Inquiry initiator: id: 1 name: 'User Name' profile_picture: null role_id: 1 counter_part: id: 2 name: 'Staff Name' profile_picture: null role_id: 2 last_message: body: Hello! sender_id: 1 read_at: null created_at: '2026-03-27 12:00:00' updated_at: '2026-03-27 12:00:00' items: type: object properties: id: type: integer example: 1 subject: type: string example: Inquiry initiator: type: object properties: id: type: integer example: 1 name: type: string example: 'User Name' profile_picture: type: string example: null role_id: type: integer example: 1 counter_part: type: object properties: id: type: integer example: 2 name: type: string example: 'Staff Name' profile_picture: type: string example: null role_id: type: integer example: 2 last_message: type: object properties: body: type: string example: Hello! sender_id: type: integer example: 1 read_at: type: string example: null created_at: type: string example: '2026-03-27 12:00:00' updated_at: type: string example: '2026-03-27 12:00:00' tags: - 'Student Conversations' post: summary: 'Start/Get conversation.' operationId: startGetConversation description: "* Initiates a 1-on-1 thread. If a conversation already exists between the users, it appends the message to the existing thread.\n* @bodyParam counter_part_id int optional The ID of the user to talk to (Required for Admin/Staff). Example: 5" parameters: [] responses: 201: description: '' content: application/json: schema: type: object example: success: true data: message: 'Conversation created' conversation: id: 1 initiator_id: 1 counter_part_id: 5 subject: 'Academic Support' properties: success: type: boolean example: true data: type: object properties: message: type: string example: 'Conversation created' conversation: type: object properties: id: type: integer example: 1 initiator_id: type: integer example: 1 counter_part_id: type: integer example: 5 subject: type: string example: 'Academic Support' 403: description: '' content: application/json: schema: type: object example: success: false message: 'You cannot start a conversation until a staff member is assigned to you' properties: success: type: boolean example: false message: type: string example: 'You cannot start a conversation until a staff member is assigned to you' tags: - 'Student Conversations' requestBody: required: true content: application/json: schema: type: object properties: subject: type: string description: 'optional The topic of conversation.' example: 'Academic Support' nullable: true body: type: string description: 'The first message body.' example: 'Hello, I need help with my application.' nullable: false required: - body '/api/v1/conversations/{id}': get: summary: 'View conversation.' operationId: viewConversation description: '* Retrieves a single conversation including the full flat list of messages.' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true data: conversation: id: 1 initiator_id: 1 counter_part_id: 5 subject: 'Academic Support' messages: - id: 10 body: Hello! sender_id: 1 receiver_id: 5 created_at: ... properties: success: type: boolean example: true data: type: object properties: conversation: type: object properties: id: type: integer example: 1 initiator_id: type: integer example: 1 counter_part_id: type: integer example: 5 subject: type: string example: 'Academic Support' messages: type: array example: - id: 10 body: Hello! sender_id: 1 receiver_id: 5 created_at: ... items: type: object properties: id: type: integer example: 10 body: type: string example: Hello! sender_id: type: integer example: 1 receiver_id: type: integer example: 5 created_at: type: string example: ... tags: - 'Student Conversations' parameters: - in: path name: id description: 'The ID of the conversation.' example: 019d914e-f748-72b7-aa90-4d20ce91737a required: true schema: type: string - in: path name: conversation description: 'The ID of the conversation.' example: '1' required: true schema: type: string '/api/v1/conversations/{conversation_id}/messages': post: summary: 'Reply to conversation.' operationId: replyToConversation description: "* Adds a new message to an existing conversation and notifies the recipient.\n* @urlParam conversation required The ID of the conversation. Example: 1" parameters: [] responses: { } tags: - 'Student Conversations' requestBody: required: true content: application/json: schema: type: object properties: body: type: string description: 'The message body.' example: "Noted, thank you.\n* @response 200 {\n\"success\": true,\n\"message\": \"Message posted\",\n\"data\": {\n\"id\": 11,\n\"body\": \"Noted, thank you.\",\n\"sender_id\": 5,\n\"receiver_id\": 1,\n\"sender\": {\"id\": 5, \"name\": \"Staff Name\"}\n}\n}" nullable: false required: - body parameters: - in: path name: conversation_id description: 'The ID of the conversation.' example: 019d914e-f748-72b7-aa90-4d20ce91737a required: true schema: type: string /api/v1/languages: post: summary: 'Store a newly created language.' operationId: storeANewlyCreatedLanguage description: '' parameters: [] responses: { } tags: - 'Student Language' requestBody: required: true content: application/json: schema: type: object properties: name: type: string description: 'Must be at least 4 characters.' example: vmqeopfuudtdsufvyvddqamniihfqcoynlazghdtqtqxbajwbpilpmufinllwloauydlsmsjur nullable: false personal_information_id: type: integer description: '' example: 17 nullable: false required: - name - personal_information_id '/api/v1/languages/{id}': put: summary: 'Update the student language.' operationId: updateTheStudentLanguage description: '' parameters: [] responses: { } tags: - 'Student Language' requestBody: required: false content: application/json: schema: type: object properties: name: type: string description: 'Must be at least 4 characters.' example: vmqeopfuudtdsufvyvddqamniihfqcoynlazghdtqtqxbajwbpilpmufinllwloauydlsmsjur nullable: false delete: summary: 'Remove the specified language.' operationId: removeTheSpecifiedLanguage description: '' parameters: [] responses: { } tags: - 'Student Language' parameters: - in: path name: id description: 'The ID of the language.' example: 1 required: true schema: type: integer '/api/v1/application_packet/{user_id}': get: summary: 'Endpoint to get the data for the packet used for his application' operationId: endpointToGetTheDataForThePacketUsedForHisApplication description: '' parameters: [] responses: 500: description: '' content: application/json: schema: type: object example: success: false errors: Unauthenticated. timestamp: '2026-04-18T17:44:13.923430Z' properties: success: type: boolean example: false errors: type: string example: Unauthenticated. timestamp: type: string example: '2026-04-18T17:44:13.923430Z' tags: - 'Student Management' parameters: - in: path name: user_id description: 'The ID of the user.' example: 1 required: true schema: type: integer '/api/v1/students/{user_id}': get: summary: 'Endpoint to get the data for the student.' operationId: endpointToGetTheDataForTheStudent description: '' parameters: [] responses: 500: description: '' content: application/json: schema: type: object example: success: false errors: Unauthenticated. timestamp: '2026-04-18T17:44:14.024219Z' properties: success: type: boolean example: false errors: type: string example: Unauthenticated. timestamp: type: string example: '2026-04-18T17:44:14.024219Z' tags: - 'Student Management' parameters: - in: path name: user_id description: 'The ID of the user.' example: 1 required: true schema: type: integer /api/v1/matches: get: summary: 'Get the matching for the authenticated student.' operationId: getTheMatchingForTheAuthenticatedStudent description: "Returns a ranked list of recommended majors for the authenticated student.\nEach item contains: type (\"major\"), score (0-100), a breakdown of contributing factors, and the related `major` and its `university` resource." parameters: - in: query name: limit description: 'Optional. The maximum number of recommendations to return.' example: 20 required: false schema: type: integer description: 'Optional. The maximum number of recommendations to return.' example: 20 nullable: false responses: 200: description: '' content: application/json: schema: type: object example: data: - type: major major: id: 1 name: 'Computer Science' is_applications_open: true university: id: 5 name: 'Example University' score: 87.2 breakdown: field: 90 budget: 70 scholarship: 100 destination: 100 academic: 80 language: 100 category: 'Strong Match' properties: data: type: array example: - type: major major: id: 1 name: 'Computer Science' is_applications_open: true university: id: 5 name: 'Example University' score: 87.2 breakdown: field: 90 budget: 70 scholarship: 100 destination: 100 academic: 80 language: 100 category: 'Strong Match' items: type: object properties: type: type: string example: major major: type: object properties: id: type: integer example: 1 name: type: string example: 'Computer Science' is_applications_open: type: boolean example: true university: type: object properties: id: type: integer example: 5 name: type: string example: 'Example University' score: type: number example: 87.2 breakdown: type: object properties: field: type: integer example: 90 budget: type: integer example: 70 scholarship: type: integer example: 100 destination: type: integer example: 100 academic: type: integer example: 80 language: type: integer example: 100 category: type: string example: 'Strong Match' tags: - 'Student Management' /api/v1/admin/students: get: summary: 'Show the list of the students on the platform' operationId: showTheListOfTheStudentsOnThePlatform description: '' parameters: [] responses: 500: description: '' content: application/json: schema: type: object example: success: false errors: Unauthenticated. timestamp: '2026-04-18T17:44:14.311387Z' properties: success: type: boolean example: false errors: type: string example: Unauthenticated. timestamp: type: string example: '2026-04-18T17:44:14.311387Z' tags: - 'Student Management' /api/v1/study_destinations: get: summary: 'Display a listing of all the study destinations.' operationId: displayAListingOfAllTheStudyDestinations description: '' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true data: - id: 209 region: Africa regionTier: emerging - id: 210 region: Asia regionTier: emerging - id: 211 region: Europe regionTier: global - id: 212 region: USA regionTier: global - id: 213 region: UK regionTier: global - id: 214 region: UAE regionTier: global timestamp: '2026-04-18T17:44:13.794147Z' properties: success: type: boolean example: true data: type: array example: - id: 209 region: Africa regionTier: emerging - id: 210 region: Asia regionTier: emerging - id: 211 region: Europe regionTier: global - id: 212 region: USA regionTier: global - id: 213 region: UK regionTier: global - id: 214 region: UAE regionTier: global items: type: object properties: id: type: integer example: 209 region: type: string example: Africa regionTier: type: string example: emerging timestamp: type: string example: '2026-04-18T17:44:13.794147Z' tags: - 'Study destination' /api/v1/admin/study_destinations: post: summary: 'Store a newly created study destination.' operationId: storeANewlyCreatedStudyDestination description: '' parameters: [] responses: { } tags: - 'Study destination' requestBody: required: true content: application/json: schema: type: object properties: region: type: string description: '' example: consequatur nullable: false region_tier: type: string description: '' example: consequatur nullable: false required: - region - region_tier '/api/v1/admin/study_destinations/{id}': put: summary: 'Update the specified study destination.' operationId: updateTheSpecifiedStudyDestination description: '' parameters: [] responses: { } tags: - 'Study destination' requestBody: required: false content: application/json: schema: type: object properties: region: type: string description: '' example: null nullable: false region_tier: type: string description: '' example: null nullable: false parameters: - in: path name: id description: 'The ID of the study destination.' example: 209 required: true schema: type: integer /api/v1/universities: get: summary: 'Display a listing of all universities.' operationId: displayAListingOfAllUniversities description: '' parameters: - in: query name: country description: 'Filter by country name.' example: Canada required: false schema: type: string description: 'Filter by country name.' example: Canada nullable: false - in: query name: region description: 'Filter by region.' example: 'North America' required: false schema: type: string description: 'Filter by region.' example: 'North America' nullable: false - in: query name: is_scholarship_available description: 'Filter by scholarship availability (deprecated, use scholarship_availability).' example: true required: false schema: type: boolean description: 'Filter by scholarship availability (deprecated, use scholarship_availability).' example: true nullable: false - in: query name: scholarship_availability description: 'Filter by specific scholarship level. One of: high, moderate, very high, low, very high (full), very high (need blind), very high (stipendium).' example: 'very high' required: false schema: type: string description: 'Filter by specific scholarship level. One of: high, moderate, very high, low, very high (full), very high (need blind), very high (stipendium).' example: 'very high' nullable: false - in: query name: affordability_tier description: 'Filter by tier (e.g., Budget, Mid-Range).' example: Mid-Range required: false schema: type: string description: 'Filter by tier (e.g., Budget, Mid-Range).' example: Mid-Range nullable: false - in: query name: limit description: 'Number of records per page/request.' example: 15 required: false schema: type: integer description: 'Number of records per page/request.' example: 15 nullable: false - in: query name: paginated description: 'Whether to return paginated results. Default: false.' example: true required: false schema: type: boolean description: 'Whether to return paginated results. Default: false.' example: true nullable: false responses: 500: description: '' content: application/json: schema: type: object example: success: false errors: Unauthenticated. timestamp: '2026-04-18T17:44:14.052427Z' properties: success: type: boolean example: false errors: type: string example: Unauthenticated. timestamp: type: string example: '2026-04-18T17:44:14.052427Z' tags: - Universities post: summary: 'Store a newly created university.' operationId: storeANewlyCreatedUniversity description: '' parameters: [] responses: { } tags: - Universities requestBody: required: true content: multipart/form-data: schema: type: object properties: name: type: string description: 'The name of the university.' example: 'University of Toronto' nullable: false address: type: string description: 'Full physical address.' example: "27 King's College Cir, Toronto, ON." nullable: false logo: type: string format: binary description: 'nullable University logo image (max 2MB).' nullable: true country: type: string description: 'Country name.' example: Canada nullable: false admission_rate: type: number description: 'Admission percentage (0-100).' example: 43.5 nullable: false is_scholarship_available: type: boolean description: 'nullable Indicates if scholarships available (deprecated).' example: true nullable: true scholarship_availability: type: string description: 'Scholarship availability level. Must be one of: high, moderate, very high, low, very high (full), very high (need blind), very high (stipendium).' example: 'very high' nullable: false study_destination_id: type: uuid description: 'The ID of the study destination.' example: 9b1e967a-706d-4912-9c31 nullable: false contact: type: object description: 'Contact information.' example: [] nullable: false properties: email: type: array description: 'Array of email addresses.' example: - qkunze@example.com items: type: string phone: type: array description: 'Array of phone numbers.' example: - consequatur items: type: string website: type: string description: 'nullable Website URL.' example: consequatur nullable: true required: - email - phone university_description: type: object description: 'Detailed description and campus info.' example: [] nullable: false properties: description: type: string description: 'nullable General description.' example: 'Dolores dolorum amet iste laborum eius est dolor.' nullable: true campus_size: type: string description: 'Campus size.' example: Large nullable: false student_life: type: string description: 'Student life description.' example: consequatur nullable: false city_type: type: string description: 'City type.' example: Urban nullable: false climate: type: string description: 'Climate type.' example: Temperate nullable: false required: - campus_size - student_life - city_type - climate annual_tuition: type: object description: 'Tuition details.' example: [] nullable: false properties: international: type: number description: 'International student fee.' example: 11613.31890586 nullable: false local: type: number description: 'Local student fee.' example: 11613.31890586 nullable: false year: type: integer description: 'Academic year.' example: 2024 nullable: false currency_id: type: uuid description: 'UUID of the currency.' example: consequatur nullable: false required: - international - local - year - currency_id gallery: type: array description: 'nullable Array of gallery images (max 2MB each).' items: type: string format: binary nullable: true application_fee: type: number description: 'The application cost.' example: 100.0 nullable: false application_flat_price: type: number description: 'Total flat price for application.' example: 500.0 nullable: false admission_requirements: type: string description: 'nullable Admission requirements text.' example: consequatur nullable: true application_link: type: string description: 'nullable URL to application portal.' example: consequatur nullable: true monthly_living_cost: type: string description: 'Monthly living cost estimate.' example: '$1,200-$1,500' nullable: false affordability_tier: type: string description: 'Affordability category.' example: Mid-Range nullable: false required: - name - address - country - admission_rate - scholarship_availability - study_destination_id - contact - university_description - annual_tuition - application_fee - application_flat_price - monthly_living_cost - affordability_tier '/api/v1/universities/{university_id}': get: summary: 'Display the specified university.' operationId: displayTheSpecifiedUniversity description: '' parameters: [] responses: 500: description: '' content: application/json: schema: type: object example: success: false errors: Unauthenticated. timestamp: '2026-04-18T17:44:14.072659Z' properties: success: type: boolean example: false errors: type: string example: Unauthenticated. timestamp: type: string example: '2026-04-18T17:44:14.072659Z' tags: - Universities parameters: - in: path name: university_id description: 'The ID of the university.' example: 00ce85a9-6d2d-4be1-a0cd-274d7c063eac required: true schema: type: string - in: path name: university description: 'Optional parameter. uuid required The UUID of the university.' required: true schema: type: string examples: omitted: summary: 'When the value is omitted' value: '' present: summary: 'When the value is present' value: 9b1e967a-706d-4912-9c31 '/api/v1/universities/{id}': put: summary: 'Update the specified university.' operationId: updateTheSpecifiedUniversity description: '' parameters: [] responses: { } tags: - Universities requestBody: required: false content: multipart/form-data: schema: type: object properties: name: type: string description: 'optional The name of the university.' example: 'University of Toronto Updated' nullable: false address: type: string description: 'optional Full physical address.' example: consequatur nullable: false logo: type: string format: binary description: 'optional New university logo image (max 2MB).' nullable: true country: type: string description: 'optional Country name.' example: Canada nullable: false admission_rate: type: number description: 'optional Admission percentage (0-100).' example: 45.0 nullable: false is_scholarship_available: type: boolean description: 'optional Indicates if scholarships available.' example: true nullable: false scholarship_availability: type: string description: 'optional Scholarship availability level. One of: high, moderate, very high, low, very high (full), very high (need blind), very high (stipendium).' example: 'very high (full)' nullable: false study_destination_id: type: uuid description: 'optional The ID of the study destination.' example: consequatur nullable: false contact: type: object description: 'optional Contact information.' example: [] nullable: false properties: email: type: array description: 'optional Array of email addresses.' example: - qkunze@example.com items: type: string phone: type: array description: 'optional Array of phone numbers.' example: - consequatur items: type: string website: type: string description: 'optional Website URL.' example: consequatur nullable: true university_description: type: object description: 'optional Detailed description updates.' example: [] nullable: false properties: description: type: string description: 'optional General description.' example: 'Dolores dolorum amet iste laborum eius est dolor.' nullable: false campus_size: type: string description: 'optional Campus size.' example: Large nullable: false student_life: type: string description: 'optional Student life description.' example: consequatur nullable: false city_type: type: string description: 'optional City type.' example: Urban nullable: false climate: type: string description: 'optional Climate type.' example: Temperate nullable: false annual_tuition: type: object description: 'optional Tuition details updates.' example: [] nullable: false properties: international: type: number description: 'optional International student fee.' example: 11613.31890586 nullable: false local: type: number description: 'optional Local student fee.' example: 11613.31890586 nullable: false year: type: integer description: 'optional Academic year.' example: 2024 nullable: false currency_id: type: uuid description: 'optional UUID of the currency.' example: consequatur nullable: false application_fee: type: number description: 'optional The application cost.' example: 11613.31890586 nullable: false application_flat_price: type: number description: 'optional Total flat price for application.' example: 11613.31890586 nullable: false admission_requirements: type: string description: 'optional Admission requirements text.' example: consequatur nullable: true application_link: type: string description: 'optional URL to application portal.' example: consequatur nullable: true monthly_living_cost: type: string description: 'optional Monthly living cost estimate.' example: consequatur nullable: false affordability_tier: type: string description: 'optional Affordability category.' example: consequatur nullable: false gallery: type: array description: 'optional New gallery images (replaces old ones).' items: type: string format: binary nullable: true delete: summary: 'Remove the specified university.' operationId: removeTheSpecifiedUniversity description: '' parameters: [] responses: { } tags: - Universities parameters: - in: path name: id description: 'The ID of the university.' example: 00ce85a9-6d2d-4be1-a0cd-274d7c063eac required: true schema: type: string - in: path name: university description: 'Optional parameter. uuid required The UUID of the university.' required: true schema: type: string examples: omitted: summary: 'When the value is omitted' value: '' present: summary: 'When the value is present' value: 9b1e967a-706d-4912-9c31 '/api/v1/universities/country/{country}': get: summary: 'Get universities by country.' operationId: getUniversitiesByCountry description: '' parameters: [] responses: 500: description: '' content: application/json: schema: type: object example: success: false errors: Unauthenticated. timestamp: '2026-04-18T17:44:14.096173Z' properties: success: type: boolean example: false errors: type: string example: Unauthenticated. timestamp: type: string example: '2026-04-18T17:44:14.096173Z' tags: - Universities parameters: - in: path name: country description: 'The country name.' example: Germany required: true schema: type: string /api/v1/universities/scholarships/available: get: summary: 'Get universities with scholarships available.' operationId: getUniversitiesWithScholarshipsAvailable description: "This endpoint filters for universities where scholarship_availability is NOT 'low'." parameters: - in: query name: level description: 'Filter by specific scholarship level (high, moderate, very high, etc.).' example: consequatur required: false schema: type: string description: 'Filter by specific scholarship level (high, moderate, very high, etc.).' example: consequatur nullable: false responses: 500: description: '' content: application/json: schema: type: object example: success: false errors: Unauthenticated. timestamp: '2026-04-18T17:44:14.100207Z' properties: success: type: boolean example: false errors: type: string example: Unauthenticated. timestamp: type: string example: '2026-04-18T17:44:14.100207Z' tags: - Universities /api/v1/admin/universities: post: summary: 'Store a newly created university.' operationId: storeANewlyCreatedUniversity description: '' parameters: [] responses: { } tags: - Universities requestBody: required: true content: multipart/form-data: schema: type: object properties: name: type: string description: 'The name of the university.' example: 'University of Toronto' nullable: false address: type: string description: 'Full physical address.' example: "27 King's College Cir, Toronto, ON." nullable: false logo: type: string format: binary description: 'nullable University logo image (max 2MB).' nullable: true country: type: string description: 'Country name.' example: Canada nullable: false admission_rate: type: number description: 'Admission percentage (0-100).' example: 43.5 nullable: false is_scholarship_available: type: boolean description: 'nullable Indicates if scholarships available (deprecated).' example: true nullable: true scholarship_availability: type: string description: 'Scholarship availability level. Must be one of: high, moderate, very high, low, very high (full), very high (need blind), very high (stipendium).' example: 'very high' nullable: false study_destination_id: type: uuid description: 'The ID of the study destination.' example: 9b1e967a-706d-4912-9c31 nullable: false contact: type: object description: 'Contact information.' example: [] nullable: false properties: email: type: array description: 'Array of email addresses.' example: - qkunze@example.com items: type: string phone: type: array description: 'Array of phone numbers.' example: - consequatur items: type: string website: type: string description: 'nullable Website URL.' example: consequatur nullable: true required: - email - phone university_description: type: object description: 'Detailed description and campus info.' example: [] nullable: false properties: description: type: string description: 'nullable General description.' example: 'Dolores dolorum amet iste laborum eius est dolor.' nullable: true campus_size: type: string description: 'Campus size.' example: Large nullable: false student_life: type: string description: 'Student life description.' example: consequatur nullable: false city_type: type: string description: 'City type.' example: Urban nullable: false climate: type: string description: 'Climate type.' example: Temperate nullable: false required: - campus_size - student_life - city_type - climate annual_tuition: type: object description: 'Tuition details.' example: [] nullable: false properties: international: type: number description: 'International student fee.' example: 11613.31890586 nullable: false local: type: number description: 'Local student fee.' example: 11613.31890586 nullable: false year: type: integer description: 'Academic year.' example: 2024 nullable: false currency_id: type: uuid description: 'UUID of the currency.' example: consequatur nullable: false required: - international - local - year - currency_id gallery: type: array description: 'nullable Array of gallery images (max 2MB each).' items: type: string format: binary nullable: true application_fee: type: number description: 'The application cost.' example: 100.0 nullable: false application_flat_price: type: number description: 'Total flat price for application.' example: 500.0 nullable: false admission_requirements: type: string description: 'nullable Admission requirements text.' example: consequatur nullable: true application_link: type: string description: 'nullable URL to application portal.' example: consequatur nullable: true monthly_living_cost: type: string description: 'Monthly living cost estimate.' example: '$1,200-$1,500' nullable: false affordability_tier: type: string description: 'Affordability category.' example: Mid-Range nullable: false required: - name - address - country - admission_rate - scholarship_availability - study_destination_id - contact - university_description - annual_tuition - application_fee - application_flat_price - monthly_living_cost - affordability_tier '/api/v1/admin/universities/{university_id}': put: summary: 'Update the specified university.' operationId: updateTheSpecifiedUniversity description: '' parameters: [] responses: { } tags: - Universities requestBody: required: false content: multipart/form-data: schema: type: object properties: name: type: string description: 'optional The name of the university.' example: 'University of Toronto Updated' nullable: false address: type: string description: 'optional Full physical address.' example: consequatur nullable: false logo: type: string format: binary description: 'optional New university logo image (max 2MB).' nullable: true country: type: string description: 'optional Country name.' example: Canada nullable: false admission_rate: type: number description: 'optional Admission percentage (0-100).' example: 45.0 nullable: false is_scholarship_available: type: boolean description: 'optional Indicates if scholarships available.' example: true nullable: false scholarship_availability: type: string description: 'optional Scholarship availability level. One of: high, moderate, very high, low, very high (full), very high (need blind), very high (stipendium).' example: 'very high (full)' nullable: false study_destination_id: type: uuid description: 'optional The ID of the study destination.' example: consequatur nullable: false contact: type: object description: 'optional Contact information.' example: [] nullable: false properties: email: type: array description: 'optional Array of email addresses.' example: - qkunze@example.com items: type: string phone: type: array description: 'optional Array of phone numbers.' example: - consequatur items: type: string website: type: string description: 'optional Website URL.' example: consequatur nullable: true university_description: type: object description: 'optional Detailed description updates.' example: [] nullable: false properties: description: type: string description: 'optional General description.' example: 'Dolores dolorum amet iste laborum eius est dolor.' nullable: false campus_size: type: string description: 'optional Campus size.' example: Large nullable: false student_life: type: string description: 'optional Student life description.' example: consequatur nullable: false city_type: type: string description: 'optional City type.' example: Urban nullable: false climate: type: string description: 'optional Climate type.' example: Temperate nullable: false annual_tuition: type: object description: 'optional Tuition details updates.' example: [] nullable: false properties: international: type: number description: 'optional International student fee.' example: 11613.31890586 nullable: false local: type: number description: 'optional Local student fee.' example: 11613.31890586 nullable: false year: type: integer description: 'optional Academic year.' example: 2024 nullable: false currency_id: type: uuid description: 'optional UUID of the currency.' example: consequatur nullable: false application_fee: type: number description: 'optional The application cost.' example: 11613.31890586 nullable: false application_flat_price: type: number description: 'optional Total flat price for application.' example: 11613.31890586 nullable: false admission_requirements: type: string description: 'optional Admission requirements text.' example: consequatur nullable: true application_link: type: string description: 'optional URL to application portal.' example: consequatur nullable: true monthly_living_cost: type: string description: 'optional Monthly living cost estimate.' example: consequatur nullable: false affordability_tier: type: string description: 'optional Affordability category.' example: consequatur nullable: false gallery: type: array description: 'optional New gallery images (replaces old ones).' items: type: string format: binary nullable: true delete: summary: 'Remove the specified university.' operationId: removeTheSpecifiedUniversity description: '' parameters: [] responses: { } tags: - Universities parameters: - in: path name: university_id description: 'The ID of the university.' example: 00ce85a9-6d2d-4be1-a0cd-274d7c063eac required: true schema: type: string - in: path name: university description: 'Optional parameter. uuid required The UUID of the university.' required: true schema: type: string examples: omitted: summary: 'When the value is omitted' value: '' present: summary: 'When the value is present' value: 9b1e967a-706d-4912-9c31 /api/v1/applications: get: summary: 'Get all applications' operationId: getAllApplications description: "Returns a paginated list of university applications.
\nYou can filter by status, student, major or university." parameters: - in: query name: status description: 'Filter by status' example: Submitted required: false schema: type: string description: 'Filter by status' example: Submitted nullable: false - in: query name: student_id description: 'Filter by student id' example: 5 required: false schema: type: integer description: 'Filter by student id' example: 5 nullable: false - in: query name: major_id description: 'Filter by major id' example: 12 required: false schema: type: integer description: 'Filter by major id' example: 12 nullable: false - in: query name: applied_university_id description: 'Filter by university id' example: 8 required: false schema: type: integer description: 'Filter by university id' example: 8 nullable: false - in: query name: page description: 'Page number' example: 1 required: false schema: type: integer description: 'Page number' example: 1 nullable: false responses: 200: description: 'Paginated list' content: application/json: schema: type: object nullable: true tags: - 'University Applications Management' post: summary: 'Create a new application' operationId: createANewApplication description: '' parameters: [] responses: 201: description: '' content: application/json: schema: type: object example: id: 550e8400-e29b-41d4-a716-446655440000 application_date: '2025-12-11' status: Draft response_date: null feedback: null student: id: 5 name: 'John Doe' major: id: 12 name: 'Data Science' applied_university: id: 8 name: 'Tech University' properties: id: type: string example: 550e8400-e29b-41d4-a716-446655440000 application_date: type: string example: '2025-12-11' status: type: string example: Draft response_date: type: string example: null feedback: type: string example: null student: type: object properties: id: type: integer example: 5 name: type: string example: 'John Doe' major: type: object properties: id: type: integer example: 12 name: type: string example: 'Data Science' applied_university: type: object properties: id: type: integer example: 8 name: type: string example: 'Tech University' 403: description: '' content: application/json: schema: type: object example: message: Forbidden properties: message: type: string example: Forbidden tags: - 'University Applications Management' requestBody: required: true content: application/json: schema: type: object properties: major_id: type: string description: 'The id of an existing record in the majors table.' example: consequatur nullable: false application_date: type: string description: 'Must be a valid date.' example: '2026-04-18T17:44:14' nullable: false applied_university_id: type: string description: 'The id of an existing record in the universities table.' example: consequatur nullable: false required: - major_id - application_date - applied_university_id '/api/v1/applications/{id}': get: summary: 'Get single application' operationId: getSingleApplication description: '' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: id: 550e8400-e29b-41d4-a716-446655440000 application_date: '2025-06-01' status: Submitted response_date: null feedback: null student: id: 5 name: 'John Doe' major: id: 12 name: 'Data Science' applied_university: id: 8 name: 'Tech University' properties: id: type: string example: 550e8400-e29b-41d4-a716-446655440000 application_date: type: string example: '2025-06-01' status: type: string example: Submitted response_date: type: string example: null feedback: type: string example: null student: type: object properties: id: type: integer example: 5 name: type: string example: 'John Doe' major: type: object properties: id: type: integer example: 12 name: type: string example: 'Data Science' applied_university: type: object properties: id: type: integer example: 8 name: type: string example: 'Tech University' tags: - 'University Applications Management' put: summary: 'Update application' operationId: updateApplication description: 'Only status, response_date and feedback can be edited after creation.' parameters: [] responses: 200: description: '' content: text/plain: schema: type: string example: '{ ...updated resource... }' 403: description: '' content: application/json: schema: type: object example: message: Forbidden properties: message: type: string example: Forbidden tags: - 'University Applications Management' requestBody: required: false content: application/json: schema: type: object properties: status: type: string description: '' example: null nullable: false response_date: type: string description: 'Must be a valid date.' example: '2026-04-18T17:44:14' nullable: true feedback: type: string description: '' example: consequatur nullable: true delete: summary: 'Delete application' operationId: deleteApplication description: '' parameters: [] responses: 204: description: '' content: application/json: schema: type: object example: { } properties: { } 403: description: '' content: application/json: schema: type: object example: message: Forbidden properties: message: type: string example: Forbidden tags: - 'University Applications Management' parameters: - in: path name: id description: 'The ID of the application.' example: 1b7f325d-b2cf-4dc4-8e39-2bb2fa02a1cd required: true schema: type: string '/api/v1/users/{user_id}': post: summary: 'Update user' operationId: updateUser description: "Admins can update any user. Users can only update their own name, email, profile picture, password, and majors.\nFor the password, the request must include a password_confirmation field that matches the new password.\nOnly admins can change user roles." parameters: [] responses: 200: description: 'User updated successfully' content: application/json: schema: type: object nullable: true 403: description: 'Not authorized' content: application/json: schema: type: object nullable: true 404: description: 'User not found' content: application/json: schema: type: object nullable: true 422: description: 'Validation error' content: application/json: schema: type: object nullable: true tags: - 'User Management' requestBody: required: false content: multipart/form-data: schema: type: object properties: name: type: string description: 'User name' example: 'John Doe' nullable: false email: type: string description: 'User email (must be unique)' example: john@example.com nullable: false role_id: type: integer description: 'Role ID - admin only (1=student, 2=manager, 3=admin, 4=adviser)' example: 4 nullable: false profile_picture: type: string format: binary description: 'User profile image (jpeg, png, jpg, webp), max 2MB' nullable: false password: type: string description: 'New password (min 8 characters)' example: newpassword123 nullable: false major_ids: type: array description: 'List of Major IDs to associate with the user' example: - 1 - 5 - 12 items: type: string password_confirmation: type: string description: 'Must match password field' example: newpassword123 nullable: false parameters: - in: path name: user_id description: 'The ID of the user.' example: 1 required: true schema: type: integer /api/v1/admin/users: get: summary: 'List all users with filters' operationId: listAllUsersWithFilters description: "Admins can filter by role, search by name/email, and view all users.\nSupports search, filtering, sorting, and pagination." parameters: - in: query name: role_id description: 'Filter by role ID (1=student, 2=manager, 3=admin, 4=adviser)' example: 1 required: false schema: type: integer description: 'Filter by role ID (1=student, 2=manager, 3=admin, 4=adviser)' example: 1 nullable: false - in: query name: search description: 'Search by name or email' example: John required: false schema: type: string description: 'Search by name or email' example: John nullable: false - in: query name: sort_by description: 'Sort field (name, email, created_at, updated_at, role_id)' example: name required: false schema: type: string description: 'Sort field (name, email, created_at, updated_at, role_id)' example: name nullable: false - in: query name: sort_order description: 'Sort order (asc or desc)' example: asc required: false schema: type: string description: 'Sort order (asc or desc)' example: asc nullable: false - in: query name: per_page description: 'Results per page (5-100)' example: 15 required: false schema: type: integer description: 'Results per page (5-100)' example: 15 nullable: false responses: 200: description: 'Paginated list of users' content: application/json: schema: type: object nullable: true 403: description: 'Not authorized' content: application/json: schema: type: object nullable: true tags: - 'User Management' requestBody: required: false content: application/json: schema: type: object properties: role_id: type: integer description: 'The id of an existing record in the roles table.' example: 17 nullable: true search: type: string description: 'Must not be greater than 255 characters.' example: mqeopfuudtdsufvyvddqa nullable: true sort_by: type: string description: '' example: updated_at nullable: true enum: - name - email - created_at - updated_at - role_id sort_order: type: string description: '' example: asc nullable: true enum: - asc - desc per_page: type: integer description: 'Must be at least 5. Must not be greater than 100.' example: 13 nullable: true '/api/v1/admin/users/{id}': get: summary: 'Get user details' operationId: getUserDetails description: 'Returns user information including role, relationships, and student/adviser data.' parameters: [] responses: 200: description: 'User details with all relationships' content: application/json: schema: type: object nullable: true 403: description: 'Not authorized' content: application/json: schema: type: object nullable: true 404: description: 'User not found' content: application/json: schema: type: object nullable: true tags: - 'User Management' put: summary: 'Update user' operationId: updateUser description: "Admins can update any user. Users can only update their own name, email, profile picture, password, and majors.\nFor the password, the request must include a password_confirmation field that matches the new password.\nOnly admins can change user roles." parameters: [] responses: 200: description: 'User updated successfully' content: application/json: schema: type: object nullable: true 403: description: 'Not authorized' content: application/json: schema: type: object nullable: true 404: description: 'User not found' content: application/json: schema: type: object nullable: true 422: description: 'Validation error' content: application/json: schema: type: object nullable: true tags: - 'User Management' requestBody: required: false content: multipart/form-data: schema: type: object properties: name: type: string description: 'User name' example: 'John Doe' nullable: false email: type: string description: 'User email (must be unique)' example: john@example.com nullable: false role_id: type: integer description: 'Role ID - admin only (1=student, 2=manager, 3=admin, 4=adviser)' example: 4 nullable: false profile_picture: type: string format: binary description: 'User profile image (jpeg, png, jpg, webp), max 2MB' nullable: false password: type: string description: 'New password (min 8 characters)' example: newpassword123 nullable: false major_ids: type: array description: 'List of Major IDs to associate with the user' example: - 1 - 5 - 12 items: type: string password_confirmation: type: string description: 'Must match password field' example: newpassword123 nullable: false delete: summary: 'Delete user' operationId: deleteUser description: 'Only admins can delete users, and cannot delete their own account.' parameters: [] responses: 204: description: 'User deleted successfully' content: application/json: schema: type: object nullable: true 403: description: 'Not authorized or cannot delete self' content: application/json: schema: type: object nullable: true 422: description: 'Cannot delete own account' content: application/json: schema: type: object nullable: true tags: - 'User Management' parameters: - in: path name: id description: 'The ID of the user.' example: 1 required: true schema: type: integer /api/v1/admin/users-by-role: get: summary: 'Get users by role' operationId: getUsersByRole description: 'Retrieve all users with a specific role.' parameters: - in: query name: role_name description: 'Role name (student, manager, admin, adviser)' example: adviser required: true schema: type: string description: 'Role name (student, manager, admin, adviser)' example: adviser nullable: false - in: query name: per_page description: 'Results per page' example: 15 required: false schema: type: integer description: 'Results per page' example: 15 nullable: false responses: 200: description: 'Paginated list of users with specified role' content: application/json: schema: type: object nullable: true 403: description: 'Not authorized' content: application/json: schema: type: object nullable: true tags: - 'User Management' requestBody: required: true content: application/json: schema: type: object properties: role_name: type: string description: '' example: adviser nullable: false enum: - student - manager - admin - adviser per_page: type: integer description: 'Must be at least 5. Must not be greater than 100.' example: 21 nullable: true required: - role_name /api/v1/admin/users-statistics: get: summary: 'Get user statistics' operationId: getUserStatistics description: 'Returns total user count and breakdown by role.' parameters: [] responses: 200: description: 'User statistics breakdown by role' content: application/json: schema: type: object nullable: true 403: description: 'Not authorized' content: application/json: schema: type: object nullable: true tags: - 'User Management' /api/v1/admin/users/change-role: post: summary: 'Change user role' operationId: changeUserRole description: "Admin-only endpoint to change a user's role with audit trail." parameters: [] responses: 200: description: 'User role changed successfully' content: application/json: schema: type: object example: message: 'User role updated successfully' old_role: adviser new_role: manager properties: message: type: string example: 'User role updated successfully' old_role: type: string example: adviser new_role: type: string example: manager 403: description: 'Not authorized' content: application/json: schema: type: object nullable: true 404: description: 'User not found' content: application/json: schema: type: object nullable: true tags: - 'User Management' requestBody: required: true content: application/json: schema: type: object properties: user_id: type: integer description: 'The user ID to modify' example: 5 nullable: false role_id: type: integer description: 'The new role ID (1=student, 2=manager, 3=admin, 4=adviser)' example: 2 nullable: false required: - user_id - role_id /api/v1/admin/users/bulk-action: post: summary: 'Bulk user operations' operationId: bulkUserOperations description: 'Supports bulk delete and bulk role change. Authenticated user is automatically excluded from operations.' parameters: [] responses: 200: description: 'Bulk operation completed' content: application/json: schema: type: object example: message: 'Bulk operation completed' affected: 5 action: delete properties: message: type: string example: 'Bulk operation completed' affected: type: integer example: 5 action: type: string example: delete 403: description: 'Not authorized' content: application/json: schema: type: object nullable: true tags: - 'User Management' requestBody: required: true content: application/json: schema: type: object properties: user_ids: type: array description: 'Array of user IDs to operate on' example: '[5, 6, 7]' items: type: string action: type: string description: 'Action to perform: delete or change_role' example: delete nullable: false role_id: type: integer description: 'Required if action is change_role' example: 2 nullable: false required: - user_ids - action /api/v1/admin/users-export: get: summary: 'Export users to CSV' operationId: exportUsersToCSV description: 'Exports user data as CSV file. Admins and managers can export; optional role filter available.' parameters: - in: query name: role_id description: 'Optional role ID to filter by' example: 1 required: false schema: type: integer description: 'Optional role ID to filter by' example: 1 nullable: false responses: 200: description: 'CSV file content with columns: ID, Name, Email, Role, Created At, Updated At' content: application/json: schema: type: object nullable: true 403: description: 'Not authorized' content: application/json: schema: type: object nullable: true tags: - 'User Management' /api/v1/notifications: get: summary: '' operationId: getApiV1Notifications description: '' parameters: - in: query name: status description: 'the kind of status to fetch example: unread, read, all.' example: consequatur required: false schema: type: string description: 'the kind of status to fetch example: unread, read, all.' example: consequatur nullable: false - in: query name: limit description: 'the number of notifications to get.' example: 17 required: false schema: type: integer description: 'the number of notifications to get.' example: 17 nullable: false - in: query name: paginated description: "choose if you need the pagination or not.\n\nGet latest 10 notifications (non-paginated):\n /api/notifications?limit=10" example: false required: false schema: type: boolean description: "choose if you need the pagination or not.\n\nGet latest 10 notifications (non-paginated):\n /api/notifications?limit=10" example: false nullable: false responses: 500: description: '' content: application/json: schema: type: object example: success: false errors: Unauthenticated. timestamp: '2026-04-18T17:44:14.031029Z' properties: success: type: boolean example: false errors: type: string example: Unauthenticated. timestamp: type: string example: '2026-04-18T17:44:14.031029Z' tags: - 'User Notification Management' '/api/v1/notifications/{id}': get: summary: 'Display one notification and mark it as read.' operationId: displayOneNotificationAndMarkItAsRead description: '' parameters: - in: query name: status description: 'the kind of status to fetch example: unread, read, all.' example: consequatur required: false schema: type: string description: 'the kind of status to fetch example: unread, read, all.' example: consequatur nullable: false - in: query name: limit description: 'the number of notifications to get.' example: 17 required: false schema: type: integer description: 'the number of notifications to get.' example: 17 nullable: false - in: query name: paginated description: "choose if you need the pagination or not.\n\nGet latest 10 notifications (non-paginated):\n /api/notifications?limit=10" example: false required: false schema: type: boolean description: "choose if you need the pagination or not.\n\nGet latest 10 notifications (non-paginated):\n /api/notifications?limit=10" example: false nullable: false responses: 500: description: '' content: application/json: schema: type: object example: success: false errors: Unauthenticated. timestamp: '2026-04-18T17:44:14.035830Z' properties: success: type: boolean example: false errors: type: string example: Unauthenticated. timestamp: type: string example: '2026-04-18T17:44:14.035830Z' tags: - 'User Notification Management' parameters: - in: path name: id description: 'The ID of the notification.' example: consequatur required: true schema: type: string /api/v1/notifications/read-all: post: summary: 'Mark all notifications as read.' operationId: markAllNotificationsAsRead description: '' parameters: - in: query name: status description: 'the kind of status to fetch example: unread, read, all.' example: consequatur required: false schema: type: string description: 'the kind of status to fetch example: unread, read, all.' example: consequatur nullable: false - in: query name: limit description: 'the number of notifications to get.' example: 17 required: false schema: type: integer description: 'the number of notifications to get.' example: 17 nullable: false - in: query name: paginated description: "choose if you need the pagination or not.\n\nGet latest 10 notifications (non-paginated):\n /api/notifications?limit=10" example: false required: false schema: type: boolean description: "choose if you need the pagination or not.\n\nGet latest 10 notifications (non-paginated):\n /api/notifications?limit=10" example: false nullable: false responses: { } tags: - 'User Notification Management' /api/v1/admin/roles: get: summary: 'Display a listing of all the roles.' operationId: displayAListingOfAllTheRoles description: '' parameters: [] responses: 500: description: '' content: application/json: schema: type: object example: success: false errors: Unauthenticated. timestamp: '2026-04-18T17:44:14.259827Z' properties: success: type: boolean example: false errors: type: string example: Unauthenticated. timestamp: type: string example: '2026-04-18T17:44:14.259827Z' tags: - 'Users roles' post: summary: 'Store a newly created resource in storage.' operationId: storeANewlyCreatedResourceInStorage description: '' parameters: [] responses: { } tags: - 'Users roles' requestBody: required: true content: application/json: schema: type: object properties: name: type: string description: '' example: consequatur nullable: false description: type: string description: '' example: 'Dolores dolorum amet iste laborum eius est dolor.' nullable: true required: - name '/api/v1/admin/roles/{id}': get: summary: 'Display the specified role.' operationId: displayTheSpecifiedRole description: '' parameters: [] responses: 500: description: '' content: application/json: schema: type: object example: success: false errors: Unauthenticated. timestamp: '2026-04-18T17:44:14.265461Z' properties: success: type: boolean example: false errors: type: string example: Unauthenticated. timestamp: type: string example: '2026-04-18T17:44:14.265461Z' tags: - 'Users roles' put: summary: 'Update the role in the table.' operationId: updateTheRoleInTheTable description: '' parameters: [] responses: { } tags: - 'Users roles' requestBody: required: false content: application/json: schema: type: object properties: name: type: string description: '' example: consequatur nullable: false description: type: string description: '' example: 'Dolores dolorum amet iste laborum eius est dolor.' nullable: false delete: summary: 'Remove the specified role from the table.' operationId: removeTheSpecifiedRoleFromTheTable description: '' parameters: [] responses: { } tags: - 'Users roles' parameters: - in: path name: id description: 'The ID of the role.' example: 1 required: true schema: type: integer '/api/v1/admin/roles/users/{role_id}': get: summary: 'Get the users by a specified role' operationId: getTheUsersByASpecifiedRole description: '' parameters: [] responses: 500: description: '' content: application/json: schema: type: object example: success: false errors: Unauthenticated. timestamp: '2026-04-18T17:44:14.273944Z' properties: success: type: boolean example: false errors: type: string example: Unauthenticated. timestamp: type: string example: '2026-04-18T17:44:14.273944Z' tags: - 'Users roles' parameters: - in: path name: role_id description: 'The ID of the role.' example: 1 required: true schema: type: integer