GET /courses/{id} returns 404 not_found.
A course and its versions
One course can be sold in several versions: levels or batches (Beginner, 2026 batch) and, on sites with course languages on, language editions (an English and a Hindi eBook). The API returns one entry per course; its versions are in variants:
idis the course id. It stays the same whichever version is shown. Use it in your routes and inGET /courses/{id}.- A language edition may be a separate course on the platform with its own id (here the Hindi eBook is
c150dfcf-…).GET /courses/{id}accepts that id too and shows that edition, but the responseidis still the course id. The hosted page of an edition is in its variant’surl. - The top-level fields (
title,subtitle,image_url,url,level,price,availability) describe the version shown: the first in catalogue order, or the one inlanguagewhen you pass it. levelisnullfor a course without named levels.
Languages
GET /site lists the site’s course languages; the list is empty when the institute has course languages off. Then languages is [] on every course and language parameters are ignored.
With languages on:
GET /courses?language=hikeeps the courses available in Hindi and shows their Hindi version. An unknown code matches nothing.GET /courses/{id}?language=hishows the Hindi version (title, url, price,seo) when there is one, else the default version.- A version’s language comes from its level name (
Hindi,Beginner (English)) or a course tag that is exactly a language name or code. A course whose language cannot be detected haslanguages: [].
Formats
Formats (“E-books”, “Live sessions”) are defined per site.GET /site lists them in display order; each course lists its own in formats. Filter with GET /courses?format=ebook. A site without formats returns [] everywhere.
Tags
tags are the course’s tags as authored, from all its versions. Some carry meaning on the hosted site (format-ebook, stream tags); show the ones that make sense to your visitors. Filter with GET /courses?tag=for-parents (any of several: tag=a,b; case-insensitive, whole tag).
Price and availability
availability says whether the version shown can be bought now:
price:
Hidden prices. An institute can hide prices on its catalogue (
GET /site returns price_visible: false). Paid courses then have price: null and price_visible: false: show “See price” and link to url. Free courses still show price with is_free: true.
The quickstart’s priceLabel implements these rules.
Listing, filtering and sorting
GET /courses combines filters with AND: q, stream, category, format, language, tag, availability.
qis a case-insensitive substring of any version’s title or any tag.- An unknown
streamorcategoryslug returns an empty page, not an error. availabilityfilters on the version shown.sort:newest(default; bycreated_at, the newest version’s creation time),title,price_asc,price_desc(by the lowest price on sale now). Ties keep the catalogue’s order.pagestarts at 1;page_sizeis 1 to 100 (default 24).totalandhas_moretell you whether to show a next page.
Detail fields
GET /courses/{id} adds what a course page needs:
Every
*_html field is sanitised (jsoup relaxed safelist; images only from http(s) URLs) and null when it has no visible content. GET /courses/{id}/outline returns subject, module and chapter titles per version.