Yimaru-BackEnd/docs/swagger.yaml
Yared Yemane 08a2886654 feat: optional dynamic question_text and OPEN_LEARNER completed access
Derive question_text from QUESTION_TEXT, INSTRUCTION, or TEXT_PASSAGE stimulus for DYNAMIC questions so the top-level field is no longer required on create.

OPEN_LEARNER access responses now set is_accessible and is_completed to true on all LMS and exam-prep content, with full progress when totals exist.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-04 09:48:33 -07:00

9962 lines
249 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

definitions:
domain.AcceptTeamInvitationReq:
properties:
bio:
type: string
department:
type: string
emergency_contact:
type: string
employment_type:
type: string
first_name:
type: string
hire_date:
description: YYYY-MM-DD
type: string
job_title:
type: string
last_name:
type: string
password:
minLength: 8
type: string
phone_number:
type: string
profile_picture_url:
type: string
token:
type: string
work_phone:
type: string
required:
- first_name
- last_name
- password
- token
type: object
domain.AgeGroup:
enum:
- UNDER_13
- "13_17"
- "18_24"
- "25_34"
- "35_44"
- "45_54"
- 55_PLUS
type: string
x-enum-varnames:
- AgeUnder13
- Age13To17
- Age18To24
- Age25To34
- Age35To44
- Age45To54
- Age55Plus
domain.AnalyticsContentSection:
properties:
question_sets_by_type:
items:
$ref: '#/definitions/domain.AnalyticsLabelCount'
type: array
questions_by_type:
items:
$ref: '#/definitions/domain.AnalyticsLabelCount'
type: array
total_question_sets:
type: integer
total_questions:
type: integer
type: object
domain.AnalyticsCoursesSection:
properties:
exam_prep:
$ref: '#/definitions/domain.AnalyticsExamPrepContentCounts'
lms:
$ref: '#/definitions/domain.AnalyticsLMSContentCounts'
total_categories:
description: 'Top-level keys preserved for existing clients: map to LMS programs,
courses, modules, and all video lessons (LMS + exam prep).'
type: integer
total_courses:
type: integer
total_sub_courses:
type: integer
total_videos:
type: integer
type: object
domain.AnalyticsDashboard:
properties:
content:
$ref: '#/definitions/domain.AnalyticsContentSection'
courses:
$ref: '#/definitions/domain.AnalyticsCoursesSection'
date_filter:
$ref: '#/definitions/domain.AnalyticsDateFilter'
generated_at:
type: string
issues:
$ref: '#/definitions/domain.AnalyticsIssuesSection'
notifications:
$ref: '#/definitions/domain.AnalyticsNotificationsSection'
payments:
$ref: '#/definitions/domain.AnalyticsPaymentsSection'
subscriptions:
$ref: '#/definitions/domain.AnalyticsSubscriptionsSection'
team:
$ref: '#/definitions/domain.AnalyticsTeamSection'
users:
$ref: '#/definitions/domain.AnalyticsUsersSection'
videos:
$ref: '#/definitions/domain.AnalyticsVideosSection'
type: object
domain.AnalyticsDateFilter:
properties:
from:
type: string
mode:
type: string
month:
type: integer
range_end:
type: string
range_start:
type: string
ref_date:
type: string
series_end:
type: string
series_start:
type: string
to:
type: string
year:
type: integer
type: object
domain.AnalyticsExamPrepContentCounts:
properties:
catalog_courses:
type: integer
lesson_practices:
type: integer
lessons:
type: integer
lessons_with_video:
type: integer
unit_modules:
type: integer
units:
type: integer
type: object
domain.AnalyticsIssuesSection:
properties:
by_status:
items:
$ref: '#/definitions/domain.AnalyticsLabelCount'
type: array
by_type:
items:
$ref: '#/definitions/domain.AnalyticsLabelCount'
type: array
resolution_rate:
type: number
resolved_issues:
type: integer
total_issues:
type: integer
type: object
domain.AnalyticsLMSContentCounts:
properties:
courses:
type: integer
lessons:
type: integer
lessons_with_video:
type: integer
modules:
type: integer
practices:
type: integer
practices_at_course:
type: integer
practices_at_lesson:
type: integer
practices_at_module:
type: integer
programs:
type: integer
type: object
domain.AnalyticsLabelAmount:
properties:
amount:
type: number
count:
type: integer
label:
type: string
type: object
domain.AnalyticsLabelCount:
properties:
count:
type: integer
label:
type: string
type: object
domain.AnalyticsMonthlyRevenuePoint:
properties:
currency:
type: string
label:
description: Short English month label, e.g. Jan
type: string
month:
description: 112
type: integer
month_start:
description: UTC date of month start (for sorting / tooltips)
type: string
revenue:
description: SUCCESS payments aggregate for that bucket
type: number
type: object
domain.AnalyticsNotificationsSection:
properties:
by_channel:
items:
$ref: '#/definitions/domain.AnalyticsLabelCount'
type: array
by_type:
items:
$ref: '#/definitions/domain.AnalyticsLabelCount'
type: array
read_count:
type: integer
total_sent:
type: integer
unread_count:
type: integer
type: object
domain.AnalyticsPaymentsSection:
properties:
avg_transaction_value:
type: number
by_method:
items:
$ref: '#/definitions/domain.AnalyticsLabelAmount'
type: array
by_status:
items:
$ref: '#/definitions/domain.AnalyticsLabelAmount'
type: array
monthly_revenue_year:
description: MonthlyRevenueYear is set when RevenueMonthly is non-empty (the
calendar year of those buckets).
type: integer
revenue_last_30_days:
items:
$ref: '#/definitions/domain.AnalyticsRevenueTimePoint'
type: array
revenue_monthly:
description: RevenueMonthly is populated only when the request includes year=...,
with 12 months (possibly multiple currencies per month).
items:
$ref: '#/definitions/domain.AnalyticsMonthlyRevenuePoint'
type: array
successful_payments:
type: integer
total_payments:
type: integer
total_revenue:
type: number
type: object
domain.AnalyticsRevenueByPlan:
properties:
currency:
type: string
plan_name:
type: string
revenue:
type: number
type: object
domain.AnalyticsRevenueTimePoint:
properties:
date:
type: string
revenue:
type: number
type: object
domain.AnalyticsSubscriptionsSection:
properties:
active_subscriptions:
type: integer
by_status:
items:
$ref: '#/definitions/domain.AnalyticsLabelCount'
type: array
new_month:
type: integer
new_subscriptions_last_30_days:
items:
$ref: '#/definitions/domain.AnalyticsTimePoint'
type: array
new_today:
type: integer
new_week:
type: integer
revenue_by_plan:
items:
$ref: '#/definitions/domain.AnalyticsRevenueByPlan'
type: array
total_subscriptions:
type: integer
type: object
domain.AnalyticsTeamSection:
properties:
by_role:
items:
$ref: '#/definitions/domain.AnalyticsLabelCount'
type: array
by_status:
items:
$ref: '#/definitions/domain.AnalyticsLabelCount'
type: array
total_members:
type: integer
type: object
domain.AnalyticsTimePoint:
properties:
count:
type: integer
date:
type: string
type: object
domain.AnalyticsUsersSection:
properties:
by_age_group:
items:
$ref: '#/definitions/domain.AnalyticsLabelCount'
type: array
by_country:
items:
$ref: '#/definitions/domain.AnalyticsLabelCount'
type: array
by_education_level:
items:
$ref: '#/definitions/domain.AnalyticsLabelCount'
type: array
by_knowledge_level:
items:
$ref: '#/definitions/domain.AnalyticsLabelCount'
type: array
by_language_challange:
items:
$ref: '#/definitions/domain.AnalyticsLabelCount'
type: array
by_learning_goal:
items:
$ref: '#/definitions/domain.AnalyticsLabelCount'
type: array
by_occupation:
items:
$ref: '#/definitions/domain.AnalyticsLabelCount'
type: array
by_region:
items:
$ref: '#/definitions/domain.AnalyticsLabelCount'
type: array
by_role:
items:
$ref: '#/definitions/domain.AnalyticsLabelCount'
type: array
by_status:
items:
$ref: '#/definitions/domain.AnalyticsLabelCount'
type: array
new_month:
type: integer
new_today:
type: integer
new_week:
type: integer
registrations_last_30_days:
items:
$ref: '#/definitions/domain.AnalyticsTimePoint'
type: array
total_users:
type: integer
type: object
domain.AnalyticsVideoDropOffPoint:
properties:
checkpoint_percent:
type: integer
drop_off_rate:
type: number
total_sessions:
type: integer
viewers_reached:
type: integer
type: object
domain.AnalyticsVideosSection:
properties:
completed_sessions:
type: integer
completion_rate:
type: number
drop_off_by_checkpoint:
items:
$ref: '#/definitions/domain.AnalyticsVideoDropOffPoint'
type: array
replay_rate:
type: number
replay_sessions:
type: integer
total_watch_sessions:
type: integer
unique_video_starts:
type: integer
users_who_replayed:
type: integer
type: object
domain.BulkAccountsByRoleRequest:
properties:
exclude_team_member_id:
type: integer
type: object
domain.CreateCourseInput:
properties:
description:
type: string
name:
type: string
sort_order:
description: SortOrder within the program when set; omit to append after current
max within program_id (uniqueness is per-program).
minimum: 0
type: integer
thumbnail:
type: string
required:
- name
type: object
domain.CreateExamPrepCatalogCourseInput:
properties:
category:
enum:
- IELTS
- DUOLINGO
type: string
description:
type: string
name:
type: string
thumbnail:
type: string
required:
- category
- name
type: object
domain.CreateExamPrepLessonInput:
properties:
description:
type: string
thumbnail:
type: string
title:
type: string
video_url:
type: string
required:
- title
type: object
domain.CreateExamPrepModuleInput:
properties:
description:
type: string
icon:
type: string
name:
type: string
thumbnail:
type: string
required:
- name
type: object
domain.CreateExamPrepPracticeInput:
properties:
persona_id:
type: integer
publish_status:
enum:
- DRAFT
- draft
- PUBLISHED
- published
type: string
question_set_id:
type: integer
quick_tips:
type: string
story_description:
type: string
story_image:
type: string
title:
type: string
required:
- question_set_id
type: object
domain.CreateExamPrepUnitInput:
properties:
description:
type: string
name:
type: string
sort_order:
description: SortOrder within the catalog course when set; omit to append
after current max sort_order within catalog_course_id.
minimum: 0
type: integer
thumbnail:
type: string
required:
- name
type: object
domain.CreateLessonInput:
properties:
description:
type: string
publish_status:
description: Omit or empty defaults to DRAFT; set PUBLISHED to make visible
to learners immediately.
enum:
- DRAFT
- draft
- PUBLISHED
- published
type: string
sort_order:
description: SortOrder within the module when set; omit to append after current
max within module_id.
minimum: 0
type: integer
thumbnail:
type: string
title:
type: string
video_url:
type: string
required:
- title
type: object
domain.CreateLmsPersonaInput:
properties:
description:
type: string
gender:
type: string
is_active:
type: boolean
name:
type: string
profile_picture:
type: string
required:
- name
type: object
domain.CreateModuleInput:
properties:
description:
type: string
icon:
type: string
name:
type: string
sort_order:
description: SortOrder within the course when set; omit to append after current
max within course_id (uniqueness is per-course).
minimum: 0
type: integer
required:
- name
type: object
domain.CreatePracticeInput:
properties:
parent_id:
type: integer
parent_kind:
allOf:
- $ref: '#/definitions/domain.ParentKind'
enum:
- COURSE
- MODULE
- LESSON
persona_id:
type: integer
publish_status:
description: Omit or empty for backward compatibility defaults to PUBLISHED;
set DRAFT to save hidden from learners until published.
enum:
- DRAFT
- draft
- PUBLISHED
- published
type: string
question_set_id:
type: integer
quick_tips:
type: string
story_description:
type: string
story_image:
type: string
title:
type: string
required:
- parent_id
- parent_kind
- question_set_id
type: object
domain.CreateProgramInput:
properties:
category:
enum:
- LEARN_ENGLISH
- IELTS
- DUOLINGO
type: string
description:
type: string
name:
type: string
sort_order:
description: SortOrder inserts at this global program order when set; omit
to append after current max (sort_order uniqueness is enforced).
minimum: 0
type: integer
thumbnail:
type: string
required:
- category
- name
type: object
domain.CreateRoleReq:
properties:
description:
type: string
name:
maxLength: 100
minLength: 2
type: string
required:
- name
type: object
domain.CreateTeamMemberReq:
properties:
bio:
type: string
department:
type: string
email:
type: string
emergency_contact:
type: string
employment_type:
type: string
first_name:
type: string
hire_date:
description: YYYY-MM-DD
type: string
job_title:
type: string
last_name:
type: string
password:
minLength: 8
type: string
permissions:
items:
type: string
type: array
phone_number:
type: string
profile_picture_url:
type: string
team_role:
type: string
work_phone:
type: string
required:
- email
- first_name
- last_name
- password
- team_role
type: object
domain.DynamicElementDefinition:
properties:
config:
additionalProperties: true
type: object
id:
type: string
kind:
type: string
label:
type: string
required:
type: boolean
type: object
domain.DynamicElementInstance:
properties:
id:
type: string
kind:
type: string
meta:
additionalProperties: true
type: object
value: {}
type: object
domain.DynamicQuestionPayload:
properties:
response:
items:
$ref: '#/definitions/domain.DynamicElementInstance'
type: array
stimulus:
items:
$ref: '#/definitions/domain.DynamicElementInstance'
type: array
type: object
domain.EmploymentType:
enum:
- full_time
- part_time
- contract
- intern
type: string
x-enum-varnames:
- EmploymentTypeFullTime
- EmploymentTypePartTime
- EmploymentTypeContract
- EmploymentTypeIntern
domain.ErrorResponse:
properties:
error:
type: string
message:
type: string
type: object
domain.InviteTeamMemberReq:
properties:
email:
type: string
team_role:
type: string
required:
- email
- team_role
type: object
domain.LogEntry:
properties:
caller:
type: string
env:
type: string
fields:
additionalProperties: true
type: object
level:
type: string
message:
type: string
service:
type: string
stacktrace:
type: string
timestamp:
type: string
type: object
domain.LogResponse:
properties:
data:
items:
$ref: '#/definitions/domain.LogEntry'
type: array
message:
type: string
pagination:
$ref: '#/definitions/domain.Pagination'
type: object
domain.LoginRequest:
properties:
email:
type: string
otp_code:
type: string
password:
type: string
phone_number:
type: string
type: object
domain.OtpMedium:
enum:
- email
- sms
type: string
x-enum-varnames:
- OtpMediumEmail
- OtpMediumSms
domain.Pagination:
properties:
current_page:
type: integer
limit:
type: integer
total:
type: integer
total_pages:
type: integer
type: object
domain.ParentKind:
enum:
- COURSE
- MODULE
- LESSON
type: string
x-enum-varnames:
- ParentKindCourse
- ParentKindModule
- ParentKindLesson
domain.Permission:
properties:
created_at:
type: string
description:
type: string
group_name:
type: string
id:
type: integer
key:
type: string
name:
type: string
type: object
domain.QuestionAudioAnswer:
properties:
correctAnswerText:
type: string
createdAt:
type: string
id:
format: int64
type: integer
questionID:
format: int64
type: integer
type: object
domain.QuestionOption:
properties:
createdAt:
type: string
id:
format: int64
type: integer
isCorrect:
type: boolean
optionOrder:
format: int32
type: integer
optionText:
type: string
questionID:
format: int64
type: integer
type: object
domain.QuestionShortAnswer:
properties:
acceptableAnswer:
type: string
createdAt:
type: string
id:
format: int64
type: integer
matchType:
type: string
questionID:
format: int64
type: integer
type: object
domain.QuestionWithDetails:
properties:
audioAnswer:
$ref: '#/definitions/domain.QuestionAudioAnswer'
createdAt:
type: string
difficultyLevel:
type: string
dynamicPayload:
$ref: '#/definitions/domain.DynamicQuestionPayload'
explanation:
type: string
id:
format: int64
type: integer
imageURL:
type: string
options:
items:
$ref: '#/definitions/domain.QuestionOption'
type: array
points:
format: int32
type: integer
questionText:
type: string
questionType:
type: string
questionTypeDefinitionID:
format: int64
type: integer
sampleAnswerVoicePrompt:
type: string
shortAnswers:
items:
$ref: '#/definitions/domain.QuestionShortAnswer'
type: array
status:
type: string
tips:
type: string
updatedAt:
type: string
voicePrompt:
type: string
type: object
domain.RegisterUserReq:
properties:
email:
type: string
otp_medium:
$ref: '#/definitions/domain.OtpMedium'
password:
type: string
phone_number:
type: string
role:
type: string
type: object
domain.ReorderIDsRequest:
properties:
ordered_ids:
items:
type: integer
type: array
type: object
domain.ResendOtpReq:
properties:
email:
type: string
phone_number:
type: string
type: object
domain.Response:
properties:
data: {}
message:
type: string
metadata: {}
status_code:
type: integer
success:
type: boolean
type: object
domain.Role:
enum:
- SUPER_ADMIN
- ADMIN
- STUDENT
- OPEN_LEARNER
- INSTRUCTOR
- SUPPORT
type: string
x-enum-varnames:
- RoleSuperAdmin
- RoleAdmin
- RoleStudent
- RoleOpenLearner
- RoleInstructor
- RoleSupport
domain.RoleRecord:
properties:
created_at:
type: string
description:
type: string
id:
type: integer
is_system:
type: boolean
name:
type: string
updated_at:
type: string
type: object
domain.RoleWithPermissions:
properties:
created_at:
type: string
description:
type: string
id:
type: integer
is_system:
type: boolean
name:
type: string
permissions:
items:
$ref: '#/definitions/domain.Permission'
type: array
updated_at:
type: string
type: object
domain.SetRolePermissionsReq:
properties:
permission_ids:
items:
type: integer
type: array
required:
- permission_ids
type: object
domain.TeamMemberLoginReq:
properties:
email:
type: string
password:
type: string
required:
- email
- password
type: object
domain.TeamMemberResponse:
properties:
bio:
type: string
created_at:
type: string
department:
type: string
email:
type: string
email_verified:
type: boolean
employment_type:
$ref: '#/definitions/domain.EmploymentType'
first_name:
type: string
hire_date:
type: string
id:
type: integer
job_title:
type: string
last_login:
type: string
last_name:
type: string
permissions:
items:
type: string
type: array
phone_number:
type: string
profile_picture_url:
type: string
status:
$ref: '#/definitions/domain.TeamMemberStatus'
team_role:
$ref: '#/definitions/domain.TeamRole'
updated_at:
type: string
work_phone:
type: string
type: object
domain.TeamMemberStats:
properties:
active_count:
type: integer
inactive_count:
type: integer
suspended_count:
type: integer
terminated_count:
type: integer
total_count:
type: integer
type: object
domain.TeamMemberStatus:
enum:
- active
- inactive
- suspended
- terminated
type: string
x-enum-varnames:
- TeamMemberStatusActive
- TeamMemberStatusInactive
- TeamMemberStatusSuspended
- TeamMemberStatusTerminated
domain.TeamRole:
enum:
- SUPER_ADMIN
- ADMIN
- CONTENT_MANAGER
- SUPPORT_AGENT
- INSTRUCTOR
- FINANCE
- HR
- ANALYST
type: string
x-enum-varnames:
- TeamRoleSuperAdmin
- TeamRoleAdmin
- TeamRoleContentManager
- TeamRoleSupportAgent
- TeamRoleInstructor
- TeamRoleFinance
- TeamRoleHR
- TeamRoleAnalyst
domain.UpdateCourseInput:
properties:
description:
type: string
name:
type: string
sort_order:
type: integer
thumbnail:
type: string
type: object
domain.UpdateExamPrepCatalogCourseInput:
properties:
category:
enum:
- IELTS
- DUOLINGO
type: string
description:
type: string
name:
type: string
sort_order:
type: integer
thumbnail:
type: string
type: object
domain.UpdateExamPrepPracticeInput:
properties:
persona_id:
type: integer
publish_status:
enum:
- DRAFT
- draft
- PUBLISHED
- published
type: string
question_set_id:
type: integer
quick_tips:
type: string
story_description:
type: string
story_image:
type: string
title:
type: string
type: object
domain.UpdateExamPrepUnitInput:
properties:
description:
type: string
name:
type: string
sort_order:
type: integer
thumbnail:
type: string
type: object
domain.UpdateKnowledgeLevelReq:
properties:
knowledge_level:
description: BEGINNER, INTERMEDIATE, ADVANCED
type: string
user_id:
type: integer
type: object
domain.UpdateLessonInput:
properties:
description:
type: string
publish_status:
enum:
- DRAFT
- draft
- PUBLISHED
- published
type: string
sort_order:
type: integer
thumbnail:
type: string
title:
type: string
video_url:
type: string
type: object
domain.UpdateLmsPersonaInput:
properties:
description:
type: string
gender:
type: string
is_active:
type: boolean
name:
type: string
profile_picture:
type: string
type: object
domain.UpdateModuleInput:
properties:
description:
type: string
icon:
type: string
name:
type: string
sort_order:
type: integer
type: object
domain.UpdatePracticeInput:
properties:
persona_id:
type: integer
publish_status:
enum:
- DRAFT
- draft
- PUBLISHED
- published
type: string
question_set_id:
type: integer
quick_tips:
type: string
story_description:
type: string
story_image:
type: string
title:
type: string
type: object
domain.UpdateProgramInput:
properties:
category:
enum:
- LEARN_ENGLISH
- IELTS
- DUOLINGO
type: string
description:
type: string
name:
type: string
sort_order:
type: integer
thumbnail:
type: string
type: object
domain.UpdateRoleReq:
properties:
description:
type: string
name:
maxLength: 100
minLength: 2
type: string
required:
- name
type: object
domain.UpdateTeamMemberReq:
properties:
bio:
type: string
department:
type: string
emergency_contact:
type: string
employment_type:
type: string
first_name:
type: string
hire_date:
type: string
job_title:
type: string
last_name:
type: string
permissions:
items:
type: string
type: array
phone_number:
type: string
profile_picture_url:
type: string
team_role:
type: string
work_phone:
type: string
type: object
domain.UpdateTeamMemberStatusReq:
properties:
status:
type: string
required:
- status
type: object
domain.UpdateUserReq:
properties:
age_group:
$ref: '#/definitions/domain.AgeGroup'
birth_day:
description: YYYY-MM-DD
type: string
country:
type: string
education_level:
type: string
favourite_topic:
type: string
first_name:
type: string
gender:
type: string
initial_assessment_completed:
type: boolean
knowledge_level:
type: string
language_challange:
type: string
language_goal:
type: string
last_name:
type: string
learning_goal:
type: string
nick_name:
type: string
occupation:
type: string
preferred_language:
type: string
profile_picture_url:
type: string
region:
type: string
type: object
domain.UserProfileResponse:
properties:
age_group:
type: string
birth_day:
description: formatted as YYYY-MM-DD
type: string
country:
type: string
created_at:
type: string
education_level:
type: string
email:
description: UserName string `json:"user_name,omitempty"`
type: string
email_verified:
type: boolean
favoutite_topic:
type: string
first_name:
type: string
gender:
type: string
id:
type: integer
initial_assessment_completed:
description: Profile fields
type: boolean
language_challange:
type: string
language_goal:
type: string
last_login:
type: string
last_name:
type: string
learning_goal:
type: string
nick_name:
type: string
occupation:
type: string
phone_number:
type: string
phone_verified:
type: boolean
preferred_language:
type: string
profile_completed:
type: boolean
profile_completion_percentage:
type: integer
profile_picture_url:
type: string
region:
type: string
role:
$ref: '#/definitions/domain.Role'
status:
$ref: '#/definitions/domain.UserStatus'
subscription_status:
type: string
updated_at:
type: string
type: object
domain.UserStatus:
enum:
- PENDING
- ACTIVE
- SUSPENDED
- DEACTIVATED
type: string
x-enum-varnames:
- UserStatusPending
- UserStatusActive
- UserStatusSuspended
- UserStatusDeactivated
domain.UserSummary:
properties:
active_users:
type: integer
joined_this_month:
type: integer
total_users:
type: integer
type: object
domain.VerifyOtpReq:
properties:
email:
type: string
otp:
type: string
phone_number:
type: string
required:
- otp
type: object
domain.VideoEngagementHeartbeatInput:
properties:
content_id:
type: integer
content_kind:
enum:
- lms_lesson
- exam_prep_lesson
type: string
duration_sec:
minimum: 0
type: integer
ended:
type: boolean
position_sec:
minimum: 0
type: integer
required:
- content_id
- content_kind
type: object
domain.VideoWatchSessionResponse:
properties:
completed:
type: boolean
max_position_sec:
type: integer
session_id:
type: integer
session_number:
type: integer
type: object
domain.WebhookRequest:
properties:
nonce:
type: string
notificationUrl:
type: string
paymentMethod:
type: string
phone:
type: string
sessionId:
type: string
totalAmount:
type: integer
transaction:
properties:
transactionId:
type: string
transactionStatus:
type: string
type: object
transactionStatus:
type: string
uuid:
type: string
type: object
handlers.AdminProfileRes:
properties:
created_at:
type: string
email:
type: string
email_verified:
type: boolean
first_name:
type: string
id:
type: integer
last_login:
type: string
last_name:
type: string
phone_number:
type: string
phone_verified:
type: boolean
role:
$ref: '#/definitions/domain.Role'
suspended:
type: boolean
suspended_at:
type: string
updated_at:
type: string
type: object
handlers.AdminRes:
properties:
created_at:
type: string
email:
type: string
email_verified:
type: boolean
first_name:
type: string
id:
type: integer
last_login:
type: string
last_name:
type: string
phone_number:
type: string
phone_verified:
type: boolean
role:
$ref: '#/definitions/domain.Role'
suspended:
type: boolean
suspended_at:
type: string
updated_at:
type: string
type: object
handlers.CheckPhoneEmailExistReq:
properties:
email:
example: john.doe@example.com
type: string
phone_number:
example: "1234567890"
type: string
type: object
handlers.CheckPhoneEmailExistRes:
properties:
email_exist:
type: boolean
phone_number_exist:
type: boolean
type: object
handlers.CreateAdminReq:
properties:
email:
example: john.doe@example.com
type: string
first_name:
example: John
type: string
last_name:
example: Doe
type: string
password:
example: password123
type: string
phone_number:
example: "1234567890"
type: string
type: object
handlers.CreatePullUploadRequest:
properties:
description:
type: string
file_size:
type: integer
name:
type: string
source_url:
type: string
required:
- file_size
- name
- source_url
type: object
handlers.CreateTusUploadRequest:
properties:
description:
type: string
file_size:
type: integer
name:
type: string
required:
- file_size
- name
type: object
handlers.LoginAdminRes:
properties:
access_token:
type: string
refresh_token:
type: string
role:
type: string
type: object
handlers.RegisterCodeReq:
properties:
email:
example: john.doe@example.com
type: string
phone_number:
example: "1234567890"
type: string
type: object
handlers.ResetCodeReq:
properties:
email:
example: john.doe@example.com
type: string
phone_number:
example: "1234567890"
type: string
type: object
handlers.ResetPasswordReq:
properties:
email:
example: john.doe@example.com
type: string
otp:
example: "123456"
type: string
password:
example: newpassword123
minLength: 8
type: string
phone_number:
example: "1234567890"
type: string
required:
- otp
- password
type: object
handlers.SearchUserByNameOrPhoneReq:
properties:
query:
type: string
role:
$ref: '#/definitions/domain.Role'
type: object
handlers.SendSingleAfroSMSReq:
properties:
message:
example: Hello world
type: string
recipient:
example: "+251912345678"
type: string
required:
- message
- recipient
type: object
handlers.VimeoEmbedResponse:
properties:
embed_html:
type: string
embed_url:
type: string
video_id:
type: string
type: object
handlers.VimeoUploadResponse:
properties:
link:
type: string
status:
type: string
upload_link:
type: string
uri:
type: string
vimeo_id:
type: string
type: object
handlers.VimeoVideoResponse:
properties:
description:
type: string
duration:
type: integer
embed_html:
type: string
embed_url:
type: string
height:
type: integer
link:
type: string
name:
type: string
status:
type: string
thumbnail_url:
type: string
transcode_status:
type: string
uri:
type: string
vimeo_id:
type: string
width:
type: integer
type: object
handlers.VimeoVideosListMetadata:
properties:
current_page:
type: integer
first:
type: string
last:
type: string
limit:
type: integer
next:
type: string
previous:
type: string
total:
type: integer
total_pages:
type: integer
type: object
handlers.addQuestionToSetReq:
properties:
display_order:
type: integer
question_id:
type: integer
required:
- question_id
type: object
handlers.addUserPersonaReq:
properties:
display_order:
type: integer
user_id:
type: integer
required:
- user_id
type: object
handlers.autoRenewReq:
properties:
auto_renew:
type: boolean
type: object
handlers.changePasswordReq:
properties:
current_password:
example: oldpassword123
type: string
new_password:
example: newpassword123
minLength: 8
type: string
required:
- current_password
- new_password
type: object
handlers.createEmailTemplateReq:
properties:
body_html:
type: string
body_text:
type: string
name:
type: string
slug:
type: string
status:
type: string
subject:
type: string
variables:
items:
type: string
type: array
required:
- body_html
- body_text
- name
- slug
- subject
type: object
handlers.createFAQReq:
properties:
answer:
type: string
category:
type: string
display_order:
type: integer
question:
type: string
status:
type: string
required:
- answer
- question
type: object
handlers.createFieldOptionReq:
properties:
code:
type: string
display_order:
type: integer
field_key:
type: string
label:
type: string
status:
type: string
required:
- code
- field_key
- label
type: object
handlers.createIssueReq:
properties:
description:
type: string
issue_type:
type: string
metadata:
additionalProperties: true
type: object
subject:
type: string
required:
- description
- issue_type
- subject
type: object
handlers.createMobileAppVersionReq:
properties:
min_supported_version_code:
type: integer
platform:
type: string
release_notes:
type: string
status:
type: string
store_url:
type: string
update_type:
type: string
version_code:
minimum: 1
type: integer
version_name:
type: string
required:
- platform
- version_code
- version_name
type: object
handlers.createPlanReq:
properties:
category:
enum:
- LEARN_ENGLISH
- IELTS
- DUOLINGO
type: string
currency:
type: string
description:
type: string
duration_unit:
enum:
- DAY
- WEEK
- MONTH
- YEAR
type: string
duration_value:
minimum: 1
type: integer
is_active:
type: boolean
name:
type: string
price:
minimum: 0
type: number
required:
- category
- currency
- duration_unit
- duration_value
- name
- price
type: object
handlers.createQuestionReq:
properties:
audio_correct_answer_text:
type: string
difficulty_level:
type: string
dynamic_payload:
$ref: '#/definitions/domain.DynamicQuestionPayload'
explanation:
type: string
image_url:
type: string
options:
items:
$ref: '#/definitions/handlers.optionInput'
type: array
points:
type: integer
question_text:
type: string
question_type:
type: string
question_type_definition_id:
type: integer
sample_answer_voice_prompt:
type: string
short_answers:
items:
$ref: '#/definitions/handlers.shortAnswerInput'
type: array
status:
type: string
tips:
type: string
voice_prompt:
type: string
type: object
handlers.createQuestionSetReq:
properties:
banner_image:
type: string
description:
type: string
intro_video_url:
type: string
owner_id:
type: integer
owner_type:
type: string
passing_score:
type: integer
persona:
type: string
set_type:
enum:
- PRACTICE
- INITIAL_ASSESSMENT
- QUIZ
- EXAM
- SURVEY
- CAPSTONE
type: string
shuffle_questions:
type: boolean
status:
type: string
time_limit_minutes:
type: integer
title:
type: string
required:
- set_type
- title
type: object
handlers.createQuestionTypeDefinitionReq:
properties:
description:
type: string
display_name:
type: string
key:
type: string
response_component_kinds:
items:
type: string
type: array
response_schema:
items:
$ref: '#/definitions/domain.DynamicElementDefinition'
type: array
status:
type: string
stimulus_component_kinds:
items:
type: string
type: array
stimulus_schema:
items:
$ref: '#/definitions/domain.DynamicElementDefinition'
type: array
required:
- display_name
- key
type: object
handlers.initiateDirectPaymentReq:
properties:
email:
type: string
payment_method:
type: string
phone:
type: string
plan_id:
type: integer
required:
- email
- payment_method
- phone
- plan_id
type: object
handlers.initiatePaymentReq:
properties:
email:
type: string
phone:
type: string
plan_id:
type: integer
provider:
type: string
required:
- email
- phone
- plan_id
- provider
type: object
handlers.issueListRes:
properties:
issues:
items:
$ref: '#/definitions/handlers.issueRes'
type: array
total_count:
type: integer
type: object
handlers.issueRes:
properties:
created_at:
type: string
description:
type: string
id:
type: integer
issue_type:
type: string
metadata:
additionalProperties: true
type: object
status:
type: string
subject:
type: string
updated_at:
type: string
user_id:
type: integer
user_role:
type: string
type: object
handlers.loginUserRes:
properties:
access_token:
type: string
refresh_token:
type: string
role:
type: string
user_id:
type: integer
type: object
handlers.logoutReq:
properties:
device_token:
example: <fcm-device-token>
type: string
refresh_token:
example: <refresh-token>
type: string
required:
- refresh_token
type: object
handlers.optionInput:
properties:
is_correct:
type: boolean
option_order:
type: integer
option_text:
type: string
required:
- option_text
type: object
handlers.previewEmailTemplateReq:
properties:
variables:
additionalProperties: {}
type: object
type: object
handlers.refreshFileURLReq:
properties:
reference:
type: string
type: object
handlers.refreshToken:
properties:
access_token:
example: <jwt-token>
type: string
refresh_token:
example: <refresh-token>
type: string
required:
- access_token
- refresh_token
type: object
handlers.shortAnswerInput:
properties:
acceptable_answer:
type: string
match_type:
type: string
required:
- acceptable_answer
type: object
handlers.submitRatingReq:
properties:
review:
type: string
stars:
maximum: 5
minimum: 1
type: integer
target_id:
type: integer
target_type:
type: string
required:
- stars
- target_type
type: object
handlers.subscribeReq:
properties:
payment_method:
type: string
payment_reference:
type: string
plan_id:
type: integer
required:
- plan_id
type: object
handlers.subscribeWithPaymentReq:
properties:
email:
type: string
phone:
type: string
plan_id:
type: integer
provider:
type: string
required:
- email
- phone
- plan_id
- provider
type: object
handlers.teamMemberLoginRes:
properties:
access_token:
example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
type: string
member_id:
example: 1
type: integer
refresh_token:
example: <opaque-refresh-token>
type: string
team_role:
example: admin
type: string
type: object
handlers.teamMemberRefreshReq:
properties:
refresh_token:
type: string
required:
- refresh_token
type: object
handlers.updateAdminReq:
properties:
first_name:
example: John
type: string
last_name:
example: Doe
type: string
suspended:
example: false
type: boolean
type: object
handlers.updateEmailTemplateReq:
properties:
body_html:
type: string
body_text:
type: string
name:
type: string
status:
type: string
subject:
type: string
variables:
items:
type: string
type: array
type: object
handlers.updateFAQReq:
properties:
answer:
type: string
category:
type: string
display_order:
type: integer
question:
type: string
status:
type: string
type: object
handlers.updateFieldOptionReq:
properties:
display_order:
type: integer
label:
type: string
status:
type: string
type: object
handlers.updateIssueStatusReq:
properties:
status:
enum:
- pending
- in_progress
- resolved
- rejected
type: string
required:
- status
type: object
handlers.updateMobileAppVersionReq:
properties:
min_supported_version_code:
type: integer
release_notes:
type: string
status:
type: string
store_url:
type: string
update_type:
type: string
version_code:
type: integer
version_name:
type: string
type: object
handlers.updatePlanReq:
properties:
category:
enum:
- LEARN_ENGLISH
- IELTS
- DUOLINGO
type: string
currency:
type: string
description:
type: string
duration_unit:
type: string
duration_value:
type: integer
is_active:
type: boolean
name:
type: string
price:
type: number
type: object
handlers.updateQuestionOrderReq:
properties:
display_order:
type: integer
required:
- display_order
type: object
handlers.updateQuestionReq:
properties:
audio_correct_answer_text:
type: string
difficulty_level:
type: string
dynamic_payload:
$ref: '#/definitions/domain.DynamicQuestionPayload'
explanation:
type: string
image_url:
type: string
options:
items:
$ref: '#/definitions/handlers.optionInput'
type: array
points:
type: integer
question_text:
type: string
question_type:
type: string
question_type_definition_id:
type: integer
sample_answer_voice_prompt:
type: string
short_answers:
items:
$ref: '#/definitions/handlers.shortAnswerInput'
type: array
status:
type: string
tips:
type: string
voice_prompt:
type: string
type: object
handlers.updateQuestionSetReq:
properties:
banner_image:
type: string
description:
type: string
intro_video_url:
type: string
passing_score:
type: integer
persona:
type: string
shuffle_questions:
type: boolean
status:
type: string
time_limit_minutes:
type: integer
title:
type: string
type: object
handlers.updateQuestionTypeDefinitionReq:
properties:
description:
type: string
display_name:
type: string
response_component_kinds:
items:
type: string
type: array
response_schema:
items:
$ref: '#/definitions/domain.DynamicElementDefinition'
type: array
status:
type: string
stimulus_component_kinds:
items:
type: string
type: array
stimulus_schema:
items:
$ref: '#/definitions/domain.DynamicElementDefinition'
type: array
type: object
handlers.validateQuestionTypeDefinitionReq:
properties:
response_component_kinds:
items:
type: string
type: array
stimulus_component_kinds:
items:
type: string
type: array
type: object
handlers.verifyOTPReq:
properties:
otp:
type: string
session_id:
type: string
required:
- otp
- session_id
type: object
response.APIResponse:
properties:
data: {}
message:
type: string
metadata: {}
page:
type: integer
status:
$ref: '#/definitions/response.Status'
timestamp:
type: string
total:
type: integer
type: object
response.Status:
enum:
- error
- success
type: string
x-enum-varnames:
- Error
- Success
vimeo.OEmbedResponse:
properties:
author_name:
type: string
author_url:
type: string
description:
type: string
duration:
type: integer
height:
type: integer
html:
type: string
is_plus:
type: string
provider_name:
type: string
provider_url:
type: string
thumbnail_height:
type: integer
thumbnail_url:
type: string
thumbnail_width:
type: integer
title:
type: string
type:
type: string
version:
type: string
video_id:
type: integer
width:
type: integer
type: object
info:
contact:
email: support@swagger.io
name: API Support
url: http://www.swagger.io/support
description: This is server for Yimaru.
license:
name: Apache 2.0
url: http://www.apache.org/licenses/LICENSE-2.0.html
termsOfService: http://swagger.io/terms/
title: Yimaru API
version: 1.0.1
paths:
/api/v1/{tenant_slug}/admin-login:
post:
consumes:
- application/json
description: Login user
parameters:
- description: Login admin
in: body
name: login
required: true
schema:
$ref: '#/definitions/domain.LoginRequest'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/handlers.LoginAdminRes'
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.APIResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/response.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.APIResponse'
summary: Login user
tags:
- auth
/api/v1/{tenant_slug}/otp/resend:
post:
consumes:
- application/json
description: Resend OTP if the previous one is expired
parameters:
- description: Resend OTP
in: body
name: resendOtp
required: true
schema:
$ref: '#/definitions/domain.ResendOtpReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.APIResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.APIResponse'
summary: Resend OTP
tags:
- otp
/api/v1/{tenant_slug}/user-login:
post:
consumes:
- application/json
description: Login user
parameters:
- description: Login user
in: body
name: login
required: true
schema:
$ref: '#/definitions/domain.LoginRequest'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/handlers.loginUserRes'
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.APIResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/response.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.APIResponse'
summary: Login user
tags:
- auth
/api/v1/{tenant_slug}/user/admin-profile:
get:
consumes:
- application/json
description: Get user profile
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/handlers.AdminProfileRes'
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.APIResponse'
security:
- Bearer: []
summary: Get user profile
tags:
- user
/api/v1/{tenant_slug}/user/checkPhoneEmailExist:
post:
consumes:
- application/json
description: Check if phone number or email exist
parameters:
- description: Check phone number or email exist
in: body
name: checkPhoneEmailExist
required: true
schema:
$ref: '#/definitions/handlers.CheckPhoneEmailExistReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/handlers.CheckPhoneEmailExistRes'
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.APIResponse'
summary: Check if phone number or email exist
tags:
- user
/api/v1/{tenant_slug}/user/knowledge-level:
put:
consumes:
- application/json
description: Updates the knowledge level of the specified user after initial
assessment
parameters:
- description: User ID
in: path
name: user_id
required: true
type: integer
- description: Knowledge level
in: body
name: knowledge_level
required: true
schema:
$ref: '#/definitions/domain.UpdateKnowledgeLevelReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Update user's knowledge level
tags:
- user
/api/v1/{tenant_slug}/user/register:
post:
consumes:
- application/json
description: Register user
parameters:
- description: Register user
in: body
name: registerUser
required: true
schema:
$ref: '#/definitions/domain.RegisterUserReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.APIResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.APIResponse'
summary: Register user
tags:
- user
/api/v1/{tenant_slug}/user/resetPassword:
post:
consumes:
- application/json
description: Reset tenant password
parameters:
- description: Reset password
in: body
name: resetPassword
required: true
schema:
$ref: '#/definitions/handlers.ResetPasswordReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.APIResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.APIResponse'
summary: Reset tenant password
tags:
- user
/api/v1/{tenant_slug}/user/sendRegisterCode:
post:
consumes:
- application/json
description: Send register code
parameters:
- description: Send register code
in: body
name: registerCode
required: true
schema:
$ref: '#/definitions/handlers.RegisterCodeReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.APIResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.APIResponse'
summary: Send register code
tags:
- user
/api/v1/{tenant_slug}/user/sendResetCode:
post:
consumes:
- application/json
description: Send reset code
parameters:
- description: Send reset code
in: body
name: resetCode
required: true
schema:
$ref: '#/definitions/handlers.ResetCodeReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.APIResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.APIResponse'
summary: Send reset code
tags:
- user
/api/v1/{tenant_slug}/user/user-profile:
get:
consumes:
- application/json
description: Get user profile
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.UserProfileResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.APIResponse'
security:
- Bearer: []
summary: Get user profile
tags:
- user
/api/v1/activity-logs:
get:
description: Returns a filtered, paginated list of activity logs
parameters:
- description: Filter by actor ID
in: query
name: actor_id
type: integer
- description: Filter by action
in: query
name: action
type: string
- description: Filter by resource type
in: query
name: resource_type
type: string
- description: Filter by resource ID
in: query
name: resource_id
type: integer
- description: Filter logs after this RFC3339 timestamp
in: query
name: after
type: string
- description: Filter logs before this RFC3339 timestamp
in: query
name: before
type: string
- default: 20
description: Limit
in: query
name: limit
type: integer
- default: 0
description: Offset
in: query
name: offset
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Get activity logs
tags:
- activity-logs
/api/v1/activity-logs/{id}:
get:
description: Returns a single activity log entry by its ID
parameters:
- description: Activity Log ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Get activity log by ID
tags:
- activity-logs
/api/v1/admin:
get:
consumes:
- application/json
description: Get all Admins
parameters:
- description: Page number
in: query
name: page
type: integer
- description: Page size
in: query
name: page_size
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/handlers.AdminRes'
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.APIResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/response.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.APIResponse'
summary: Get all Admins
tags:
- admin
post:
consumes:
- application/json
description: Create Admin
parameters:
- description: Create admin
in: body
name: manger
required: true
schema:
$ref: '#/definitions/handlers.CreateAdminReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.APIResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.APIResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/response.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.APIResponse'
summary: Create Admin
tags:
- admin
/api/v1/admin/{id}:
get:
consumes:
- application/json
description: Get a single admin by id
parameters:
- description: User ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/handlers.AdminRes'
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.APIResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/response.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.APIResponse'
summary: Get admin by id
tags:
- admin
put:
consumes:
- application/json
description: Update Admin
parameters:
- description: Update Admin
in: body
name: admin
required: true
schema:
$ref: '#/definitions/handlers.updateAdminReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.APIResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.APIResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/response.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.APIResponse'
summary: Update Admin
tags:
- admin
/api/v1/admin/app-versions:
get:
parameters:
- description: Filter by ANDROID or IOS
in: query
name: platform
type: string
- description: Filter by ACTIVE or INACTIVE
in: query
name: status
type: string
- description: Limit (default 20)
in: query
name: limit
type: integer
- description: Offset (default 0)
in: query
name: offset
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
security:
- Bearer: []
summary: List mobile app versions (admin)
tags:
- app-versions
post:
consumes:
- application/json
parameters:
- description: App version payload
in: body
name: body
required: true
schema:
$ref: '#/definitions/handlers.createMobileAppVersionReq'
produces:
- application/json
responses:
"201":
description: Created
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
security:
- Bearer: []
summary: Create mobile app version (admin)
tags:
- app-versions
/api/v1/admin/app-versions/{id}:
delete:
parameters:
- description: App version ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
security:
- Bearer: []
summary: Delete mobile app version (admin)
tags:
- app-versions
get:
parameters:
- description: App version ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
security:
- Bearer: []
summary: Get mobile app version by ID (admin)
tags:
- app-versions
put:
consumes:
- application/json
parameters:
- description: App version ID
in: path
name: id
required: true
type: integer
- description: App version payload
in: body
name: body
required: true
schema:
$ref: '#/definitions/handlers.updateMobileAppVersionReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
security:
- Bearer: []
summary: Update mobile app version (admin)
tags:
- app-versions
/api/v1/admin/email-templates:
get:
description: Returns email templates for admin management
parameters:
- description: ACTIVE or INACTIVE
in: query
name: status
type: string
- description: Search by slug, name, or subject
in: query
name: query
type: string
- description: Limit (default 20)
in: query
name: limit
type: integer
- description: Offset (default 0)
in: query
name: offset
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: List email templates (admin)
tags:
- email-templates
post:
consumes:
- application/json
description: Creates a new custom email template
parameters:
- description: Create email template payload
in: body
name: body
required: true
schema:
$ref: '#/definitions/handlers.createEmailTemplateReq'
produces:
- application/json
responses:
"201":
description: Created
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Create email template
tags:
- email-templates
/api/v1/admin/email-templates/{id}:
delete:
description: Deletes a custom email template
parameters:
- description: Email template ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Delete email template
tags:
- email-templates
get:
description: Returns one email template regardless of status
parameters:
- description: Email template ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Get email template by ID (admin)
tags:
- email-templates
put:
consumes:
- application/json
description: Updates an existing email template
parameters:
- description: Email template ID
in: path
name: id
required: true
type: integer
- description: Update email template payload
in: body
name: body
required: true
schema:
$ref: '#/definitions/handlers.updateEmailTemplateReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Update email template
tags:
- email-templates
/api/v1/admin/email-templates/{id}/preview:
post:
consumes:
- application/json
description: Renders an email template with sample variables without sending
parameters:
- description: Email template ID
in: path
name: id
required: true
type: integer
- description: Preview variables
in: body
name: body
required: true
schema:
$ref: '#/definitions/handlers.previewEmailTemplateReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Preview email template by ID
tags:
- email-templates
/api/v1/admin/email-templates/slug/{slug}:
get:
description: Returns one email template by slug regardless of status
parameters:
- description: Email template slug
in: path
name: slug
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Get email template by slug (admin)
tags:
- email-templates
/api/v1/admin/email-templates/slug/{slug}/preview:
post:
consumes:
- application/json
description: Renders an email template with sample variables without sending
parameters:
- description: Email template slug
in: path
name: slug
required: true
type: string
- description: Preview variables
in: body
name: body
required: true
schema:
$ref: '#/definitions/handlers.previewEmailTemplateReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Preview email template by slug
tags:
- email-templates
/api/v1/admin/faqs:
get:
description: Returns FAQs for admin management with status/category filtering
parameters:
- description: ACTIVE or INACTIVE
in: query
name: status
type: string
- description: Filter by category
in: query
name: category
type: string
- description: Limit (default 20)
in: query
name: limit
type: integer
- description: Offset (default 0)
in: query
name: offset
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: List FAQs (admin)
tags:
- faqs
post:
consumes:
- application/json
description: Creates a new FAQ item
parameters:
- description: Create FAQ payload
in: body
name: body
required: true
schema:
$ref: '#/definitions/handlers.createFAQReq'
produces:
- application/json
responses:
"201":
description: Created
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Create FAQ
tags:
- faqs
/api/v1/admin/faqs/{id}:
delete:
description: Deletes an FAQ item
parameters:
- description: FAQ ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Delete FAQ
tags:
- faqs
get:
description: Returns one FAQ regardless of status
parameters:
- description: FAQ ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Get FAQ by ID (admin)
tags:
- faqs
put:
consumes:
- application/json
description: Updates an existing FAQ item
parameters:
- description: FAQ ID
in: path
name: id
required: true
type: integer
- description: Update FAQ payload
in: body
name: body
required: true
schema:
$ref: '#/definitions/handlers.updateFAQReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Update FAQ
tags:
- faqs
/api/v1/admin/field-options:
get:
parameters:
- description: Filter by field key
in: query
name: field_key
type: string
- description: ACTIVE or INACTIVE
in: query
name: status
type: string
- description: Limit
in: query
name: limit
type: integer
- description: Offset
in: query
name: offset
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
summary: List field options (admin)
tags:
- field-options
post:
consumes:
- application/json
parameters:
- description: Create option
in: body
name: body
required: true
schema:
$ref: '#/definitions/handlers.createFieldOptionReq'
produces:
- application/json
responses:
"201":
description: Created
schema:
$ref: '#/definitions/domain.Response'
summary: Create field option (admin)
tags:
- field-options
/api/v1/admin/field-options/{id}:
delete:
parameters:
- description: Option ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
summary: Delete field option (admin)
tags:
- field-options
get:
parameters:
- description: Option ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
summary: Get field option by ID (admin)
tags:
- field-options
put:
consumes:
- application/json
parameters:
- description: Option ID
in: path
name: id
required: true
type: integer
- description: Update option
in: body
name: body
required: true
schema:
$ref: '#/definitions/handlers.updateFieldOptionReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
summary: Update field option (admin)
tags:
- field-options
/api/v1/admin/roles/{role}/bulk-deactivate:
post:
consumes:
- application/json
description: Sets all platform users with the given users.role to DEACTIVATED
(except the caller) and all team_members with the given team_role to inactive.
Path :role may be a role key (e.g. INSTRUCTOR, ADMIN) or a decimal RBAC roles.id
from GET /api/v1/rbac/roles (resolved to RoleRecord.name uppercased). SUPER_ADMIN
cannot be bulk-deactivated. ADMIN platform users must use SUPER_ADMIN to bulk
change other platform ADMIN users (team_members with team_role ADMIN under
path ADMIN remain allowed). Empty body allowed; optionally pass exclude_team_member_id
to skip one team_members row (e.g. yourself).
parameters:
- description: Role key (INSTRUCTOR etc.) or RBAC roles.id (integer string)
in: path
name: role
required: true
type: string
- description: Optional exclusions
in: body
name: body
schema:
$ref: '#/definitions/domain.BulkAccountsByRoleRequest'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"403":
description: Forbidden
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
security:
- Bearer: []
summary: Bulk deactivate accounts by role (SUPER_ADMIN or ADMIN platform users
only)
tags:
- admin
/api/v1/admin/roles/{role}/bulk-reactivate:
post:
consumes:
- application/json
description: Sets all platform users with the given role from DEACTIVATED to
ACTIVE (except the caller) and all team_members with the given team_role from
inactive to active. Path :role may be a role key or decimal RBAC roles.id
(see bulk-deactivate). Path role must correspond to valid platform users.role
or team_members.team_role (after resolving id → name). SUPER_ADMIN cannot
be bulk changed. ADMIN callers cannot bulk change other platform ADMIN users
(team_members ADMIN under path ADMIN is allowed). Matches only users currently
DEACTIVATED and team rows currently inactive.
parameters:
- description: Role key (INSTRUCTOR etc.) or RBAC roles.id (integer string)
in: path
name: role
required: true
type: string
- description: Optional exclusions
in: body
name: body
schema:
$ref: '#/definitions/domain.BulkAccountsByRoleRequest'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"403":
description: Forbidden
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
security:
- Bearer: []
summary: Bulk reactivate accounts by role (SUPER_ADMIN or ADMIN platform users
only)
tags:
- admin
/api/v1/admin/users/{user_id}/lms-learning-activity:
get:
description: Returns programs, courses, modules, and lessons with completion
details and completed practices. Only persisted completion signals are included
(completed lessons, completed published practices, and rollup completion timestamps—not
partial or in-progress attempts).
parameters:
- description: Target user ID
in: path
name: user_id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
security:
- Bearer: []
summary: Get a user's nested LMS learning activity (admin)
tags:
- lms
/api/v1/admin/users/{user_id}/recent-activity:
get:
description: 'Reverse-chronological feed for profile UI: account joined plus
LMS completion milestones (lessons/modules/courses/programs). Optional practice
completions via include_practices. Does not include "started learning path"
unless you add persisted engagement events—the schema stores completions only.'
parameters:
- description: Target user ID
in: path
name: user_id
required: true
type: integer
- description: Max items after merge (default 40, max 120)
in: query
name: limit
type: integer
- description: Include completed LMS practices (more verbose)
in: query
name: include_practices
type: boolean
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
security:
- Bearer: []
summary: Recent activity timeline for a user (admin)
tags:
- lms
/api/v1/admin/users/deletion-requests:
get:
consumes:
- application/json
description: Returns account deletion requests for admin panel tracking with
filtering and pagination
parameters:
- description: Search in first_name, last_name, email, phone_number
in: query
name: query
type: string
- description: Role filter
in: query
name: role
type: string
- description: User status filter (ACTIVE, PENDING, SUSPENDED, DEACTIVATED)
in: query
name: status
type: string
- description: Deletion state filter (PENDING, DUE, CANCELLED)
in: query
name: state
type: string
- description: Requested before (RFC3339)
in: query
name: requested_before
type: string
- description: Requested after (RFC3339)
in: query
name: requested_after
type: string
- description: Scheduled before (RFC3339)
in: query
name: scheduled_before
type: string
- description: Scheduled after (RFC3339)
in: query
name: scheduled_after
type: string
- description: Page number (default 1)
in: query
name: page
type: integer
- description: Page size (default 10, max 100)
in: query
name: page_size
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.APIResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.APIResponse'
summary: List account deletion requests
tags:
- user
/api/v1/analytics/dashboard:
get:
description: 'Platform analytics with optional date filters: all-time (default),
year, year+month, or custom from/to range. When year is set, payments.revenue_monthly
returns JanDec SUCCESS revenue totals (UTC) per currency for that calendar
year — use for yearly revenue charts. Daily series remains in revenue_last_30_days
(see date_filter.series_*). Courses section counts LMS + exam_prep inventory.'
parameters:
- description: Calendar year (e.g. 2025)
in: query
name: year
type: integer
- description: Calendar month 1-12 (requires year)
in: query
name: month
type: integer
- description: Custom range start (YYYY-MM-DD or RFC3339)
in: query
name: from
type: string
- description: Custom range end (YYYY-MM-DD or RFC3339, inclusive)
in: query
name: to
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.AnalyticsDashboard'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Analytics dashboard
tags:
- analytics
/api/v1/app/version/check:
get:
description: Public endpoint for mobile clients to determine if an app update
is available (force or optional)
parameters:
- description: 'Platform: ANDROID or IOS'
in: query
name: platform
required: true
type: string
- description: Client build number (Android versionCode / iOS build number)
in: query
name: version_code
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Check mobile app version
tags:
- app-versions
/api/v1/assessment/questions:
get:
description: Returns all active assessment questions from the initial assessment
set
produces:
- application/json
responses:
"200":
description: OK
schema:
items:
$ref: '#/definitions/domain.QuestionWithDetails'
type: array
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: List assessment questions
tags:
- assessment-question
post:
consumes:
- application/json
description: Creates a new assessment question using the unified questions system
parameters:
- description: Create question payload
in: body
name: body
required: true
schema:
$ref: '#/definitions/handlers.createQuestionReq'
produces:
- application/json
responses:
"201":
description: Created
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Create assessment question
tags:
- assessment-question
/api/v1/assessment/questions/{id}:
get:
description: Returns a single assessment question with its options or answer
parameters:
- description: Question ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.QuestionWithDetails'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Get assessment question by ID
tags:
- assessment-question
/api/v1/auth/google/android:
post:
parameters:
- description: Google ID Token from Android
in: body
name: idToken
required: true
schema:
type: string
responses: {}
summary: Login via Google Android ID Token
tags:
- auth
/api/v1/auth/google/callback:
get:
responses: {}
summary: Google login callback
tags:
- auth
/api/v1/auth/google/login:
get:
responses: {}
summary: Google login redirect
tags:
- auth
/api/v1/auth/logout:
post:
consumes:
- application/json
description: Logout user
parameters:
- description: Logout user
in: body
name: logout
required: true
schema:
$ref: '#/definitions/handlers.logoutReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.APIResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.APIResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/response.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.APIResponse'
summary: Logout user
tags:
- auth
/api/v1/auth/refresh:
post:
consumes:
- application/json
description: Refresh token
parameters:
- description: tokens
in: body
name: refresh
required: true
schema:
$ref: '#/definitions/handlers.refreshToken'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/handlers.loginUserRes'
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.APIResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/response.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.APIResponse'
summary: Refresh token
tags:
- auth
/api/v1/courses/{courseId}/modules:
get:
parameters:
- description: Course ID
in: path
name: courseId
required: true
type: integer
- default: 20
description: Page size
in: query
name: limit
type: integer
- default: 0
description: Offset
in: query
name: offset
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
summary: List modules for a course
tags:
- modules
post:
consumes:
- application/json
description: Create a module under a course; parent program is taken from the
course.
parameters:
- description: Course ID
in: path
name: courseId
required: true
type: integer
- description: Module
in: body
name: body
required: true
schema:
$ref: '#/definitions/domain.CreateModuleInput'
produces:
- application/json
responses:
"201":
description: Created
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Create module
tags:
- modules
/api/v1/courses/{courseId}/modules/reorder:
put:
parameters:
- description: Course ID
in: path
name: courseId
required: true
type: integer
- description: 'ordered_ids: every module id in this course, in the new order'
in: body
name: body
required: true
schema:
$ref: '#/definitions/domain.ReorderIDsRequest'
responses: {}
summary: Reorder modules within a course
tags:
- modules
/api/v1/courses/{id}:
delete:
parameters:
- description: Course ID
in: path
name: id
required: true
type: integer
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Delete course
tags:
- courses
get:
parameters:
- description: Course ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Get course by ID
tags:
- courses
put:
consumes:
- application/json
parameters:
- description: Course ID
in: path
name: id
required: true
type: integer
- description: Fields to update
in: body
name: body
required: true
schema:
$ref: '#/definitions/domain.UpdateCourseInput'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Update course
tags:
- courses
/api/v1/courses/{id}/practices:
get:
parameters:
- description: Course ID
in: path
name: id
required: true
type: integer
responses: {}
tags:
- practices
/api/v1/exam-prep/catalog-courses:
get:
parameters:
- default: 20
description: Page size
in: query
name: limit
type: integer
- default: 0
description: Offset
in: query
name: offset
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
summary: List exam-prep catalog courses
tags:
- exam-prep
post:
consumes:
- application/json
description: Top-level exam track (DET, IELTS, …) in schema exam_prep — separate
from LMS programs/courses
parameters:
- description: Catalog course
in: body
name: body
required: true
schema:
$ref: '#/definitions/domain.CreateExamPrepCatalogCourseInput'
produces:
- application/json
responses:
"201":
description: Created
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Create exam-prep catalog course
tags:
- exam-prep
/api/v1/exam-prep/catalog-courses/{catalogCourseId}/units:
get:
parameters:
- description: Catalog course ID
in: path
name: catalogCourseId
required: true
type: integer
- default: 20
description: Page size
in: query
name: limit
type: integer
- default: 0
description: Offset
in: query
name: offset
type: integer
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
summary: List exam-prep units for a catalog course
tags:
- exam-prep
post:
consumes:
- application/json
description: Unit under a catalog course (e.g. chapter title). Optional sort_order
assigns position within that catalog course (siblings at or after that index
are shifted); omit to append after the current highest sort_order in the catalog
course.
parameters:
- description: Catalog course ID
in: path
name: catalogCourseId
required: true
type: integer
- description: Unit
in: body
name: body
required: true
schema:
$ref: '#/definitions/domain.CreateExamPrepUnitInput'
produces:
- application/json
responses:
"201":
description: Created
schema:
$ref: '#/definitions/domain.Response'
summary: Create exam-prep unit
tags:
- exam-prep
/api/v1/exam-prep/catalog-courses/{catalogCourseId}/units/reorder:
put:
parameters:
- description: Catalog course ID
in: path
name: catalogCourseId
required: true
type: integer
- description: 'ordered_ids: every unit id in this catalog course, new order'
in: body
name: body
required: true
schema:
$ref: '#/definitions/domain.ReorderIDsRequest'
responses: {}
summary: Reorder units within a catalog course
tags:
- exam-prep
/api/v1/exam-prep/catalog-courses/{id}:
delete:
parameters:
- description: Catalog course ID
in: path
name: id
required: true
type: integer
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
summary: Delete exam-prep catalog course
tags:
- exam-prep
get:
parameters:
- description: Catalog course ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
summary: Get exam-prep catalog course by ID
tags:
- exam-prep
put:
consumes:
- application/json
parameters:
- description: Catalog course ID
in: path
name: id
required: true
type: integer
- description: Fields to update
in: body
name: body
required: true
schema:
$ref: '#/definitions/domain.UpdateExamPrepCatalogCourseInput'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
summary: Update exam-prep catalog course
tags:
- exam-prep
/api/v1/exam-prep/catalog-courses/reorder:
put:
consumes:
- application/json
parameters:
- description: 'ordered_ids: every catalog course id exactly once'
in: body
name: body
required: true
schema:
$ref: '#/definitions/domain.ReorderIDsRequest'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
summary: Reorder all exam-prep catalog courses
tags:
- exam-prep
/api/v1/exam-prep/lessons/{id}:
delete:
responses: {}
summary: Delete exam-prep lesson
tags:
- exam-prep
get:
responses: {}
summary: Get exam-prep lesson by ID
tags:
- exam-prep
put:
responses: {}
summary: Update exam-prep lesson
tags:
- exam-prep
/api/v1/exam-prep/lessons/{lessonId}/practices:
get:
parameters:
- description: Exam prep lesson ID
in: path
name: lessonId
required: true
type: integer
- default: 20
description: Page size
in: query
name: limit
type: integer
- default: 0
description: Offset
in: query
name: offset
type: integer
responses: {}
summary: List exam-prep practices for a lesson
tags:
- exam-prep
post:
parameters:
- description: Exam prep lesson ID (unit_module_lessons.id)
in: path
name: lessonId
required: true
type: integer
- description: Practice
in: body
name: body
required: true
schema:
$ref: '#/definitions/domain.CreateExamPrepPracticeInput'
responses: {}
summary: Create exam-prep practice (under a lesson; uses shared question_sets)
tags:
- exam-prep
/api/v1/exam-prep/modules/{id}:
delete:
responses: {}
summary: Delete exam-prep module
tags:
- exam-prep
get:
responses: {}
summary: Get exam-prep module by ID
tags:
- exam-prep
put:
responses: {}
summary: Update exam-prep module
tags:
- exam-prep
/api/v1/exam-prep/modules/{moduleId}/lessons:
get:
parameters:
- description: Exam prep unit module ID
in: path
name: moduleId
required: true
type: integer
- default: 20
description: Page size
in: query
name: limit
type: integer
- default: 0
description: Offset
in: query
name: offset
type: integer
responses: {}
summary: List exam-prep lessons for a unit module
tags:
- exam-prep
post:
parameters:
- description: Exam prep unit module ID
in: path
name: moduleId
required: true
type: integer
- description: Lesson
in: body
name: body
required: true
schema:
$ref: '#/definitions/domain.CreateExamPrepLessonInput'
responses: {}
summary: Create exam-prep lesson (under a unit module)
tags:
- exam-prep
/api/v1/exam-prep/modules/{moduleId}/lessons/reorder:
put:
responses: {}
summary: Reorder lessons within an exam-prep unit module
tags:
- exam-prep
/api/v1/exam-prep/practices/{id}:
delete:
parameters:
- description: Exam prep practice ID
in: path
name: id
required: true
type: integer
responses: {}
summary: Delete exam-prep practice
tags:
- exam-prep
get:
parameters:
- description: Exam prep practice ID
in: path
name: id
required: true
type: integer
responses: {}
summary: Get exam-prep practice by ID
tags:
- exam-prep
put:
parameters:
- description: Exam prep practice ID
in: path
name: id
required: true
type: integer
- description: Fields to update
in: body
name: body
required: true
schema:
$ref: '#/definitions/domain.UpdateExamPrepPracticeInput'
responses: {}
summary: Update exam-prep practice
tags:
- exam-prep
/api/v1/exam-prep/units/{id}:
delete:
parameters:
- description: Unit ID
in: path
name: id
required: true
type: integer
responses: {}
summary: Delete exam-prep unit
tags:
- exam-prep
get:
parameters:
- description: Unit ID
in: path
name: id
required: true
type: integer
responses: {}
summary: Get exam-prep unit by ID
tags:
- exam-prep
put:
parameters:
- description: Unit ID
in: path
name: id
required: true
type: integer
- description: Fields to update
in: body
name: body
required: true
schema:
$ref: '#/definitions/domain.UpdateExamPrepUnitInput'
responses: {}
summary: Update exam-prep unit
tags:
- exam-prep
/api/v1/exam-prep/units/{unitId}/modules:
get:
parameters:
- description: Unit ID
in: path
name: unitId
required: true
type: integer
responses: {}
summary: List exam-prep modules for a unit
tags:
- exam-prep
post:
parameters:
- description: Unit ID
in: path
name: unitId
required: true
type: integer
- description: Module
in: body
name: body
required: true
schema:
$ref: '#/definitions/domain.CreateExamPrepModuleInput'
responses: {}
summary: Create exam-prep module
tags:
- exam-prep
/api/v1/exam-prep/units/{unitId}/modules/reorder:
put:
parameters:
- description: Unit ID
in: path
name: unitId
required: true
type: integer
- description: ordered_ids
in: body
name: body
required: true
schema:
$ref: '#/definitions/domain.ReorderIDsRequest'
responses: {}
summary: Reorder modules within a unit
tags:
- exam-prep
/api/v1/faqs:
get:
description: Returns active FAQs for public/help center usage
parameters:
- description: Filter by category
in: query
name: category
type: string
- description: Limit (default 50)
in: query
name: limit
type: integer
- description: Offset (default 0)
in: query
name: offset
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: List published FAQs
tags:
- faqs
/api/v1/faqs/{id}:
get:
description: Returns one active FAQ item
parameters:
- description: FAQ ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Get published FAQ by ID
tags:
- faqs
/api/v1/field-options:
get:
description: Returns active options grouped by field_key (e.g. education_level,
country)
parameters:
- description: Filter by field key
in: query
name: field_key
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
summary: List field options for client dropdowns
tags:
- field-options
/api/v1/field-options/fields:
get:
description: Returns field_key values that have options (e.g. education_level,
country)
parameters:
- description: If true, only keys with active options
in: query
name: active_only
type: boolean
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
summary: List distinct field keys
tags:
- field-options
/api/v1/files/audio:
post:
consumes:
- multipart/form-data
parameters:
- description: Audio file (mp3, wav, ogg, m4a, aac, webm)
in: formData
name: file
required: true
type: file
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
summary: Upload an audio file
tags:
- files
/api/v1/files/refresh-url:
post:
consumes:
- application/json
parameters:
- description: reference (object key, minio://..., or existing presigned URL)
in: body
name: body
required: true
schema:
$ref: '#/definitions/handlers.refreshFileURLReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
summary: Refresh presigned URL for a file
tags:
- files
/api/v1/files/upload:
post:
consumes:
- multipart/form-data
parameters:
- description: 'Media type: image|audio|video'
in: formData
name: media_type
required: true
type: string
- description: Media file
in: formData
name: file
required: true
type: file
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
summary: Upload media file
tags:
- files
/api/v1/files/url:
get:
parameters:
- description: MinIO object key (e.g. profile_pictures/uuid.jpg)
in: query
name: key
required: true
type: string
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
summary: Get presigned URL for a file
tags:
- files
/api/v1/internal/users/purge-due-deletions:
post:
description: Worker-safe purge for due self-deletion requests
parameters:
- description: Max users to purge in one run (default 100, max 1000)
in: query
name: limit
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.APIResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.APIResponse'
security:
- Bearer: []
summary: Purge due account deletions
tags:
- user
/api/v1/issues:
get:
description: Returns all reported issues with pagination (admin only)
parameters:
- default: 20
description: Limit
in: query
name: limit
type: integer
- default: 0
description: Offset
in: query
name: offset
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/domain.Response'
- properties:
data:
$ref: '#/definitions/handlers.issueListRes'
type: object
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
security:
- Bearer: []
summary: Get all issues
tags:
- issues
post:
consumes:
- application/json
description: Allows any authenticated user to report an issue they encountered
parameters:
- description: Issue report payload
in: body
name: body
required: true
schema:
$ref: '#/definitions/handlers.createIssueReq'
produces:
- application/json
responses:
"201":
description: Created
schema:
allOf:
- $ref: '#/definitions/domain.Response'
- properties:
data:
$ref: '#/definitions/handlers.issueRes'
type: object
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
security:
- Bearer: []
summary: Report an issue
tags:
- issues
/api/v1/issues/{id}:
delete:
description: Deletes an issue report (admin only)
parameters:
- description: Issue ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
security:
- Bearer: []
summary: Delete an issue
tags:
- issues
get:
description: Returns a single issue report by its ID (admin only)
parameters:
- description: Issue ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/domain.Response'
- properties:
data:
$ref: '#/definitions/handlers.issueRes'
type: object
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
security:
- Bearer: []
summary: Get issue by ID
tags:
- issues
/api/v1/issues/{id}/status:
patch:
consumes:
- application/json
description: Updates the status of an issue (admin only)
parameters:
- description: Issue ID
in: path
name: id
required: true
type: integer
- description: Status update payload
in: body
name: body
required: true
schema:
$ref: '#/definitions/handlers.updateIssueStatusReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
security:
- Bearer: []
summary: Update issue status
tags:
- issues
/api/v1/issues/me:
get:
description: Returns paginated issues reported by the authenticated user
parameters:
- default: 20
description: Limit
in: query
name: limit
type: integer
- default: 0
description: Offset
in: query
name: offset
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/domain.Response'
- properties:
data:
$ref: '#/definitions/handlers.issueListRes'
type: object
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
security:
- Bearer: []
summary: Get my reported issues
tags:
- issues
/api/v1/issues/user/{user_id}:
get:
description: Returns paginated issues reported by a specific user (admin only)
parameters:
- description: User ID
in: path
name: user_id
required: true
type: integer
- default: 20
description: Limit
in: query
name: limit
type: integer
- default: 0
description: Offset
in: query
name: offset
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/domain.Response'
- properties:
data:
$ref: '#/definitions/handlers.issueListRes'
type: object
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
security:
- Bearer: []
summary: Get issues for a specific user
tags:
- issues
/api/v1/lessons/{id}:
delete:
parameters:
- description: Lesson ID
in: path
name: id
required: true
type: integer
responses: {}
tags:
- lessons
get:
parameters:
- description: Lesson ID
in: path
name: id
required: true
type: integer
responses: {}
tags:
- lessons
put:
parameters:
- description: Lesson ID
in: path
name: id
required: true
type: integer
- description: Fields to update
in: body
name: body
required: true
schema:
$ref: '#/definitions/domain.UpdateLessonInput'
responses: {}
tags:
- lessons
/api/v1/lessons/{id}/complete:
post:
description: Records lesson completion; may cascade to module, course, and program
progress for the authenticated user. Learners must meet sequential prerequisites;
staff bypass checks.
parameters:
- description: Lesson ID
in: path
name: id
required: true
type: integer
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"403":
description: Forbidden
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Mark a lesson as completed
tags:
- lessons
/api/v1/lessons/{id}/practices:
get:
parameters:
- description: Lesson ID
in: path
name: id
required: true
type: integer
responses: {}
tags:
- practices
/api/v1/lms/progress:
get:
description: Returns practice-based completed lesson, module, course, and program
IDs for the authenticated user (ordered by completion time, then id).
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Get my LMS completion history
tags:
- lms
/api/v1/lms/progress-summary:
get:
description: Returns the learner's nested LMS hierarchy with the same access
progress data exposed on the individual program, course, module, and lesson
APIs.
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Get my LMS progress summary
tags:
- lms
/api/v1/logs:
get:
description: Fetches application logs from MongoDB with pagination, level filtering,
and search
parameters:
- description: Filter logs by level (debug, info, warn, error, dpanic, panic,
fatal)
in: query
name: level
type: string
- description: Search term to match against message or fields
in: query
name: search
type: string
- default: 1
description: 'Page number for pagination (default: 1)'
in: query
name: page
type: integer
- default: 50
description: 'Number of items per page (default: 50, max: 100)'
in: query
name: limit
type: integer
produces:
- application/json
responses:
"200":
description: Paginated list of application logs
schema:
$ref: '#/definitions/domain.LogResponse'
"400":
description: Invalid request parameters
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal server error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Retrieve application logs with filtering and pagination
tags:
- Logs
/api/v1/modules/{id}:
delete:
parameters:
- description: Module ID
in: path
name: id
required: true
type: integer
responses: {}
tags:
- modules
get:
parameters:
- description: Module ID
in: path
name: id
required: true
type: integer
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
tags:
- modules
put:
parameters:
- description: Module ID
in: path
name: id
required: true
type: integer
- description: Fields to update
in: body
name: body
required: true
schema:
$ref: '#/definitions/domain.UpdateModuleInput'
responses: {}
tags:
- modules
/api/v1/modules/{id}/practices:
get:
parameters:
- description: Module ID
in: path
name: id
required: true
type: integer
responses: {}
tags:
- practices
/api/v1/modules/{moduleId}/lessons:
get:
parameters:
- description: Module ID
in: path
name: moduleId
required: true
type: integer
- default: 20
description: Page size
in: query
name: limit
type: integer
- default: 0
description: Offset
in: query
name: offset
type: integer
responses: {}
tags:
- lessons
post:
consumes:
- application/json
parameters:
- description: Module ID
in: path
name: moduleId
required: true
type: integer
- description: Lesson
in: body
name: body
required: true
schema:
$ref: '#/definitions/domain.CreateLessonInput'
produces:
- application/json
responses: {}
summary: Create lesson
tags:
- lessons
/api/v1/notifications/bulk-email:
post:
consumes:
- multipart/form-data
description: Sends an email to specified user IDs, all users of a role, or direct
email addresses with optional image attachment. Optionally schedule for later
with scheduled_at (RFC3339).
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Send bulk email
tags:
- notifications
/api/v1/notifications/bulk-push:
post:
consumes:
- application/json
description: Sends a push notification to specified user IDs or all users matching
a role. Optionally schedule for later with scheduled_at (RFC3339).
parameters:
- description: Bulk push content
in: body
name: body
required: true
schema:
properties:
image:
type: string
message:
type: string
role:
type: string
scheduled_at:
type: string
title:
type: string
user_ids:
items:
format: int64
type: integer
type: array
type: object
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Send bulk push notification
tags:
- notifications
/api/v1/notifications/bulk-sms:
post:
consumes:
- application/json
description: Sends an SMS to specified user IDs, all users of a role, or direct
phone numbers. Optionally schedule for later with scheduled_at (RFC3339).
parameters:
- description: Bulk SMS content
in: body
name: body
required: true
schema:
properties:
message:
type: string
phone_numbers:
items:
type: string
type: array
role:
type: string
scheduled_at:
type: string
user_ids:
items:
format: int64
type: integer
type: array
type: object
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Send bulk SMS
tags:
- notifications
/api/v1/notifications/scheduled:
get:
description: Returns paginated scheduled notifications with optional status,
channel, and date filters
parameters:
- description: Filter by status
in: query
name: status
type: string
- description: Filter by channel
in: query
name: channel
type: string
- description: Filter after date (RFC3339)
in: query
name: after
type: string
- description: Filter before date (RFC3339)
in: query
name: before
type: string
- default: 20
description: Page size
in: query
name: limit
type: integer
- default: 1
description: Page number
in: query
name: page
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: List scheduled notifications
tags:
- notifications
/api/v1/notifications/scheduled/{id}:
get:
description: Returns a single scheduled notification by its ID
parameters:
- description: Scheduled Notification ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Get scheduled notification
tags:
- notifications
/api/v1/notifications/scheduled/{id}/cancel:
post:
description: Cancels a scheduled notification if it is still pending or processing
parameters:
- description: Scheduled Notification ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Cancel scheduled notification
tags:
- notifications
/api/v1/notifications/send-email:
post:
consumes:
- multipart/form-data
description: Sends an email to a single email address with optional image attachment
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Send single email
tags:
- notifications
/api/v1/notifications/test-push:
post:
consumes:
- application/json
description: Sends a test push notification to all registered devices of the
current user
parameters:
- description: Test notification content
in: body
name: body
required: true
schema:
properties:
message:
type: string
title:
type: string
type: object
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Send test push notification
tags:
- notifications
/api/v1/payments:
get:
description: Returns the authenticated user's payment history
parameters:
- default: 20
description: Limit
in: query
name: limit
type: integer
- default: 0
description: Offset
in: query
name: offset
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
summary: Get payment history
tags:
- payments
/api/v1/payments/{id}:
get:
description: Returns details of a specific payment
parameters:
- description: Payment ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Get payment details
tags:
- payments
/api/v1/payments/{id}/cancel:
post:
description: Cancels a payment that is still pending
parameters:
- description: Payment ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Cancel a pending payment
tags:
- payments
/api/v1/payments/arifpay/success:
get:
description: Displays the Yimaru Academy success page after ArifPay redirects
the learner back to the backend.
parameters:
- description: ArifPay session identifier
in: query
name: session_id
type: string
- description: ArifPay session identifier
in: query
name: sessionId
type: string
- description: Fallback payment nonce
in: query
name: nonce
type: string
produces:
- text/html
responses:
"200":
description: HTML success page
schema:
type: string
summary: ArifPay payment success page
tags:
- payments
/api/v1/payments/chapa/callback:
get:
description: Verifies payment after Chapa redirects to callback_url
parameters:
- description: Transaction reference
in: query
name: trx_ref
type: string
- description: Chapa reference ID
in: query
name: ref_id
type: string
- description: Payment status
in: query
name: status
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
summary: Chapa payment callback
tags:
- payments
/api/v1/payments/direct:
post:
consumes:
- application/json
description: Creates a payment session and initiates direct payment (OTP-based)
parameters:
- description: Direct payment request
in: body
name: body
required: true
schema:
$ref: '#/definitions/handlers.initiateDirectPaymentReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Initiate direct payment
tags:
- payments
/api/v1/payments/direct/methods:
get:
description: Returns list of payment methods that support direct payment (OTP-based)
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
summary: Get direct payment methods
tags:
- payments
/api/v1/payments/direct/verify-otp:
post:
consumes:
- application/json
description: Verifies the OTP sent for direct payment methods (Amole, HelloCash,
etc.)
parameters:
- description: OTP verification request
in: body
name: body
required: true
schema:
$ref: '#/definitions/handlers.verifyOTPReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Verify OTP for direct payment
tags:
- payments
/api/v1/payments/methods:
get:
description: Returns payment methods available on Chapa checkout
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
summary: Get Chapa payment methods
tags:
- payments
/api/v1/payments/subscribe:
post:
consumes:
- application/json
description: Creates a payment session for a subscription plan
parameters:
- description: Payment request
in: body
name: body
required: true
schema:
$ref: '#/definitions/handlers.initiatePaymentReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Initiate subscription payment
tags:
- payments
/api/v1/payments/verify/{session_id}:
get:
description: Checks the payment status with the payment provider
parameters:
- description: Session ID
in: path
name: session_id
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Verify payment status
tags:
- payments
/api/v1/payments/webhook:
post:
consumes:
- application/json
description: Processes payment notifications from Chapa (charge.success, etc.)
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Handle Chapa webhook
tags:
- payments
/api/v1/personas:
get:
parameters:
- default: true
description: When true (default), return only active personas
in: query
name: active_only
type: boolean
- description: Page size
in: query
name: limit
type: integer
- description: Offset
in: query
name: offset
type: integer
responses: {}
summary: List LMS personas (catalog for practice assignment)
tags:
- personas
post:
consumes:
- application/json
parameters:
- description: Persona
in: body
name: body
required: true
schema:
$ref: '#/definitions/domain.CreateLmsPersonaInput'
responses:
"201":
description: Created
schema:
$ref: '#/definitions/domain.Response'
summary: Create LMS persona catalog entry
tags:
- personas
/api/v1/personas/{id}:
delete:
parameters:
- description: Persona ID
in: path
name: id
required: true
type: integer
responses: {}
summary: Delete LMS persona (practices referencing it will have persona_id cleared)
tags:
- personas
get:
parameters:
- description: Persona ID
in: path
name: id
required: true
type: integer
responses: {}
summary: Get LMS persona by ID
tags:
- personas
put:
parameters:
- description: Persona ID
in: path
name: id
required: true
type: integer
- description: Fields to update
in: body
name: body
required: true
schema:
$ref: '#/definitions/domain.UpdateLmsPersonaInput'
responses: {}
summary: Update LMS persona
tags:
- personas
/api/v1/practices:
post:
consumes:
- application/json
parameters:
- description: 'Practice (parent_kind: COURSE | MODULE | LESSON)'
in: body
name: body
required: true
schema:
$ref: '#/definitions/domain.CreatePracticeInput'
responses: {}
tags:
- practices
/api/v1/practices/{id}:
delete:
parameters:
- description: Practice ID
in: path
name: id
required: true
type: integer
responses: {}
tags:
- practices
get:
parameters:
- description: Practice ID
in: path
name: id
required: true
type: integer
responses: {}
tags:
- practices
put:
parameters:
- description: Practice ID
in: path
name: id
required: true
type: integer
- description: Fields to update (parent is immutable)
in: body
name: body
required: true
schema:
$ref: '#/definitions/domain.UpdatePracticeInput'
responses: {}
tags:
- practices
/api/v1/practices/{practiceId}/questions:
get:
description: Returns paginated questions for a practice(question-set), including
AUDIO fields
parameters:
- description: Practice(question-set) ID
in: path
name: practiceId
required: true
type: integer
- description: Question type filter (e.g. AUDIO)
in: query
name: question_type
type: string
- default: 10
description: Limit
in: query
name: limit
type: integer
- default: 0
description: Offset
in: query
name: offset
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Get questions by practice
tags:
- question-set-items
/api/v1/programs:
get:
description: Paginated list of programs
parameters:
- default: 20
description: Page size
in: query
name: limit
type: integer
- default: 0
description: Offset
in: query
name: offset
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: List programs
tags:
- programs
post:
consumes:
- application/json
description: Create a top-level LMS program. Optional sort_order inserts at
that global ordering; omit it to append after the current highest sort_order.
Unique constraint applies to sort_order.
parameters:
- description: Program
in: body
name: body
required: true
schema:
$ref: '#/definitions/domain.CreateProgramInput'
produces:
- application/json
responses:
"201":
description: Created
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Create program
tags:
- programs
/api/v1/programs/{id}:
delete:
parameters:
- description: Program ID
in: path
name: id
required: true
type: integer
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Delete program
tags:
- programs
get:
parameters:
- description: Program ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Get program by ID
tags:
- programs
put:
consumes:
- application/json
parameters:
- description: Program ID
in: path
name: id
required: true
type: integer
- description: Fields to update
in: body
name: body
required: true
schema:
$ref: '#/definitions/domain.UpdateProgramInput'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Update program
tags:
- programs
/api/v1/programs/{id}/courses:
get:
parameters:
- description: Program ID
in: path
name: id
required: true
type: integer
- default: 20
description: Page size
in: query
name: limit
type: integer
- default: 0
description: Offset
in: query
name: offset
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: List courses by program
tags:
- courses
post:
consumes:
- application/json
description: Create a course under a program. Optional sort_order assigns position
within that program (siblings shifted); omit to append after the current highest
sort_order in the program.
parameters:
- description: Program ID
in: path
name: id
required: true
type: integer
- description: Course
in: body
name: body
required: true
schema:
$ref: '#/definitions/domain.CreateCourseInput'
produces:
- application/json
responses:
"201":
description: Created
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Create course
tags:
- courses
/api/v1/programs/{id}/courses/reorder:
put:
parameters:
- description: Program ID
in: path
name: id
required: true
type: integer
- description: 'ordered_ids: every course id in this program, in the new order'
in: body
name: body
required: true
schema:
$ref: '#/definitions/domain.ReorderIDsRequest'
responses: {}
summary: Reorder courses within a program
tags:
- courses
/api/v1/programs/reorder:
put:
consumes:
- application/json
description: Sets learning order of programs. Body must list every current program
id exactly once, in the desired order (index 0 = first in path).
parameters:
- description: 'New order: ordered_ids is the full set of program ids'
in: body
name: body
required: true
schema:
$ref: '#/definitions/domain.ReorderIDsRequest'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Reorder all programs
tags:
- programs
/api/v1/progress/practices/{id}/complete:
post:
description: Marks a practice question set as completed for the authenticated
learner
parameters:
- description: Practice Question Set ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"403":
description: Forbidden
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Mark practice as completed
tags:
- progression
/api/v1/question-sets:
get:
description: Returns a paginated list of question sets filtered by type
parameters:
- description: Set type (PRACTICE, INITIAL_ASSESSMENT, QUIZ, EXAM, SURVEY, CAPSTONE)
in: query
name: set_type
required: true
type: string
- default: 10
description: Limit
in: query
name: limit
type: integer
- default: 0
description: Offset
in: query
name: offset
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Get question sets by type
tags:
- question-sets
post:
consumes:
- application/json
description: Creates a new question set (practice, assessment, quiz, exam, or
survey)
parameters:
- description: Create question set payload
in: body
name: body
required: true
schema:
$ref: '#/definitions/handlers.createQuestionSetReq'
produces:
- application/json
responses:
"201":
description: Created
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Create a new question set
tags:
- question-sets
/api/v1/question-sets/{id}:
delete:
description: Archives a question set (soft delete)
parameters:
- description: Question Set ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Delete a question set
tags:
- question-sets
get:
description: Returns a question set with question count
parameters:
- description: Question Set ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Get question set by ID
tags:
- question-sets
put:
consumes:
- application/json
description: Updates a question set's properties
parameters:
- description: Question Set ID
in: path
name: id
required: true
type: integer
- description: Update question set payload
in: body
name: body
required: true
schema:
$ref: '#/definitions/handlers.updateQuestionSetReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Update a question set
tags:
- question-sets
/api/v1/question-sets/{setId}/personas:
get:
description: Returns all users assigned as personas to a question set (practice)
parameters:
- description: Question Set ID
in: path
name: setId
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Get user personas for a question set
tags:
- question-sets
post:
consumes:
- application/json
description: Links a user as a persona to a question set (practice)
parameters:
- description: Question Set ID
in: path
name: setId
required: true
type: integer
- description: Add user persona payload
in: body
name: body
required: true
schema:
$ref: '#/definitions/handlers.addUserPersonaReq'
produces:
- application/json
responses:
"201":
description: Created
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Add a user as persona to a question set
tags:
- question-sets
/api/v1/question-sets/{setId}/personas/{userId}:
delete:
description: Unlinks a user as persona from a question set (practice)
parameters:
- description: Question Set ID
in: path
name: setId
required: true
type: integer
- description: User ID
in: path
name: userId
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Remove a user persona from a question set
tags:
- question-sets
/api/v1/question-sets/{setId}/questions:
get:
description: Returns all questions in a question set with details
parameters:
- description: Question Set ID
in: path
name: setId
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Get questions in set
tags:
- question-set-items
post:
consumes:
- application/json
description: Links a question to a question set
parameters:
- description: Question Set ID
in: path
name: setId
required: true
type: integer
- description: Add question to set payload
in: body
name: body
required: true
schema:
$ref: '#/definitions/handlers.addQuestionToSetReq'
produces:
- application/json
responses:
"201":
description: Created
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Add question to set
tags:
- question-set-items
/api/v1/question-sets/{setId}/questions/{questionId}:
delete:
description: Unlinks a question from a question set
parameters:
- description: Question Set ID
in: path
name: setId
required: true
type: integer
- description: Question ID
in: path
name: questionId
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Remove question from set
tags:
- question-set-items
/api/v1/question-sets/{setId}/questions/{questionId}/order:
put:
consumes:
- application/json
description: Updates the display order of a question in a set
parameters:
- description: Question Set ID
in: path
name: setId
required: true
type: integer
- description: Question ID
in: path
name: questionId
required: true
type: integer
- description: Update order payload
in: body
name: body
required: true
schema:
$ref: '#/definitions/handlers.updateQuestionOrderReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Update question order in set
tags:
- question-set-items
/api/v1/question-sets/by-owner:
get:
description: Returns question sets for a specific owner (e.g., sub-course)
parameters:
- description: Owner type (SUB_COURSE, COURSE, CATEGORY, STANDALONE)
in: query
name: owner_type
required: true
type: string
- description: Owner ID
in: query
name: owner_id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Get question sets by owner
tags:
- question-sets
/api/v1/questions:
get:
description: Returns a paginated list of questions with optional filters
parameters:
- description: Question type filter (MCQ, TRUE_FALSE, SHORT_ANSWER)
in: query
name: question_type
type: string
- description: Difficulty level filter (EASY, MEDIUM, HARD)
in: query
name: difficulty
type: string
- description: Status filter (DRAFT, PUBLISHED, INACTIVE)
in: query
name: status
type: string
- default: 10
description: Limit
in: query
name: limit
type: integer
- default: 0
description: Offset
in: query
name: offset
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: List questions
tags:
- questions
post:
consumes:
- application/json
description: Creates a new question with options (for MCQ/TRUE_FALSE) or short
answers (for SHORT_ANSWER). Supports question_type_definition_id for dynamic
builder-linked questions.
parameters:
- description: Create question payload
in: body
name: body
required: true
schema:
$ref: '#/definitions/handlers.createQuestionReq'
produces:
- application/json
responses:
"201":
description: Created
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Create a new question
tags:
- questions
/api/v1/questions/{id}:
delete:
description: Archives a question (soft delete)
parameters:
- description: Question ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Delete a question
tags:
- questions
get:
description: Returns a question with its options/short answers
parameters:
- description: Question ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Get question by ID
tags:
- questions
put:
consumes:
- application/json
description: Updates a question and optionally replaces its options/short answers.
Supports question_type_definition_id for dynamic builder-linked questions.
parameters:
- description: Question ID
in: path
name: id
required: true
type: integer
- description: Update question payload
in: body
name: body
required: true
schema:
$ref: '#/definitions/handlers.updateQuestionReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Update a question
tags:
- questions
/api/v1/questions/audio-answer:
post:
consumes:
- multipart/form-data
parameters:
- description: Question ID
in: formData
name: question_id
required: true
type: integer
- description: Question Set ID
in: formData
name: question_set_id
required: true
type: integer
- description: Audio recording
in: formData
name: file
required: true
type: file
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
summary: Submit audio answer for a question
tags:
- questions
/api/v1/questions/component-catalog:
get:
description: Valid stimulus and response component kind codes for dynamic question-type
definitions
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
summary: Question-type builder component catalog
tags:
- questions
/api/v1/questions/search:
get:
description: Search questions by text
parameters:
- description: Search query
in: query
name: q
required: true
type: string
- default: 10
description: Limit
in: query
name: limit
type: integer
- default: 0
description: Offset
in: query
name: offset
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Search questions
tags:
- questions
/api/v1/questions/type-definitions:
get:
parameters:
- description: Filter by status (ACTIVE, INACTIVE)
in: query
name: status
type: string
- description: Include system seeded definitions
in: query
name: include_system
type: boolean
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: List reusable question-type definitions
tags:
- questions
post:
consumes:
- application/json
description: Stores a reusable dynamic question-type definition for future question
construction. Only runtime-mappable definitions are persisted.
parameters:
- description: Question type definition payload
in: body
name: body
required: true
schema:
$ref: '#/definitions/handlers.createQuestionTypeDefinitionReq'
produces:
- application/json
responses:
"201":
description: Created
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Create reusable question-type definition
tags:
- questions
/api/v1/questions/type-definitions/{id}:
delete:
parameters:
- description: Question type definition id
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Delete reusable question-type definition
tags:
- questions
get:
parameters:
- description: Question type definition id
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Get reusable question-type definition by id
tags:
- questions
put:
consumes:
- application/json
description: Updates a reusable dynamic question-type definition. Updated definitions
must remain runtime-mappable.
parameters:
- description: Question type definition id
in: path
name: id
required: true
type: integer
- description: Update question type definition payload
in: body
name: body
required: true
schema:
$ref: '#/definitions/handlers.updateQuestionTypeDefinitionReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Update reusable question-type definition
tags:
- questions
/api/v1/questions/validate-question-type-definition:
post:
consumes:
- application/json
description: Validates selected stimulus and response component kinds for temporary
question-type definitions (component-level validation only)
parameters:
- description: Stimulus and response component kinds
in: body
name: body
required: true
schema:
$ref: '#/definitions/handlers.validateQuestionTypeDefinitionReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Validate dynamic question-type definition
tags:
- questions
/api/v1/ratings:
get:
description: Returns paginated ratings for a specific target
parameters:
- description: Target type (app, course, sub_course)
in: query
name: target_type
required: true
type: string
- description: Target ID (0 for app)
in: query
name: target_id
required: true
type: integer
- description: Limit (default 20)
in: query
name: limit
type: integer
- description: Offset (default 0)
in: query
name: offset
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Get ratings for a target
tags:
- ratings
post:
consumes:
- application/json
description: Submit a rating for an app, course, or sub-course
parameters:
- description: Submit rating payload
in: body
name: body
required: true
schema:
$ref: '#/definitions/handlers.submitRatingReq'
produces:
- application/json
responses:
"201":
description: Created
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Submit a rating
tags:
- ratings
/api/v1/ratings/{id}:
delete:
description: Deletes a rating by ID for the current user
parameters:
- description: Rating ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Delete a rating
tags:
- ratings
/api/v1/ratings/me:
get:
description: Returns the current user's rating for a specific target
parameters:
- description: Target type (app, course, sub_course)
in: query
name: target_type
required: true
type: string
- description: Target ID (0 for app)
in: query
name: target_id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Get my rating for a target
tags:
- ratings
/api/v1/ratings/me/all:
get:
description: Returns all ratings submitted by the current user
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Get all my ratings
tags:
- ratings
/api/v1/ratings/summary:
get:
description: Returns the total count and average stars for a specific target
parameters:
- description: Target type (app, course, sub_course)
in: query
name: target_type
required: true
type: string
- description: Target ID (0 for app)
in: query
name: target_id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Get rating summary for a target
tags:
- ratings
/api/v1/rbac/permissions:
get:
consumes:
- application/json
description: Get all permissions in the system grouped by group name
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/domain.Response'
- properties:
data:
items:
$ref: '#/definitions/domain.Permission'
type: array
type: object
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
security:
- Bearer: []
summary: List all permissions
tags:
- rbac
/api/v1/rbac/permissions/groups:
get:
consumes:
- application/json
description: Get all distinct permission group names
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/domain.Response'
- properties:
data:
items:
type: string
type: array
type: object
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
security:
- Bearer: []
summary: List permission groups
tags:
- rbac
/api/v1/rbac/permissions/sync:
post:
consumes:
- application/json
description: Re-seed permissions from code and reload the RBAC cache
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
security:
- Bearer: []
summary: Sync permissions
tags:
- rbac
/api/v1/rbac/roles:
get:
consumes:
- application/json
description: Get all roles with optional filters
parameters:
- description: Search by role name
in: query
name: query
type: string
- description: Filter by system role (true/false)
in: query
name: is_system
type: boolean
- description: 'Page number (default: 1)'
in: query
name: page
type: integer
- description: 'Page size (default: 20)'
in: query
name: page_size
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
security:
- Bearer: []
summary: List all roles
tags:
- rbac
post:
consumes:
- application/json
description: Create a new role with a name and description
parameters:
- description: Role creation payload
in: body
name: body
required: true
schema:
$ref: '#/definitions/domain.CreateRoleReq'
produces:
- application/json
responses:
"201":
description: Created
schema:
allOf:
- $ref: '#/definitions/domain.Response'
- properties:
data:
$ref: '#/definitions/domain.RoleRecord'
type: object
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
security:
- Bearer: []
summary: Create a new role
tags:
- rbac
/api/v1/rbac/roles/{id}:
delete:
consumes:
- application/json
description: Delete a non-system role by ID
parameters:
- description: Role ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
security:
- Bearer: []
summary: Delete a role
tags:
- rbac
get:
consumes:
- application/json
description: Get a role and its permissions by ID
parameters:
- description: Role ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/domain.Response'
- properties:
data:
$ref: '#/definitions/domain.RoleWithPermissions'
type: object
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
security:
- Bearer: []
summary: Get a role by ID
tags:
- rbac
put:
consumes:
- application/json
description: Update an existing role's name and description
parameters:
- description: Role ID
in: path
name: id
required: true
type: integer
- description: Role update payload
in: body
name: body
required: true
schema:
$ref: '#/definitions/domain.UpdateRoleReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
security:
- Bearer: []
summary: Update a role
tags:
- rbac
/api/v1/rbac/roles/{id}/permissions:
get:
consumes:
- application/json
description: Get all permissions assigned to a role
parameters:
- description: Role ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/domain.Response'
- properties:
data:
items:
$ref: '#/definitions/domain.Permission'
type: array
type: object
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
security:
- Bearer: []
summary: Get permissions for a role
tags:
- rbac
put:
consumes:
- application/json
description: Replace all permissions for a role with the given permission IDs
parameters:
- description: Role ID
in: path
name: id
required: true
type: integer
- description: Permission IDs payload
in: body
name: body
required: true
schema:
$ref: '#/definitions/domain.SetRolePermissionsReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
security:
- Bearer: []
summary: Set permissions for a role
tags:
- rbac
/api/v1/sendSMS:
post:
consumes:
- application/json
description: Sends an SMS message to a single phone number using AfroMessage
parameters:
- description: Send SMS request
in: body
name: sendSMS
required: true
schema:
$ref: '#/definitions/handlers.SendSingleAfroSMSReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.APIResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.APIResponse'
summary: Send single SMS via AfroMessage
tags:
- user
/api/v1/subscription-plans:
get:
description: Returns all subscription plans
parameters:
- description: Return only active plans
in: query
name: active_only
type: boolean
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: List subscription plans
tags:
- subscriptions
post:
consumes:
- application/json
description: Creates a new subscription plan (admin only)
parameters:
- description: Create plan payload
in: body
name: body
required: true
schema:
$ref: '#/definitions/handlers.createPlanReq'
produces:
- application/json
responses:
"201":
description: Created
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Create a subscription plan
tags:
- subscriptions
/api/v1/subscription-plans/{id}:
delete:
description: Deletes a subscription plan (admin only)
parameters:
- description: Plan ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Delete a subscription plan
tags:
- subscriptions
get:
description: Returns a single subscription plan by ID
parameters:
- description: Plan ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Get a subscription plan
tags:
- subscriptions
put:
consumes:
- application/json
description: Updates a subscription plan (admin only)
parameters:
- description: Plan ID
in: path
name: id
required: true
type: integer
- description: Update plan payload
in: body
name: body
required: true
schema:
$ref: '#/definitions/handlers.updatePlanReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Update a subscription plan
tags:
- subscriptions
/api/v1/subscriptions:
post:
consumes:
- application/json
deprecated: true
description: Creates a new subscription for the authenticated user. For regular
users, use /payments/subscribe instead.
parameters:
- description: Subscribe payload
in: body
name: body
required: true
schema:
$ref: '#/definitions/handlers.subscribeReq'
produces:
- application/json
responses:
"201":
description: Created
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Subscribe to a plan (Admin only - bypasses payment)
tags:
- subscriptions
/api/v1/subscriptions/{id}/auto-renew:
put:
consumes:
- application/json
description: Enables or disables auto-renewal for a subscription
parameters:
- description: Subscription ID
in: path
name: id
required: true
type: integer
- description: Auto-renew payload
in: body
name: body
required: true
schema:
$ref: '#/definitions/handlers.autoRenewReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Set auto-renew
tags:
- subscriptions
/api/v1/subscriptions/{id}/cancel:
post:
description: Cancels the user's subscription
parameters:
- description: Subscription ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Cancel subscription
tags:
- subscriptions
/api/v1/subscriptions/checkout:
post:
consumes:
- application/json
description: Initiates payment for a subscription plan. Returns payment URL
for checkout.
parameters:
- description: Subscribe with payment payload
in: body
name: body
required: true
schema:
$ref: '#/definitions/handlers.subscribeWithPaymentReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"409":
description: User already has active subscription
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Subscribe to a plan with payment
tags:
- subscriptions
/api/v1/subscriptions/history:
get:
description: Returns the authenticated user's subscription history
parameters:
- default: 20
description: Limit
in: query
name: limit
type: integer
- default: 0
description: Offset
in: query
name: offset
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
summary: Get subscription history
tags:
- subscriptions
/api/v1/subscriptions/me:
get:
description: Returns the authenticated user's active subscription
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Get current subscription
tags:
- subscriptions
/api/v1/subscriptions/status:
get:
description: Returns whether the authenticated user has an active subscription
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
summary: Check subscription status
tags:
- subscriptions
/api/v1/super-login:
post:
consumes:
- application/json
description: Login super-admin
parameters:
- description: Login super-admin
in: body
name: login
required: true
schema:
$ref: '#/definitions/domain.LoginRequest'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/handlers.LoginAdminRes'
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.APIResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/response.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.APIResponse'
summary: Login super-admin
tags:
- auth
/api/v1/t-approver/{id}:
get:
consumes:
- application/json
description: Get a single admin by id
parameters:
- description: User ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/handlers.AdminRes'
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.APIResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/response.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.APIResponse'
summary: Get admin by id
tags:
- admin
put:
consumes:
- application/json
description: Update Admin
parameters:
- description: Update Admin
in: body
name: admin
required: true
schema:
$ref: '#/definitions/handlers.updateAdminReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.APIResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.APIResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/response.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.APIResponse'
summary: Update Admin
tags:
- admin
/api/v1/team/invitations:
get:
description: Lists team member invitations with optional status filter
parameters:
- description: pending, accepted, expired, or revoked
in: query
name: status
type: string
- description: Limit (default 20)
in: query
name: limit
type: integer
- description: Offset (default 0)
in: query
name: offset
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
summary: List team invitations
tags:
- team
/api/v1/team/invitations/{id}/revoke:
post:
description: Revokes the invitation and removes the pending team member if not
yet accepted
parameters:
- description: Invitation ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
summary: Revoke a pending team invitation
tags:
- team
/api/v1/team/invitations/accept:
post:
consumes:
- application/json
description: Public endpoint to set password and profile details after following
the invite link
parameters:
- description: Accept invitation payload
in: body
name: body
required: true
schema:
$ref: '#/definitions/domain.AcceptTeamInvitationReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
summary: Accept team invitation and complete account setup
tags:
- team
/api/v1/team/invitations/verify:
get:
description: Public endpoint used by the admin panel accept-invite page
parameters:
- description: Invitation token
in: query
name: token
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
summary: Verify team invitation token
tags:
- team
/api/v1/team/login:
post:
consumes:
- application/json
description: Authenticate a team member (internal staff) with email and password
parameters:
- description: Team member login credentials
in: body
name: body
required: true
schema:
$ref: '#/definitions/domain.TeamMemberLoginReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/domain.Response'
- properties:
data:
$ref: '#/definitions/handlers.teamMemberLoginRes'
type: object
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Login team member
tags:
- team
/api/v1/team/me:
get:
consumes:
- application/json
description: Get the authenticated team member's own profile
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/domain.Response'
- properties:
data:
$ref: '#/definitions/domain.TeamMemberResponse'
type: object
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
security:
- Bearer: []
summary: Get my team profile
tags:
- team
/api/v1/team/members:
get:
consumes:
- application/json
description: Get a paginated list of team members with optional filtering
parameters:
- description: Filter by team role (super_admin, admin, content_manager, support_agent,
instructor, finance, hr, analyst)
in: query
name: team_role
type: string
- description: Filter by department
in: query
name: department
type: string
- description: Filter by status (active, inactive, suspended, terminated)
in: query
name: status
type: string
- description: Search by name, email, or phone number
in: query
name: search
type: string
- description: 'Page number (default: 1)'
in: query
name: page
type: integer
- description: 'Items per page (default: 10, max: 100)'
in: query
name: page_size
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/domain.Response'
- properties:
data:
items:
$ref: '#/definitions/domain.TeamMemberResponse'
type: array
metadata:
$ref: '#/definitions/domain.Pagination'
type: object
"401":
description: Unauthorized
schema:
$ref: '#/definitions/domain.ErrorResponse'
"403":
description: Forbidden
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
security:
- Bearer: []
summary: List all team members
tags:
- team
post:
consumes:
- application/json
description: Create a new internal team member (admin only)
parameters:
- description: Team member creation payload
in: body
name: body
required: true
schema:
$ref: '#/definitions/domain.CreateTeamMemberReq'
produces:
- application/json
responses:
"201":
description: Created
schema:
allOf:
- $ref: '#/definitions/domain.Response'
- properties:
data:
$ref: '#/definitions/domain.TeamMemberResponse'
type: object
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/domain.ErrorResponse'
"403":
description: Forbidden
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
security:
- Bearer: []
summary: Create a new team member
tags:
- team
/api/v1/team/members/{id}:
delete:
consumes:
- application/json
description: Delete a team member (super admin only)
parameters:
- description: Team Member ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/domain.ErrorResponse'
"403":
description: Forbidden
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
security:
- Bearer: []
summary: Delete team member
tags:
- team
get:
consumes:
- application/json
description: Retrieve a team member's details by their ID
parameters:
- description: Team Member ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/domain.Response'
- properties:
data:
$ref: '#/definitions/domain.TeamMemberResponse'
type: object
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
security:
- Bearer: []
summary: Get team member by ID
tags:
- team
put:
consumes:
- application/json
description: Update an existing team member's details (admin only)
parameters:
- description: Team Member ID
in: path
name: id
required: true
type: integer
- description: Team member update payload
in: body
name: body
required: true
schema:
$ref: '#/definitions/domain.UpdateTeamMemberReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/domain.ErrorResponse'
"403":
description: Forbidden
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
security:
- Bearer: []
summary: Update team member
tags:
- team
/api/v1/team/members/{id}/change-password:
post:
consumes:
- application/json
description: Change a team member's password (requires current password)
parameters:
- description: Team Member ID
in: path
name: id
required: true
type: integer
- description: Password change payload
in: body
name: body
required: true
schema:
$ref: '#/definitions/handlers.changePasswordReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
security:
- Bearer: []
summary: Change team member password
tags:
- team
/api/v1/team/members/{id}/resend-invite:
post:
description: Revokes the current pending invite and sends a new invitation email
parameters:
- description: Team member ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Resend team invitation
tags:
- team
/api/v1/team/members/{id}/status:
patch:
consumes:
- application/json
description: Update a team member's status (active, inactive, suspended, terminated)
parameters:
- description: Team Member ID
in: path
name: id
required: true
type: integer
- description: Status update payload
in: body
name: body
required: true
schema:
$ref: '#/definitions/domain.UpdateTeamMemberStatusReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/domain.ErrorResponse'
"403":
description: Forbidden
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
security:
- Bearer: []
summary: Update team member status
tags:
- team
/api/v1/team/members/invite:
post:
consumes:
- application/json
description: Creates a pending team member (email + team_role only) and sends
an invitation email; profile is completed on accept
parameters:
- description: Invite payload
in: body
name: body
required: true
schema:
$ref: '#/definitions/domain.InviteTeamMemberReq'
produces:
- application/json
responses:
"201":
description: Created
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Invite a team member by email
tags:
- team
/api/v1/team/refresh:
post:
consumes:
- application/json
description: Exchanges a valid team refresh token for a new access JWT and a
rotated refresh token (use only tokens from POST /team/login or this endpoint).
parameters:
- description: Current refresh token
in: body
name: body
required: true
schema:
$ref: '#/definitions/handlers.teamMemberRefreshReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/domain.Response'
- properties:
data:
$ref: '#/definitions/handlers.teamMemberLoginRes'
type: object
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Refresh team member tokens
tags:
- team
/api/v1/team/stats:
get:
consumes:
- application/json
description: Get statistics about team members by status
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/domain.Response'
- properties:
data:
$ref: '#/definitions/domain.TeamMemberStats'
type: object
"401":
description: Unauthorized
schema:
$ref: '#/definitions/domain.ErrorResponse'
"403":
description: Forbidden
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
security:
- Bearer: []
summary: Get team member statistics
tags:
- team
/api/v1/tenant:
get:
consumes:
- application/json
description: Check if phone number or email exist
parameters:
- description: Check phone number or email exist
in: body
name: checkPhoneEmailExist
required: true
schema:
$ref: '#/definitions/handlers.CheckPhoneEmailExistReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/handlers.CheckPhoneEmailExistRes'
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.APIResponse'
summary: Check if phone number or email exist
tags:
- user
/api/v1/user:
put:
consumes:
- application/json
description: Updates user profile information (partial updates supported)
parameters:
- description: User ID
in: path
name: user_id
required: true
type: integer
- description: Update user payload
in: body
name: body
required: true
schema:
$ref: '#/definitions/domain.UpdateUserReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Update user profile
tags:
- user
/api/v1/user/{id}/profile-picture:
post:
consumes:
- multipart/form-data
description: Uploads a profile picture for the specified user
parameters:
- description: User ID
in: path
name: id
required: true
type: integer
- description: Image file (jpg|png|webp)
in: formData
name: file
required: true
type: file
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.APIResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.APIResponse'
security:
- Bearer: []
summary: Upload profile picture
tags:
- user
/api/v1/user/{user_id}/is-pending:
get:
consumes:
- application/json
description: Returns whether the specified user has a status of "pending"
parameters:
- description: User ID
in: path
name: user_id
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Check if user status is pending
tags:
- user
/api/v1/user/{user_id}/is-profile-completed:
get:
consumes:
- application/json
description: Returns the profile completion status and percentage for the specified
user
parameters:
- description: User ID
in: path
name: user_id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Check if user profile is completed
tags:
- user
/api/v1/user/delete/{id}:
delete:
consumes:
- application/json
description: Delete a user by their ID
parameters:
- description: User ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.APIResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.APIResponse'
summary: Delete user by ID
tags:
- user
/api/v1/user/me:
delete:
description: Starts account deletion with grace period before permanent purge
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.APIResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/response.APIResponse'
"403":
description: Forbidden
schema:
$ref: '#/definitions/response.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.APIResponse'
security:
- Bearer: []
summary: Request deletion of my account
tags:
- user
/api/v1/user/me/deletion/cancel:
post:
description: Cancels a pending self-deletion request during grace period
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.APIResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/response.APIResponse'
"403":
description: Forbidden
schema:
$ref: '#/definitions/response.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.APIResponse'
security:
- Bearer: []
summary: Cancel my account deletion request
tags:
- user
/api/v1/user/resetPassword:
post:
consumes:
- application/json
description: Reset password
parameters:
- description: Reset password
in: body
name: resetPassword
required: true
schema:
$ref: '#/definitions/handlers.ResetPasswordReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.APIResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.APIResponse'
summary: Reset password
tags:
- user
/api/v1/user/search:
post:
consumes:
- application/json
description: Search for user using name or phone
parameters:
- description: Search for using his name or phone
in: body
name: searchUserByNameOrPhone
required: true
schema:
$ref: '#/definitions/handlers.SearchUserByNameOrPhoneReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.UserProfileResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.APIResponse'
summary: Search for user using name or phone
tags:
- user
/api/v1/user/sendResetCode:
post:
consumes:
- application/json
description: Send reset code
parameters:
- description: Send reset code
in: body
name: resetCode
required: true
schema:
$ref: '#/definitions/handlers.ResetCodeReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.APIResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.APIResponse'
summary: Send reset code
tags:
- user
/api/v1/user/single/{id}:
get:
consumes:
- application/json
description: Get a single user by id
parameters:
- description: User ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.UserProfileResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.APIResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/response.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.APIResponse'
summary: Get user by id
tags:
- user
/api/v1/user/status:
patch:
consumes:
- application/json
description: Activates, deactivates, or suspends a user account
parameters:
- description: Status update payload
in: body
name: body
required: true
schema:
type: object
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.APIResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.APIResponse'
summary: Update user status
tags:
- user
/api/v1/user/verify-otp:
post:
consumes:
- application/json
description: Verify OTP for registration or other actions
parameters:
- description: Verify OTP
in: body
name: verifyOtp
required: true
schema:
$ref: '#/definitions/domain.VerifyOtpReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.APIResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.APIResponse'
summary: Verify OTP
tags:
- user
/api/v1/users:
get:
consumes:
- application/json
description: 'Get users with optional filters. Each user includes subscription_status:
ACTIVE, PENDING, or Unsubscribed.'
parameters:
- description: Role filter
in: query
name: role
type: string
- description: Search query
in: query
name: query
type: string
- description: Page number
in: query
name: page
type: integer
- description: Page size
in: query
name: page_size
type: integer
- description: Created before (RFC3339)
in: query
name: created_before
type: string
- description: Created after (RFC3339)
in: query
name: created_after
type: string
- description: User account status filter (ACTIVE, PENDING, SUSPENDED, DEACTIVATED)
in: query
name: status
type: string
- description: Country filter (case-insensitive match on stored value)
in: query
name: country
type: string
- description: Region filter (case-insensitive match on stored value)
in: query
name: region
type: string
- description: 'Derived subscription filter: ACTIVE, PENDING, or Unsubscribed
(matches response subscription_status semantics)'
in: query
name: subscription_status
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.APIResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.APIResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.APIResponse'
summary: Get all users
tags:
- user
/api/v1/users/summary:
get:
consumes:
- application/json
description: Returns total users, active users, and users who joined this month
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/domain.Response'
- properties:
data:
$ref: '#/definitions/domain.UserSummary'
type: object
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
security:
- Bearer: []
summary: Get user summary statistics
tags:
- user
/api/v1/videos/engagement/heartbeat:
post:
consumes:
- application/json
description: Records playback position for analytics (completion, replay, and
drop-off). Send periodic heartbeats while watching; set ended=true when the
viewer leaves. A new session starts after 30 minutes of inactivity or when
ended=true on the prior session.
parameters:
- description: Playback heartbeat
in: body
name: body
required: true
schema:
$ref: '#/definitions/domain.VideoEngagementHeartbeatInput'
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/domain.Response'
- properties:
data:
$ref: '#/definitions/domain.VideoWatchSessionResponse'
type: object
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"403":
description: Forbidden
schema:
$ref: '#/definitions/domain.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Report video playback progress
tags:
- videos
/api/v1/vimeo/oembed:
get:
consumes:
- application/json
description: Fetches oEmbed metadata for a Vimeo video URL
parameters:
- description: Vimeo video URL
in: query
name: url
required: true
type: string
- description: Desired width
in: query
name: width
type: integer
- description: Desired height
in: query
name: height
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/vimeo.OEmbedResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Get oEmbed data for a Vimeo URL
tags:
- Vimeo
/api/v1/vimeo/sample:
get:
consumes:
- application/json
description: Fetches a sample video from Vimeo and returns video details along
with an embeddable iframe for client-side integration
parameters:
- default: "76979871"
description: Vimeo Video ID to use as sample
in: query
name: video_id
type: string
- default: 640
description: Player width
in: query
name: width
type: integer
- default: 360
description: Player height
in: query
name: height
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/domain.Response'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Get a sample Vimeo video with iframe embed
tags:
- Vimeo
/api/v1/vimeo/uploads/pull:
post:
consumes:
- application/json
description: Initiates a pull upload where Vimeo fetches the video from a URL
parameters:
- description: Pull Upload Request
in: body
name: request
required: true
schema:
$ref: '#/definitions/handlers.CreatePullUploadRequest'
produces:
- application/json
responses:
"201":
description: Created
schema:
$ref: '#/definitions/handlers.VimeoUploadResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Create a pull upload to Vimeo
tags:
- Vimeo
/api/v1/vimeo/uploads/tus:
post:
consumes:
- application/json
description: Initiates a TUS resumable upload and returns the upload link
parameters:
- description: TUS Upload Request
in: body
name: request
required: true
schema:
$ref: '#/definitions/handlers.CreateTusUploadRequest'
produces:
- application/json
responses:
"201":
description: Created
schema:
$ref: '#/definitions/handlers.VimeoUploadResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Create a TUS resumable upload to Vimeo
tags:
- Vimeo
/api/v1/vimeo/videos:
get:
consumes:
- application/json
description: Returns a paginated list of videos for the Vimeo API token (GET
https://api.vimeo.com/me/videos)
parameters:
- default: 1
description: Page number (starts at 1)
in: query
name: page
type: integer
- default: 25
description: Page size (Vimeo max 100)
in: query
name: per_page
type: integer
- description: Search query
in: query
name: query
type: string
- description: Sort field (e.g. date, alphabetical, plays, likes, comments,
duration, relevance)
in: query
name: sort
type: string
- description: asc or desc
in: query
name: direction
type: string
- description: Vimeo filter (e.g. embeddable, playable)
in: query
name: filter
type: string
- description: Vimeo filter_type when using filter
in: query
name: filter_type
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/domain.Response'
- properties:
data:
items:
$ref: '#/definitions/handlers.VimeoVideoResponse'
type: array
metadata:
$ref: '#/definitions/handlers.VimeoVideosListMetadata'
type: object
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
"503":
description: Service Unavailable
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: List videos stored in the Vimeo account
tags:
- Vimeo
/api/v1/vimeo/videos/{video_id}:
delete:
consumes:
- application/json
description: Deletes a video from the Vimeo account
parameters:
- description: Vimeo Video ID
in: path
name: video_id
required: true
type: string
produces:
- application/json
responses:
"204":
description: No Content
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Delete a video from Vimeo
tags:
- Vimeo
get:
consumes:
- application/json
description: Retrieves video details from Vimeo by video ID
parameters:
- description: Vimeo Video ID
in: path
name: video_id
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/handlers.VimeoVideoResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Get video information from Vimeo
tags:
- Vimeo
/api/v1/vimeo/videos/{video_id}/embed:
get:
consumes:
- application/json
description: Generates an embeddable player iframe for the video
parameters:
- description: Vimeo Video ID
in: path
name: video_id
required: true
type: string
- default: 640
description: Player width
in: query
name: width
type: integer
- default: 360
description: Player height
in: query
name: height
type: integer
- description: Autoplay video
in: query
name: autoplay
type: boolean
- description: Loop video
in: query
name: loop
type: boolean
- description: Mute video
in: query
name: muted
type: boolean
- description: Background mode (no controls)
in: query
name: background
type: boolean
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/handlers.VimeoEmbedResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Get embed code for a Vimeo video
tags:
- Vimeo
/api/v1/vimeo/videos/{video_id}/status:
get:
consumes:
- application/json
description: Returns the current transcoding status of a video
parameters:
- description: Vimeo Video ID
in: path
name: video_id
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
additionalProperties:
type: string
type: object
"400":
description: Bad Request
schema:
$ref: '#/definitions/domain.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/domain.ErrorResponse'
summary: Get transcode status of a Vimeo video
tags:
- Vimeo
securityDefinitions:
Bearer:
in: header
name: Authorization
type: apiKey
swagger: "2.0"