Discovery API Documentation
This document describes the Discovery API endpoints for retrieving course and program information.
Authentication
All endpoints support two authentication methods:
-
Session Authentication (for authenticated users)
- Uses session cookies from a logged-in session
- No additional headers required
-
Action Secret Authentication (for unauthenticated/public access)
- Header:
actionsecret: <your_action_secret> - Required when making requests without an active session
- Value must match the
ACTION_SECRETsetting
- Header:
Note: If a user is authenticated via session, the actionsecret header is not required.
GET /blendxapi/discovery/courses/
Description: Retrieves a list of available courses with support for pagination, search, and filtering.
Endpoint: GET <https://lms_endpoint/blendxapi/discovery/courses/>
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
limit |
integer | No | Number of records to return per page (default: 8, min: 1, max: 100). Values outside this range are automatically clamped. |
page |
integer | No | Page number (default: 1, 1-indexed). |
search |
string | No | Search term for course name, description, or overview. |
org |
string | No | Comma-separated list of organizations to filter by. |
tags |
string | No | Comma-separated list of tags to filter by. |
order_by |
string | No | Sort order in format {field}.{direction} (e.g., created_at.desc, display_name.asc). Default: created_at.desc. Direction defaults to desc if not specified. Note: display_name sorting requires Hasura configuration. |
fields |
string | No | Response optimization parameter. Values: light (default) or full. light excludes heavy fields like overview (~70% smaller response, faster). full includes all fields including overview HTML content. |
Response Format
The response is a JSON object containing the list of courses and pagination metadata.
| Field | Type | Description |
|---|---|---|
courses |
array | List of course objects (see details below). |
total_count |
integer | Total number of courses matching the criteria. |
has_more |
boolean | Indicates if more pages are available. |
limit |
integer | The limit used for the current page. |
page |
integer | The current page number. |
offset |
integer | The offset calculated from the page number. |
partial_errors |
object (optional) | Included when some courses fail to serialize. Contains count (integer) and errors (array of error objects with course_id, error_type, error_message). |
Course Object Attributes
The fields included depend on the fields parameter:
Light Mode (default) - Includes:
id(string): Unique UUID for the courseopenedx_course_id(string): Open edX course identifier stringdisplay_name(string): Course titledisplay_image(string): URL to the course card imageshort_description(string): Brief course descriptionprice(integer): Minimum price of the course (0 if free)currency(string): Currency code for the price (e.g., “usd”)start(string): Course start date (ISO 8601)end(string): Course end date (ISO 8601)org(string): Organization identifierorg_logo_url(string|null): URL to the organization logoorg_favicon_url(string|null): URL to the organization faviconcourse_mode(string): The slug of the default (lowest price) mode (e.g., “honor”)tags(array): List of tags associated with the courseis_invite_only(boolean): Indicates if the course is by invitation onlyis_published(boolean): Indicates if the course is currently publishedavg_rating(number): Average rating for the course (defaults to 0 if unavailable)
Full Mode - Includes all Light Mode fields plus:
overview(string): Full HTML description of the courseeffort(string): Estimated time effortenrollment_start(string): Enrollment start date (ISO 8601)enrollment_end(string): Enrollment end date (ISO 8601)certificate_available_date(string): Date when certificates become availablehas_any_active_web_certificate(boolean): Indicates if an active web certificate existslink_to_course(string): Direct URL to the course dashboardlanguage(string): Course language code (e.g., “en”)self_paced(boolean): true if self-paced, false if instructor-lednumber(string): Course number/codecourse_video_url(string|null): URL to the course introduction videoavailable_course_modes(array): List of all available modes for this course
Example Request
# Light mode (fast, default)
curl -X GET "https://lms_endpoint/blendxapi/discovery/courses/?limit=20&page=2&search=python&fields=light" \
-H "actionsecret: your_secret"
# Full mode (complete)
curl -X GET "https://lms_endpoint/blendxapi/discovery/courses/?limit=20&page=2&search=python&fields=full" \
-H "actionsecret: your_secret"
# With filters
curl -X GET "https://lms_endpoint/blendxapi/discovery/courses/?org=TestOrg&tags=health,midwifery&order_by=display_name.asc" \
-H "actionsecret: your_secret"
Example Response (Light Mode)
{
"courses": [
{
"id": "267ce96d-1454-4292-aa42-1a0487c7eaaa",
"openedx_course_id": "course-v1:Fundacion-Santa-Fe-de-Bogota+HOC201+2025_T2",
"display_name": "Proyecto Warra Jaramia",
"display_image": "https://lms.lms_endpoint/asset-v1:ZamsOrg+FOO346+type@asset+block@thumb.jpg",
"short_description": "Sabiduría Ancestral en la Atención del Parto...",
"price": 0,
"currency": "usd",
"start": "2025-02-01T00:00:00Z",
"end": "2027-02-01T00:30:00Z",
"org": "TestOrg",
"org_logo_url": "https://lms_endpoint/static/org_logos/testorg.png",
"org_favicon_url": "https://lms_endpoint/static/org_favicons/testorg.ico",
"course_mode": "honor",
"tags": ["health", "midwifery"],
"is_invite_only": false,
"is_published": true,
"avg_rating": 4.5
}
],
"total_count": 1,
"has_more": false,
"limit": 20,
"page": 2,
"offset": 20
}
Example Response (Full Mode)
{
"courses": [
{
"id": "267ce96d-1454-4292-aa42-1a0487c7eaaa",
"openedx_course_id": "course-v1:Fundacion-Santa-Fe-de-Bogota+HOC201+2025_T2",
"display_name": "Proyecto Warra Jaramia",
"display_image": "https://lms.lms_endpoint/asset-v1:ZamsOrg+FOO346+type@asset+block@thumb.jpg",
"short_description": "Sabiduría Ancestral en la Atención del Parto...",
"overview": "<!DOCTYPE html>...",
"price": 0,
"currency": "usd",
"start": "2025-02-01T00:00:00Z",
"end": "2027-02-01T00:30:00Z",
"effort": "01:00",
"enrollment_start": "2025-01-01T00:00:00Z",
"enrollment_end": "2025-03-01T00:00:00Z",
"certificate_available_date": "2027-02-03T00:30:00Z",
"has_any_active_web_certificate": false,
"link_to_course": "https://apps.lms_endpoint/dashboard/course/course-v1:Fundacion...",
"language": "en",
"self_paced": false,
"org": "TestOrg",
"org_logo_url": "https://lms_endpoint/static/org_logos/testorg.png",
"org_favicon_url": "https://lms_endpoint/static/org_favicons/testorg.ico",
"number": "FOO346",
"course_video_url": null,
"course_mode": "honor",
"available_course_modes": [
{
"modeSlug": "honor",
"minPrice": 0,
"modeDisplayName": "Honor",
"currency": "usd",
"visible": true
}
],
"tags": ["health", "midwifery"],
"is_invite_only": false,
"is_published": true,
"avg_rating": 4.5
}
],
"total_count": 1,
"has_more": false,
"limit": 8,
"page": 1,
"offset": 0
}
Error Responses
401 Unauthorized
{
"message": "Unauthorized",
"status": "failed"
}
Cause: Invalid or missing actionsecret header for unauthenticated requests.
500 Internal Server Error
{
"message": "Error fetching courses",
"status": "failed"
}
Cause: Server error during course retrieval.
GET /blendxapi/discovery/course/{openedx_course_id}/
Description: Retrieves detailed information about a specific course.
Endpoint: GET <https://lms_endpoint/blendxapi/discovery/course/{openedx_course_id}/>
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
openedx_course_id |
string | Yes | Open edX course identifier (e.g., course-v1:org+course+run) |
Request Parameters
None (all information comes from the path parameter).
Response Format
The response is a JSON object containing complete course details.
Course Object Attributes
| Field | Type | Description |
|---|---|---|
id |
string | Unique UUID for the course |
openedx_course_id |
string | Open edX course identifier string |
display_name |
string | Course title |
short_description |
string | Brief course description |
overview |
string | Full HTML description of the course |
course_image_url |
string | Full URL to course image (note: different field name than display_image in list endpoint) |
course_video_url |
string|null | URL to the course introduction video |
start |
string | Course start date (ISO 8601) |
start_display |
string | Human-readable start date display |
end |
string | Course end date (ISO 8601) |
effort |
string | Estimated time effort |
enrollment_start |
string | Enrollment start date (ISO 8601) |
enrollment_end |
string | Enrollment end date (ISO 8601) |
certificate_available_date |
string | Date when certificates become available |
has_any_active_web_certificate |
boolean | Indicates if an active web certificate exists |
language |
string | Course language code (e.g., “en”) |
self_paced |
boolean | true if self-paced, false if instructor-led |
is_invite_only |
boolean | Indicates if the course is by invitation only |
is_published |
boolean | Indicates if the course is currently published |
price |
integer | Minimum price of the course (0 if free) |
course_mode |
string | The slug of the default (lowest price) mode (e.g., “honor”) |
available_course_modes |
array | List of all available modes for this course |
organisation |
string | Organization name (note: string, not an object like in list endpoint) |
organisation_id |
string | UUID of the organization |
organisation_logo_url |
string|null | URL to the organization logo |
organisation_favicon_url |
string|null | URL to the organization favicon |
course_structure |
object | Hierarchical course structure with sections and subsections (see structure below) |
avg_rating |
number | Average rating for the course |
reviews |
array | List of review objects for the course |
Course Structure Object
The course_structure field contains:
| Field | Type | Description |
|---|---|---|
sections |
array | List of course sections, each containing name, usage_key, hide_from_toc, visible_to_staff_only, and subsections array |
total_sections |
integer | Total number of sections |
total_subsections |
integer | Total number of subsections |
course_info |
object | Course metadata including course_key, title, published_at, published_version, days_early_for_beta, entrance_exam_id, self_paced, course_visibility |
Example Request
curl -X GET "https://lms_endpoint/blendxapi/discovery/course/course-v1:Fundacion-Santa-Fe-de-Bogota+HOC201+2025_T2/" \
-H "actionsecret: your_secret"
Example Response
{
"id": "267ce96d-1454-4292-aa42-1a0487c7eaaa",
"openedx_course_id": "course-v1:Fundacion-Santa-Fe-de-Bogota+HOC201+2025_T2",
"display_name": "Proyecto Warra Jaramia",
"short_description": "Sabiduría Ancestral en la Atención del Parto...",
"overview": "<!DOCTYPE html>...",
"course_image_url": "https://lms.lms_endpoint/asset-v1:ZamsOrg+FOO346+type@asset+block@thumb.jpg",
"course_video_url": null,
"start": "2025-02-01T00:00:00Z",
"start_display": "February 1, 2025",
"end": "2027-02-01T00:30:00Z",
"effort": "01:00",
"enrollment_start": "2025-01-01T00:00:00Z",
"enrollment_end": "2025-03-01T00:00:00Z",
"certificate_available_date": "2027-02-03T00:30:00Z",
"has_any_active_web_certificate": false,
"language": "en",
"self_paced": false,
"is_invite_only": false,
"is_published": true,
"price": 0,
"course_mode": "honor",
"available_course_modes": [
{
"modeSlug": "honor",
"minPrice": 0,
"modeDisplayName": "Honor",
"currency": "usd",
"visible": true
}
],
"organisation": "Fundacion Santa Fe de Bogota",
"organisation_id": "123e4567-e89b-12d3-a456-426614174000",
"organisation_logo_url": "https://lms_endpoint/static/org_logos/fundacion.png",
"organisation_favicon_url": "https://lms_endpoint/static/org_favicons/fundacion.ico",
"course_structure": {
"sections": [
{
"name": "Introduction",
"usage_key": "block-v1:...",
"hide_from_toc": false,
"visible_to_staff_only": false,
"subsections": [
{
"name": "Getting Started",
"usage_key": "block-v1:...",
"inaccessible_after_due": false,
"hide_from_toc": false,
"visible_to_staff_only": false,
"exam": null
}
]
}
],
"total_sections": 1,
"total_subsections": 1,
"course_info": {
"course_key": "course-v1:Fundacion-Santa-Fe-de-Bogota+HOC201+2025_T2",
"title": "Proyecto Warra Jaramia",
"published_at": "2024-01-01T00:00:00Z",
"published_version": "abc123",
"days_early_for_beta": 0,
"entrance_exam_id": null,
"self_paced": false,
"course_visibility": "public"
}
},
"avg_rating": 4.5,
"reviews": [
{
"id": "review-uuid",
"user": "John Doe",
"rating": 5,
"comment": "Excellent course!",
"created_at": "2025-01-15T10:00:00Z"
}
]
}
Error Responses
401 Unauthorized
{
"message": "Unauthorized",
"status": "failed"
}
Cause: Invalid or missing actionsecret header for unauthenticated requests.
404 Not Found
{
"message": "Course not found",
"status": "failed"
}
Cause: Course with the specified openedx_course_id does not exist.
500 Internal Server Error
{
"message": "Error fetching course details",
"status": "failed"
}
Cause: Server error during course detail retrieval.
POST /search/course_discovery/
Description: Searches for courses based on a given search string.
Endpoint: POST <https://lms_endpoint/search/course_discovery/>
Note: This endpoint is part of a separate external service (not part of the main discovery API codebase).
Request Parameters
The request must be sent as application/x-www-form-urlencoded.
| Parameter | Type | Required | Description |
|---|---|---|---|
search_string |
string | No | The text to search for in course titles and descriptions. |
page_size |
integer | No | Number of results per page (default: 20, max: 100). |
page_index |
integer | No | Zero-based page index (default: 0). |
Response Format
| Field | Type | Description |
|---|---|---|
took |
integer | Time taken for the search (milliseconds). |
total |
integer | Total number of matching results. |
max_score |
float | Maximum relevance score of results. |
results |
array | List of matching course objects. |
error |
string | Error message (if any). |
Example Request
curl -X POST "https://lms_endpoint/search/course_discovery/" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "search_string=AI" \
-d "page_size=10" \
-d "page_index=1"
Example Response
{
"took": 8,
"total": 6,
"max_score": 1,
"results": [
{
"_index": "course_info",
"_type": "_doc",
"_id": "course-v1:HealthOnCloud+Test101+2025_T1",
"_ignored": [
"content.overview.keyword"
],
"data": {
"id": "course-v1:HealthOnCloud+Test101+2025_T1",
"course": "course-v1:HealthOnCloud+Test101+2025_T1",
"content": {
"display_name": "Health on Cloud Test",
"overview": " About This Course Include your long course description here... ",
"number": "Test101",
"short_description": "It is a testing course "
},
"image_url": "/static/studio/images/pencils.jpg",
"start": "2030-01-01T00:00:00+00:00",
"number": "Test101",
"org": "HealthOnCloud",
"modes": ["honor"],
"language": "ar",
"invitation_only": true,
"catalog_visibility": "both"
},
"score": 1
}
]
}
Field Differences Between Endpoints
List Endpoint vs Single Course Endpoint
| List Endpoint Field | Single Course Endpoint Field | Notes |
|---|---|---|
display_image |
course_image_url |
Different field names for the same data |
organisation (object) |
organisation (string) |
List endpoint may return organization object, detail endpoint returns name string |
| N/A | organisation_id |
Only available in detail endpoint |
| N/A | start_display |
Only available in detail endpoint |
| N/A | course_structure |
Only available in detail endpoint |
| N/A | reviews |
Only available in detail endpoint (list endpoint only has avg_rating) |
Notes
- The
fieldsparameter on the list endpoint significantly affects response size. Uselightmode for list views andfullmode when detailed information is needed. - Organization filtering uses the Organization model as the source of truth - organization names are resolved to their short names internally.
- Tag filtering supports comma-separated values and matches any of the provided tags.
- The
order_byparameter format is{field}.{direction}where direction can beascordesc. - Partial errors may be included in list responses when some courses fail to serialize, allowing the response to succeed even if individual courses have issues.