API Reference
Build powerful integrations with Jiroshi's professional LMS engine. Our REST API is designed for reliability, speed, and seamless multi-tenant operations.
Introduction
The Jiroshi REST API provides programmatic access to all core platform resources, including instructors, students, courses, enrollments, and related operational data. It is intended for building custom integrations, instructor-facing tools, internal services, and automated workflows on top of the Jiroshi platform.
The API follows standard REST conventions, uses JSON for all request and response payloads, and is versioned to ensure backward compatibility as the platform evolves. Authentication, authorization, and rate limiting are enforced consistently across all endpoints.
This documentation describes the available endpoints, request/response formats, authentication mechanisms, error handling conventions, and operational constraints. All the API endpoints are subject to change as this is a MVP Version of the API and new platform capabilities will be introduced.
Active Base URL for Jiroshi V1
https://api.jiroshi.com/api/v1/public
Base URL
All API requests should be made to https://api.jiroshi.com/api/v1/public
Note: Future versions will be exposed under separate versioned paths (for example,/api/v2/public).
API Keys
Jiroshi uses API keys to authenticate and authorize access to its REST API. API keys are scoped to your account and must be included with every request to protected endpoints.
You can create and manage API keys from the Jiroshi Dashboard. Each key pair consists of a Public Key (pk) and a Secret Key (sk), each intended for different security contexts.
Creating an API Key
To generate a new API key, navigate to the Manage API Keys section from the dashboard sidebar. On the Manage API Keys page:
- Enter a meaningful name for the API key to identify its purpose.
- Select an expiration period. Available options include 1 week, 1 month, 1 year, or never.
- Generate the API key.
Important
The Public Key and Secret Key are displayed only onceat the time of creation. Make sure to copy and store them securely. Lost keys cannot be recovered and must be regenerated.
Public vs Secret Keys
Jiroshi distinguishes between public and secret API keys to enforce proper security boundaries:
- Public Key (pk) - Safe to use in client-side applications such as web or mobile frontends. Required for all public-facing API calls.
Sample Public Key (pk)
bashpk:12a3b456-1ab2-3c45-4d67-21f72ad886f3:RK07B89pGD4J3-VypELpwDX4z1ZX0yF1R_0au6EZibU=
- Secret Key (sk) - Must never be exposed on the frontend. Intended strictly for secure server-to-server operations, such as payment processing or privileged administrative actions.
Sample Secret Key (sk)
bashsk:12a3b456-1ab2-3c45-4d67-21f72ad886f3:RK07B89pGD4J3-VypELpwDX4z1ZX0yF1R_0au6EZibU=
Security Warning
Do not store or transmit secret keys in frontend code, public repositories, or client-side environments. Compromised secret keys can lead to irreversible account-level damage.
Current Usage
At present, all documented API endpoints require only the use of the Public Key (pk). While Secret Keys are not actively used in the current API surface, they are reserved for upcoming features and enhanced security-sensitive workflows.
Each API endpoint in this documentation is explicitly tagged to indicate whether it requires a pk or sk, allowing you to clearly distinguish frontend-safe and server-only operations.
Key Rotation Policy
Jiroshi does not enforce a key rotation policy. However, it is recommended to rotate your API keys periodically to enhance security.
Key Revocation Behavior
API keys are revokable. When a key is revoked, it is no longer valid and cannot be used to access the API. This ensures that compromised keys are quickly rendered ineffective.
API keys can be revoked from the Jiroshi Dashboard by simply deleting a particular key. It also gets revoked on expiration.
API Abuse policy
If API abuse is suspected, Jiroshi reserves the right to revoke API keys and take other measures to prevent abuse.
API Key Usage
All authenticated requests to the Jiroshi API must include a valid API key in the request headers. The API uses this key to identify the requesting account and to enforce access control rules.
API keys are passed using the x-api-keyheader. Requests missing this header or providing an invalid key will be rejected.
API Key Header
x-api-key: <YOUR_API_KEY>
Key Validation Rules
The Jiroshi API performs strict validation on every API key provided with a request. A request will fail if any of the following conditions apply:
- The API key is missing from the request headers.
- The API key is malformed, invalid, or does not exist.
- The API key has expired.
- The API key type does not match the endpoint requirements (for example, using a Secret Key where a Public Key is expected, or vice versa).
API Key Errors
All errors related to API key authentication and validation use the standardized error codeAPI_KEY_ERR.
The HTTP status code and error message will vary depending on the failure scenario (for example, missing credentials, expired keys, or invalid key usage). Detailed information about response formats, error structures, and status codes is covered in a later section of this documentation.
Sample Error Response
{
"status": false,
"results": false,
"message": "API key missing",
"data": null,
"error_code": "INVALID_TOKEN_ERR"
}Retry Behavior & Best Practices
Requests that fail due to API key errors should not be retried automatically. These errors indicate a client-side configuration issue that must be resolved before the request can succeed.
- Ensure the
x-api-keyheader is present. - Verify that the correct API key type (pk or sk) is being used.
- Confirm that the API key has not expired or been revoked.
- Rotate the API key immediately if compromise is suspected.
Retrying the same request with an invalid API key will always result in failure.
Rate Limiting & API Keys
API requests are rate-limited on a per-API-key basis to protect the platform and ensure fair usage across accounts.
- Requests exceeding the allowed rate are rejected with an appropriate HTTP status code.
- Exceeding a rate limit does not revoke or invalidate the API key.
- Clients should implement exponential backoff before retrying requests.
- Rate limits may vary based on API key type, endpoint category, and account configuration.
Response Format
All Jiroshi API responses follow a consistent, envelope-based JSON structure. This applies to both successful and failed requests, allowing clients to reliably parse and handle responses across all endpoints.
Standard Response Structure
{
"status": true,
"results": true,
"message": "Success",
"data": {
"id": "c1a2b3d4-e89b-12d3-a456-426614174000",
"name": "Introduction to Backend Development",
"is_active": true,
"created_at": "2025-01-12T10:42:31Z"
},
"error_code": null
}- status - Indicates whether the request was successfully processed (
true) or failed (false). - results - Indicates whether the
datafield is non-null. - message - A human-readable success or error message.
- data - The response payload containing resource data.
- error_code - A machine-readable error identifier, or
nullfor successful responses.
Paginated Response Structure
Endpoints that return collections use a paginated response format. Pagination metadata is included alongside the result set.
Paginated Response Structure
{
"status": true,
"results": true,
"message": "Successfully Fetched",
"data": {
"results": [
{
"uuid": "a12f3c9b-4e91-44de-bf6a-9f1a2a6d90ab",
"title": "Advanced Django Course",
"description": "",
"thumbnail": "<thumbnail_url>",
"duration": "39600.9667",
"created_at": "2025-10-02T14:20:11.544767Z",
"is_enrolled": false
},
{
"uuid": "a12f3c9b-4e91-44de-bf6a-9f1a2a6d90ab",
"title": "Learn Python",
"description": "",
"thumbnail": "<thumbnail_url>",
"duration": "15876.9667",
"created_at": "2025-10-02T14:20:11.544767Z",
"is_enrolled": false
},
{
"uuid": "a12f3c9b-4e91-44de-bf6a-9f1a2a6d90ab",
"title": "Learn JavaScript",
"description": "",
"thumbnail": "<thumbnail_url>",
"duration": "15876.9667",
"created_at": "2025-10-02T14:20:11.544767Z",
"is_enrolled": false
}
],
"pagination": {
"count": 3,
"total_pages": 1,
"current_page": 1,
"next": null,
"previous": null
}
},
"error_code": null
}- results - A list of resource objects for the current page.
- pagination - Metadata used to navigate large result sets.
Error Response Structure
Error responses use the same envelope structure, withstatus andresults set tofalse,data set tonullor maybe some structured error, and a non-nullerror_code.
Sample Error Response
{
"status": false,
"results": false,
"message": "API key missing",
"data": null,
"error_code": "INVALID_TOKEN_ERR"
}Error Codes
Jiroshi APIs use standardized error codes to help clients reliably identify and handle different failure scenarios. Error codes are string literals that remain consistent across API versions and environments, even if the human-readable error message changes.
Whenever an error occurs, the response includes a non-nullerror_code field along with an appropriate HTTP status code and message.
Data & Validation Errors
- INTEGRITY_ERR - Database integrity constraint violations, such as foreign key or uniqueness mismatches.
INTEGRITY_ERR
json{ "status": false, "results": false, "message": "Database integrity error !", "data": null, "error_code": "INTEGRITY_ERR" } - VALIDATION_ERR - Invalid input data or failed validation rules based on the request payload.
VALIDATION_ERR
json{ "status": false, "results": false, "message": "API key missing", "data": null, "error_code": "VALIDATION_ERR" }
Authentication & Authorization Errors
- API_KEY_ERR - Issues related to API key authentication, including missing, invalid, malformed, or expired API keys.
API_KEY_ERR
json{ "status": false, "results": false, "message": "API key missing", "data": null, "error_code": "API_KEY_ERR" } - INVALID_TOKEN_ERR - Student authentication failures due to missing, invalid, malformed, or expired access or refresh tokens.
INVALID_TOKEN_ERR
json{ "status": false, "results": false, "message": "Student not authenticated", "data": null, "error_code": "INVALID_TOKEN_ERR" } - ACCESS_DENIED_ERR - Unauthorized access attempts to resources that do not belong to the requesting tenant.
ACCESS_DENIED_ERR
json{ "status": false, "results": false, "message": "Access denied to this resource !", "data": null, "error_code": "ACCESS_DENIED_ERR" }
Resource State Errors
- ALREADY_EXISTS_ERR - Attempt to create a resource that already exists.
ALREADY_EXISTS_ERR
json{ "status": false, "results": false, "message": "Record already exists !", "data": null, "error_code": "ALREADY_EXISTS_ERR" } - NOT_FOUND_ERR - Requested resource could not be found.
NOT_FOUND_ERR
json{ "status": false, "results": false, "message": "Record not found !", "data": null, "error_code": "NOT_FOUND_ERR" }
Server Errors
- INTERNAL_ERR - An unhandled server-side exception. If this error is encountered, please report it with request details as soon as possible.
INTERNAL_ERR
json{ "status": false, "results": false, "message": "Internal Server Error", "data": null, "error_code": "INTERNAL_ERR" }
Clients are strongly encouraged to rely onerror_code values and HTTP Response codes for programmatic error handling rather than parsing response messages, which are intended primarily for human readability.
Pagination Usage
Pagination is applied to all listing APIs in Jiroshi. By default, the API uses cursor-based pagination to ensure faster response times and better performance on large datasets.
Tenants may override this behavior and use page-offset based pagination by explicitly passing the query parameter pagination:page:
Override Default Pagination to Page Offset Pagination
GET /courses/?pagination=page
Cursor-based pagination can also be explicitly enforced usingpagination=cursor, although this is the default behavior and does not need to be specified.
Performance Note
Cursor-Based Pagination Response
When using cursor-based pagination, the response includes navigation URLs and encoded cursor values that can be used to fetch the next or previous set of results.
Cursor-Based Pagination Response
{
"status": true,
"results": true,
"message": "Successfully Fetched",
"data": {
"results": [
{
"uuid": "723a743c-a012-40ee-bebc-dc24c48818bf",
"title": "Course Dummy v3",
"description": "Test Desc",
"thumbnail": "https://jiroshi-static-dev.s3.ap-south-1.amazonaws.com/course-thumbnail/...",
"duration": "15.9667",
"created_at": "2025-11-01T06:41:03.008653Z",
"is_enrolled": false
},
{
"uuid": "a9fb5567-a9ae-4980-add7-763c2aca0351",
"title": "Course Test V2",
"description": "",
"thumbnail": "<course_thumbnail>",
"duration": "148.3854",
"created_at": "2025-10-19T19:40:28.598591Z",
"is_enrolled": false
}
],
"pagination": {
"next": "https://api.jiroshi.com/api/v1/public/courses/?cursor=...",
"previous": "https://api.jiroshi.com/api/v1/public/courses/?cursor=...",
"next_cursor": "cD0yMDI1LTEwLTE5KzE5JTNBNDAlM0EyOC41OTg1OTElMkIwMCUzQTAw",
"previous_cursor": "cj0xJnA9MjAyNS0xMC0xOSsxOSUzQTQwJTNBMjguNTk4NTkxJTJCMDAlM0EwMA=="
}
},
"error_code": null
}- next - Fully constructed URL to fetch the next page of results, if available.
- previous - Fully constructed URL to fetch the previous page of results, if available.
- next_cursor - Encoded cursor value for fetching the next set of results programmatically.
- previous_cursor - Encoded cursor value for fetching the previous set of results.
Clients may either follow the provided pagination URLs directly or extract and reuse cursor values as query parameters in subsequent requests.
Using Cursor Parameters
Cursor-based pagination uses encoded cursor values to determine the starting point for the next or previous set of results. These cursor values are returned in thepagination object of a paginated response.
To fetch the next or previous page, include thecursor query parameter in your request using the corresponding cursor value.
Fetching the Next Page
Next Page Request
GET /courses/?cursor=<NEXT_CURSOR_VALUE>
The next_cursor value is used to retrieve the next set of results relative to the current response. Ifnext_cursor isnull, no further pages are available.
Fetching the Previous Page
Previous Page Request
GET /courses/?cursor=<PREVIOUS_CURSOR_VALUE>
The previous_cursor value allows navigating backward through the result set. Ifprevious_cursor isnull, the current page is the first page.
Important Notes
- Cursor values are opaque and should not be decoded or modified by clients.
- Cursor-based pagination guarantees consistent ordering even when underlying data changes.
- Mixing cursor-based and page-based pagination within the same request flow is not supported.
Cursor Based Pagination Limitations
With cursor based pagination, the number of results that can be fetched in a single request is fixed to 20 items. If you need to fetch more results, you will need to make multiple requests.
Also, you won't have access to the count of total number of items and related details about the listing data.
Page-Based (Offset) Pagination
In addition to cursor-based pagination, Jiroshi APIs support traditional page-offset based pagination. This pagination strategy must be explicitly enabled by passing thepagination=page query parameter.
Page-based pagination allows clients to request a specific page number and control the number of items returned per page. This approach is useful for simple navigation and UI-driven pagination but comes with performance trade-offs.
Enabling Page-Based Pagination
Page-Based Pagination Request
GET /courses/?pagination=page&page=1&page_size=10
- pagination - Must be set to
pageto enable page-based pagination. - page - The page number to fetch.
- page_size - Number of items to return per page (Max allowed is 150).
Page-Based Pagination Response
Page-Based Pagination Response
{
"status": true,
"results": true,
"message": "Successfully Fetched",
"data": {
"results": [
{
"uuid": "723a743c-a012-40ee-bebc-dc24c48818bf",
"title": "Course Dummy",
"description": "Description",
"thumbnail": "<thumbnail_url>",
"duration": "1599.9667",
"created_at": "2025-11-01T06:41:03.008653Z",
"is_enrolled": false
}
],
"pagination": {
"count": 21,
"total_pages": 3,
"current_page": 3,
"next": null,
"previous": "https://api.jiroshi.com/api/v1/public/courses/?page=2&page_size=10&pagination=page"
}
},
"error_code": null
}Pagination Fields
- count - Total number of items available.
- total_pages - Total number of pages based on the current
page_size. - current_page - The currently requested page number.
- next - URL to fetch the next page, or
nullif no further pages exist. - previous - URL to fetch the previous page, or
nullif the current page is the first page.
Page-Offset Based Pagination Limitations
- With page-offset based pagination, fetching data becomes slower as page numbers increase due to database offset scans.
- Results may become inconsistent if data changes between requests.
- Not suitable for large datasets or high-frequency access patterns.
When to Use Page-Based Pagination
- When building simple, UI-driven pagination controls.
- When explicit page navigation is required.
- When dataset size is small and performance is not critical.
For most production use cases, cursor-based pagination remains the recommended and default approach in Jiroshi APIs.
Selections & Filters
Jiroshi APIs provide selection and filtering mechanisms to optimize data retrieval, reduce response payload size, and improve performance for data-intensive endpoints.
Selections
Selections allow clients to explicitly specify which fields should be returned in the response. This is particularly useful for list and retrieve APIs where returning the full object is unnecessary.
For example, when displaying a list of lessons where only the title and description are required, selections can be used to fetch only those fields.
Selections Query Parameter
GET /courses/<course_id>/lessons/?selections=title,description
- Only fields included in
selectionsare returned in the response. - Selections are restricted to a predefined set of allowed fields per API.
- Invalid or unsupported selection fields are silently ignored.
- If no selections are provided, or all provided selections are invalid, the API returns all allowed fields by default.
Not all APIs support selections. Wherever supported, the list of allowed selectable fields is documented explicitly for that endpoint.
Filters (Listing APIs Only)
Listing APIs support a set of generic filters that allow clients to narrow down results based on search terms, ordering, and date ranges.
Search
To perform a generic search across all searchable fields, use thesearch query parameter.
Generic Search
GET /courses/?search=backend
Field-specific searches can also be performed by using the field name directly as a query parameter.
Field-Specific Search
GET /courses/?title=django
Searchable fields vary by API and are documented individually for each endpoint.
Ordering
All listing APIs apply a default ordering of-created_at(descending by creation time).
This behavior can be overridden using theordering query parameter.
Ordering Examples
# Ascending order by duration GET /courses/?ordering=duration # Descending order by duration GET /courses/?ordering=-duration
Date Range Filters
Date range filtering follows a consistent naming convention for all supported date fields.
<field>_after- Filters records after the specified date.<field>_before- Filters records before the specified date.
Date Range Filter Example
GET /courses/?created_at_after=2025-01-01T00:00:00Z&created_at_before=2025-01-31T23:59:59Z
Important: All date values must be provided in UTC format.
Get Instructor Profile
GETFilters: Not supported
Response
{
"status": true,
"results": true,
"message": "Instructor Profile Fetched !",
"data": {
"instructor": {
"username": "demo.instructor",
"email": "demo.instructor@mail.com",
"country_code": "+91",
"display_name": "Demo Instructor",
"phone_number": "1234567890"
},
"profile": {
"bio": "The bio for a test instructor.",
"location": "Sector 1, State, Country",
"profile_picture": "<profile_picture>"
}
},
"error_code": null
}country_codephone_numberbiolocationprofile_picture
Get Instructor KPIs
GETFilters: Not supported
Response
{
"status": true,
"results": true,
"message": "KPIs Fetched !",
"data": {
"courses": {
"total": 3,
"in_last_thirty_days": 0
},
"signups": {
"total": 4,
"in_last_thirty_days": 4
},
"enrollments": {
"total": 4,
"in_last_thirty_days": 4
}
},
"error_code": null
}totalrepresents the all-time count for the metric.in_last_thirty_daysrepresents activity within the last 30 days, calculated using UTC timestamps.
Student Authentication (Introduction)
Jiroshi currently only supports standard JWT-based authentication mechanism for student authentication and session management. This flow is used for all student-facing actions such as sign-up, login, enrollment, and course access.
Upon successful authentication, a student is issued an access token and a refresh token. The access token is used to authenticate API requests, while the refresh token is used to obtain new access tokens when the current one expires.
All authentication APIs are accessed using the Public API Key (pk) of an instructor. When a student authenticates using an instructor’s public key, that student is permanently associated with the corresponding instructor tenant.
This tenant-based authentication model ensures strict isolation between instructors. Tokens issued under one instructor’s API key cannot be used to access resources belonging to another instructor.
Important
Authentication Transport & Client Detection
Jiroshi adapts its authentication token handling based on the detected client environment to ensure maximum security while supporting multiple application types.
Browser-Based Clients
When a request is identified as originating from a browser environment, refresh tokens are issued and stored exclusively via HTTP-only cookies. These cookies are inaccessible to browser-side JavaScript and are automatically included in subsequent refresh requests by the browser.
In this mode, refresh tokens are never exposed in API responses or request payloads, significantly reducing the risk of token theft via XSS or client-side compromise.
Cross-Origin Requests
credentials: 'include' (Fetch API) or withCredentials: true (Axios) in your request configuration.Non-Browser Clients
For non-browser clients such as mobile applications, desktop clients, or backend services, refresh tokens are returned directly in the API response payload. Subsequent refresh requests must include the refresh token explicitly in the request body.
This mode is intended only for environments where secure storage of tokens is handled by the client platform itself.
Development Mode
During local development, strict cookie policies (SameSite, Secure) can sometimes hinder testing on localhost. You can switch to a developer-friendly mode by setting the following header:
Force Development Mode
X-Client-Type: dev
Effect: In this mode, just like with non-browser clients, the refresh token is transported via the request and response payloads instead of cookies. This makes it easier to inspect and manage tokens manually during development.
Forcing API Mode
In certain edge cases-such as React Native or Electron-based applications-the client may be incorrectly detected as a browser. In such scenarios, token handling can be explicitly forced to API mode by setting the following request header:
Force API Client Mode
X-Client-Type: non-browser
Restricted Usage
Jiroshi reserves the right to introduce additional validation, restrictions, or rate limits on forced API mode usage to prevent abuse.
Student Signup
POSTFilters: Not supported
Request Body
Signup Payload
{
"identifier": "dummy@mail.com",
"password": "12345678"
}Server-Side Validation Rules
Server-side Validations
- The
identifiermust be unique within the instructor tenant. identifierlength must be between 1 and 255 characters.passwordlength must be between 8 and 72 characters.
All additional identifier validation (format, pattern, semantics) must be enforced on the client side.
Response (Browser Environment)
Browser Response
{
"access_token": "<access_token>"
}Cross-Origin Requests
credentials: 'include' (Fetch API) or withCredentials: true (Axios) in your request configuration.Response (Non-Browser / Dev Mode / Forced API Mode)
API Client Response
{
"access_token": "<access_token>",
"refresh_token": "<refresh_token>"
}Student Login
POSTFilters: Not supported
Request Body
Login Payload
{
"identifier": "muteen@mail.com",
"password": "12345678"
}identifier must match the value used during signup and must be unique within the instructor tenant.Response (Browser Environment)
Browser Response
{
"access_token": "<access_token>"
}Cross-Origin Requests
credentials: 'include' (Fetch API) or withCredentials: true (Axios) in your request configuration.Response (Non-Browser / Dev Mode / Forced API Mode)
API Client Response
{
"access_token": "<access_token>",
"refresh_token": "<refresh_token>"
}Student Refresh Access Token
POSTFilters: Not supported
Request Body (Browser Environment)
Cross-Origin Requests
credentials: 'include' (Fetch API) or withCredentials: true (Axios) in your request configuration.Request Body (Non-Browser / Dev Mode / Forced API)
Refresh Token Payload
{
"refresh_token": "<refresh_token>"
}Response (Browser Environment)
Browser Response
{
"access_token": "<new_access_token>"
}Response (Non-Browser / Dev Mode / Forced API)
API Client Response
{
"access_token": "<new_access_token>",
"refresh_token": "<new_refresh_token>"
}Token Lifetime & Rotation Rules
1. Token Lifetimes
- Access tokens: 15 minutes
- Refresh tokens: 7 days (sliding window)
2. Rotation Policy (Important)
Jiroshi implements strict Refresh Token Rotation. Every time a refresh token is used to get a new access token, a new refresh token is issued in the response.
- You must replace the old refresh token with the new one immediately.
- The old refresh token becomes instantly invalid.
Security: Reuse Detection
If a reused token is detected, the system will:
- Immediately revoke the entire family of tokens (including the valid one).
- Force the user to sign in again.
Student Logout
POSTFilters: Not supported
Authentication Requirements
Request Body
Logout Request Body (Non-Browser / Dev / Forced API Mode)
{
"refresh_token": "<token>"
}Client-Specific Behavior
- Browser Clients: Calling this endpoint invalidates the refresh token stored in the HTTP-only cookie. You must set
credentials: 'include'(Fetch) orwithCredentials: true(Axios) to ensure the cookie is sent. Clients should also manually flush the access token from local storage. - Non-Browser & Dev Mode: These clients must call this endpoint passing the `refresh_token` in the request body. This blacklists the token to reduce the blast radius in case of compromise. Clients should then flush both access and refresh tokens from local storage.
Response
Logout Response
{
"status": true,
"results": true,
"message": "Logged out successfully",
"data": null,
"error_code": null
}Get Student Profile
GETFilters: Not supported
Authentication Requirements
Response
Student Profile Response
{
"status": true,
"results": true,
"message": "Student Profile Fetched !",
"data": {
"uuid": "<student_uuid>",
"identifier": "<student_identifier>"
},
"error_code": null
}- This endpoint can be used to verify whether a student is currently authenticated.
- If the access token is expired or invalid, the request will fail, indicating that re-authentication or token refresh is required.
- Additional student profile fields will be added in future versions without breaking existing clients.
Update Student Account Details
PUTFilters: Not supported
Authentication Requirements
Request Body
Update Account Payload
{
"identifier": "dummy@mail.com",
"password": "1234567890",
"current_password": "12345678"
}Rules
- At least one of
identifierorpasswordmust be provided. current_passwordis mandatory for all update requests and is used to verify the authenticity of the request.- Identifier uniqueness is enforced within the instructor tenant.
- Password updates follow the same length constraints as signup and login flows.
Response
Update Response
{
"status": true,
"results": true,
"message": "Student account details updated !",
"data": null,
"error_code": null
}Student Identifier Lookup
POSTFilters: Not supported
Request Body
Lookup Payload
{
"identifier": "muteen@mail.com"
}identifier value must follow the same rules as used during signup and login. The lookup is scoped strictly to the current instructor tenant.Response
Lookup Response
{
"status": true,
"results": true,
"message": "Status fetched",
"data": {
"student_exists": true
},
"error_code": null
}student_existsindicates whether the identifier is already registered under the current instructor tenant.- This endpoint is suitable for debounced checks during signup or account update flows.
- The lookup does not reveal any additional information about the student.
List Courses
GETAuthenticated Student Use-Case (Important)
is_enrolled field. But if the student access token is expired or invalid, it will throw authentication error.Now, if the access token is not provided with the request, the
is_enrolledfield will be set tofalse for every course in the list.Supported selectable fields:
| Name | Type | Description |
|---|---|---|
| uuid | string | The unique identifier of the course. |
| title | string | The title of the course. |
| description | string | The description of the course. |
| thumbnail | string | The thumbnail URL of the course. (Image File) |
| duration | string (Seconds) | The duration of the course IN SECONDS. |
| created_at | string (UTC Date) | The creation date (IN UTC DATETIME FORMAT) of the course. |
is_enrolled field is always included in the response and cannot be excluded via selections. Check Response.Selections Usage Example
Selections Usage Example
GET /courses/?selections=uuid,title
Search Filter Query Params:
| Name | Type | Description |
|---|---|---|
| search | string | Searches for a match in course titles or descriptions. |
| title | string | Search courses by title |
Search Filter Usage Example
Usage Example
GET /courses/?search=python
Ordering Fields:
| Name | Type | Description |
|---|---|---|
| created_at | string | Orders the results by created_at. |
| duration | string | Orders the results by duration. |
Ordering Usage Example
Usage Example
GET /courses/?ordering=created_at
Ordering usage Tip
Although already mentioned in 'Selections & Filters' section, it is important to note that, if you want to order the results in descending order, prefix the field name with a minus sign (-).
For example, to order the results by created_at in descending order, useordering=-created_at .
The default ordering is -created_at.
Date Range Filters:
| Name | Type | Description |
|---|---|---|
| created_at_after | string | Filters the results to include only courses created after the specified date (IN UTC DATETIME FORMAT). |
| created_at_before | string | Filters the results to include only courses created before the specified date (IN UTC DATETIME FORMAT). |
Date Range Filter Usage Example
Date Range Filter Usage Example
GET /courses/?created_at_after=2023-01-01&created_at_before=2023-12-31
Pagination
pagination=pagein query params.Response
Course List Response
{
"status": true,
"results": true,
"message": "Successfully Fetched",
"data": {
"results": [
{
"uuid": "11111111-aaaa-bbbb-cccc-000000000001",
"title": "Introduction to Backend Systems",
"description": "Learn the fundamentals of backend development.",
"thumbnail": "<course_thumbnail>",
"duration": "12500.50",
"created_at": "2025-01-10T10:00:00Z",
"is_enrolled": false
},
{
"uuid": "22222222-aaaa-bbbb-cccc-000000000002",
"title": "Advanced API Design",
"description": "Deep dive into scalable API architectures.",
"thumbnail": "<course_thumbnail>",
"duration": "42500.75",
"created_at": "2025-01-05T08:30:00Z",
"is_enrolled": true
}
],
"pagination": {
"next": null,
"previous": null,
"next_cursor": null,
"previous_cursor": null
}
},
"error_code": null
}Get Course Details
GETPath Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| courseUUID | string | Yes | The unique identifier of the course. |
Authenticated Student Use-Case (Important)
is_enrolled field. But if the student access token is expired or invalid, it will throw authentication error.Now, if the access token is not provided with the request, the
is_enrolledfield will be set tofalse for every course in the list.Supported selectable fields:
| Name | Type | Description |
|---|---|---|
| uuid | string | The unique identifier of the course. |
| title | string | The title of the course. |
| description | string | The description of the course. |
| thumbnail | string | The thumbnail URL of the course. (Image File) |
| duration | string (Seconds) | The duration of the course IN SECONDS. |
| created_at | string (UTC Date) | The creation date (IN UTC DATETIME FORMAT) of the course. |
is_enrolled field is always included in the response and cannot be excluded via selections. Check Response.Selections Usage Example
Selections Usage Example
GET /courses/{courseUUID}/?selections=uuid,titleResponse
Response
{
"status": true,
"results": true,
"message": "Successfully fetched !",
"data": {
"uuid": "11111111-aaaa-2222-bbbb-333333333333",
"title": "Demo Course",
"description": "Dummy description",
"thumbnail": "<thumbnail_url>",
"duration": "15900.9667",
"created_at": "2025-10-02T14:20:11.544767Z",
"is_enrolled": false
},
"error_code": null
}List Course Lessons
GETNote:
Access Token is NOT required to access this endpoint.
Path Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| courseUUID | string | Yes | The unique identifier of the course. |
Supported selectable fields:
| Name | Type | Description |
|---|---|---|
| uuid | string | The unique identifier of the lesson. |
| title | string | The title of the lesson. |
| description | string | The description of the lesson. |
| duration | string (Seconds) | The duration of the lesson IN SECONDS. |
| created_at | string (UTC Date) | The creation date (IN UTC DATETIME FORMAT) of the lesson. |
Selections Usage Example
Selections Usage Example
GET /courses/{courseUUID}/lessons/?selections=uuid,titleSearch Filter Query Params:
| Name | Type | Description |
|---|---|---|
| search | string | Searches for a match in lesson titles or descriptions. |
| title | string | Search lessons by title |
Search Filter Usage Example
Usage Example
GET /courses/{courseUUID}/lessons/?search=pythonOrdering Fields:
| Name | Type | Description |
|---|---|---|
| created_at | string | Orders the results by created_at. |
| duration | string | Orders the results by duration. |
Ordering Usage Example
Usage Example
GET /courses/{courseUUID}/lessons/?ordering=created_atOrdering usage Tip
Although already mentioned in 'Selections & Filters' section, it is important to note that, if you want to order the results in descending order, prefix the field name with a minus sign (-).
For example, to order the results by created_at in descending order, useordering=-created_at .
The default ordering is -created_at.
Date Range Filters:
| Name | Type | Description |
|---|---|---|
| created_at_after | string | Filters the results to include only lessons created after the specified date (IN UTC DATETIME FORMAT). |
| created_at_before | string | Filters the results to include only lessons created before the specified date (IN UTC DATETIME FORMAT). |
Date Range Filter Usage Example
Date Range Filter Usage Example
GET /courses/{courseUUID}/lessons/?created_at_after=2023-01-01&created_at_before=2023-12-31Pagination
pagination=pagein query params.Response
Lesson List Response
{
"status": true,
"results": true,
"message": "Successfully Fetched",
"data": {
"results": [
{
"uuid": "11111111-1111-1111-1111-111111111111",
"title": "Lesson 1",
"description": "Description 1",
"duration": "860.9667",
"created_at": "2025-10-24T06:01:10.463300Z"
},
{
"uuid": "22222222-2222-2222-2222-222222222222",
"title": "Lesson 2",
"description": "Description 2",
"duration": "860.9667",
"created_at": "2025-10-24T06:10:09.708923Z"
},
{
"uuid": "33333333-3333-3333-3333-333333333333",
"title": "Lesson 3",
"description": "Description 3",
"duration": "650.0000",
"created_at": "2025-10-28T06:12:18.083998Z"
},
{
"uuid": "44444444-4444-4444-4444-444444444444",
"title": "Lesson 4",
"description": "Description 4",
"duration": "860.9667",
"created_at": "2025-10-28T18:49:19.128782Z"
},
{
"uuid": "55555555-5555-5555-5555-555555555555",
"title": "Lesson 5",
"description": "Description 5",
"duration": "860.9667",
"created_at": "2025-10-30T18:17:24.966641Z"
},
{
"uuid": "66666666-6666-6666-6666-666666666666",
"title": "Lesson 6",
"description": "Description 6",
"duration": "920.6873",
"created_at": "2025-10-31T19:10:51.296300Z"
}
],
"pagination": {
"next": null,
"previous": null,
"next_cursor": null,
"previous_cursor": null
}
},
"error_code": null
}Enroll Student to Course
POSTWe'll eventually make the use of secret key (sk) mandatory for this endpoint.
Filters: Not supported
Authentication Requirements
- A valid student access token is required to authenticate the student.
- A valid instructor public API key (pk) must be provided with the request.
Request Body
Enrollment Payload
{
"course_uuid": "aaaaaaaa-1111-bbbb-2222-cccccccccccc"
}course_uuid must reference an existing course under the instructor tenant.Response
Enrollment Response
{
"status": true,
"results": true,
"message": "Enrolled successfully !",
"data": {
"enrollment_id": "bbbbbbbb-bbbb-bbbb-cccc-dddddddddddd"
},
"error_code": null
}- Re-enrolling an already enrolled student may result in an
ALREADY_EXISTS_ERR. - Enrollment logic will be extended in future versions to support paid courses and additional validation rules.
Enrollment Error Response
{
"status": false,
"results": false,
"message": "Student already enrolled !",
"data": null,
"error_code": "ALREADY_EXISTS_ERR"
}Real-World Business Workflow (Recommended for Now)
Until built-in payments are available, tenants can choose to keep student signup and enrollment APIs private.
In this approach, the tenant first collects payment outside the platform and then creates the student account and enrolls the student manually using the API.
Students do not sign up or enroll on their own. Access is granted only after the tenant confirms payment.
Why this is useful
- Ensures only paid students get access.
- Gives full control to the tenant.
- Works well for early launches and private batches.
Security note
Since public API keys can be misused, tenants should design access in a way where enrolling without payment does not expose valuable content.
Common ways to do this include using one common course, enrolling paid students into all courses, or keeping premium content behind additional checks.
This setup keeps the platform usable and safe until stronger payment checks are added.
Tenant himself/herself will be responsible for any payment security failures or any misconducts by students.
Get Lesson Details
GETPath Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| courseUUID | string | Yes | The unique identifier of the course. |
| lessonUUID | string | Yes | The unique identifier of the lesson. |
Supported selectable fields:
| Name | Type | Description |
|---|---|---|
| uuid | string | The unique identifier of the lesson. |
| title | string | The title of the lesson. |
| description | string | The description of the lesson. |
| duration | string (Seconds) | The duration of the lesson IN SECONDS. |
| video_url | string | The video URL of the lesson. (Video File) |
| created_at | string (UTC Date) | The creation date (IN UTC DATETIME FORMAT) of the lesson. |
Selections Usage Example
Selections Usage Example
GET /courses/{courseUUID}/lessons/{lessonUUID}/?selections=uuid,titleResponse
Response
{
"status": true,
"results": true,
"message": "Successfully fetched !",
"data": {
"uuid": "11111111-aaaa-2222-bbbb-333333333333",
"title": "Demo Course",
"description": "Dummy description",
"duration": "15900.9667",
"video_url": "<video_url>",
"created_at": "2025-10-02T14:20:11.544767Z"
},
"error_code": null
}Lesson Extra Resources
GETPath Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| courseUUID | string | Yes | The unique identifier of the course. |
| lessonUUID | string | Yes | The unique identifier of the lesson. |
Supported selectable resource fields:
| Name | Type | Description |
|---|---|---|
| notes | string | The notes of the lesson. |
| related_links | string | The related links of the lesson. |
Supported selectable file fields:
| Name | Type | Description |
|---|---|---|
| uuid | string | The unique identifier of the file. |
| title | string | The title of the file. |
| file_size | string | The file size (IN BYTES) of the file. |
| file_type | string | The file type of the file. |
| file_url | string | The file URL of the file. |
| created_at | string | The creation date (IN UTC DATETIME FORMAT) of the file. |
Selections Usage Example
Selections Usage Example
GET /courses/{courseUUID}/lessons/{lessonUUID}/resources/?selections=notes,related_links,title,file_size,file_urlSearch Filter Query Params for File Resources:
| Name | Type | Description |
|---|---|---|
| search | string | Searches for a match in lesson resource file titles or file_types. |
| title | string | Search lesson resource files by title |
| file_type | string | Search lesson resource files by file_type |
Search Filter Usage Example
Usage Example
GET /courses/{courseUUID}/lessons/{lessonUUID}/resources/?search=ebookOrdering Fields for File Resources:
| Name | Type | Description |
|---|---|---|
| created_at | string | Orders file resources list by created_at. |
| file_size | string | Orders file resources list by file_size. |
Ordering Usage Example
Usage Example
GET /courses/{courseUUID}/lessons/{lessonUUID}/resources/?ordering=created_atOrdering usage Tip
Although already mentioned in 'Selections & Filters' section, it is important to note that, if you want to order the results in descending order, prefix the field name with a minus sign (-).
For example, to order the results by created_at in descending order, useordering=-created_at .
The default ordering is -created_at.
Date Range Filters:
| Name | Type | Description |
|---|---|---|
| created_at_after | string | Filters the results to include only file resources created after the specified date (IN UTC DATETIME FORMAT). |
| created_at_before | string | Filters the results to include only file resources created before the specified date (IN UTC DATETIME FORMAT). |
Date Range Filter Usage Example
Date Range Filter Usage Example
GET /courses/{courseUUID}/lessons/{lessonUUID}/resources/?created_at_after=2023-01-01&created_at_before=2023-12-31Pagination
pagination=pagein query params.Response
Response
{
"status": true,
"results": true,
"message": "Successfully Fetched",
"data": {
"notes": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam nec metus nec ante feugiat finibus. Nullam nec metus nec ante feugiat finibus.",
"related_links": [
{
"url": "https://chatgpt.com/",
"title": "ChatGPT"
}
],
"results": [
{
"uuid": "11111111-aaaa-2222-bbbb-333333333333",
"title": "Dummy ref material",
"file_size": 8130,
"file_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"file_url": "<file_url>",
"created_at": "2025-10-31T19:11:27.180036Z"
},
{
"uuid": "11111111-cccc-2222-dddd-333333333333",
"title": "Dummy ref material 2",
"file_size": 6130,
"file_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"file_url": "<file_url>",
"created_at": "2025-10-31T19:11:27.180036Z"
}
],
"pagination": {
"next": null,
"previous": null,
"next_cursor": null,
"previous_cursor": null
}
},
"error_code": null
}Student Enrolled Courses
GETSupported selectable fields:
| Name | Type | Description |
|---|---|---|
| uuid | string | The unique identifier of the course. |
| title | string | The title of the course. |
| description | string | The description of the course. |
| thumbnail | string | The thumbnail URL of the course. (Image File) |
| duration | string (Seconds) | The duration of the course IN SECONDS. |
| course_created_at | string (UTC Date) | The creation date (IN UTC DATETIME FORMAT) of the course. |
| enrolled_at | string (UTC Date) | The date (IN UTC DATETIME FORMAT) when the student enrolled in the course. |
Selections Usage Example
Selections Usage Example
GET /courses/enrolled/?selections=uuid,title
Search Filter Query Params:
| Name | Type | Description |
|---|---|---|
| search | string | Searches for a match in course titles or descriptions. |
| title | string | Search courses by title |
Search Filter Usage Example
Usage Example
GET /courses/enrolled/?search=python
Ordering Fields:
| Name | Type | Description |
|---|---|---|
| course_created_at | string | Orders the results by course_created_at. |
| duration | string | Orders the results by duration. |
| enrolled_at | string | Orders the results by enrolled_at. |
Ordering Usage Example
Usage Example
GET /courses/enrolled/?ordering=course_created_at
Ordering usage Tip
Although already mentioned in 'Selections & Filters' section, it is important to note that, if you want to order the results in descending order, prefix the field name with a minus sign (-).
For example, to order the results by created_at in descending order, useordering=-created_at .
The default ordering is -enrolled_at.
Date Range Filters:
| Name | Type | Description |
|---|---|---|
| created_at_after | string | Filters the results to include only courses created after the specified date (IN UTC DATETIME FORMAT). |
| created_at_before | string | Filters the results to include only courses created before the specified date (IN UTC DATETIME FORMAT). |
| enrolled_at_after | string | Filters the results to include only courses enrolled after the specified date (IN UTC DATETIME FORMAT). |
| enrolled_at_before | string | Filters the results to include only courses enrolled before the specified date (IN UTC DATETIME FORMAT). |
Date Range Filter Usage Example
Date Range Filter Usage Example
GET /courses/enrolled/?enrolled_at_after=2023-01-01&enrolled_at_before=2023-12-31
Pagination
pagination=pagein query params.Response
Course List Response
{
"status": true,
"results": true,
"message": "Successfully Fetched",
"data": {
"results": [
{
"uuid": "11111111-aaaa-bbbb-cccc-000000000001",
"title": "Introduction to Backend Systems",
"description": "Learn the fundamentals of backend development.",
"thumbnail": "<course_thumbnail>",
"duration": "12500.50",
"course_created_at": "2025-11-01T06:41:03.008653Z",
"enrolled_at": "2025-12-19T05:55:56.087766Z"
},
{
"uuid": "22222222-aaaa-bbbb-cccc-000000000002",
"title": "Advanced API Design",
"description": "Deep dive into scalable API architectures.",
"thumbnail": "<course_thumbnail>",
"duration": "42500.75",
"course_created_at": "2025-01-05T08:30:00Z",
"enrolled_at": "2025-12-20T05:55:56.087766Z"
}
],
"pagination": {
"next": null,
"previous": null,
"next_cursor": null,
"previous_cursor": null
}
},
"error_code": null
}