Skip to main content
Skip to content
Browse the docs

Developer Guide

API reference

The public site API exposes one institution and its publicly listed programmes. It is anonymous and read-only, and has two endpoints.

Base URL

Text
https://api.lernmark.app

Every path below is relative to this origin and starts with /api/v1. In the paths, {school} is your school slug and {institution} is your institution ID. See Before you start.

Authentication

None. Do not send API keys, tokens, passwords, or cookies. Send Accept: application/json with every request.

Get the institution

Confirms that your school slug and school ID point to an institution that is listed publicly. Use it as a health check when you set up or change your configuration.

GET/api/v1/public/site/{school}/institutions/{institution}

Response (200 OK):

JSON
{
  "data": {
    "institution": {
      "id": "3f2b6c1e-8a4d-4f7b-9c2e-5d1a0b7e4c93",
      "name": "Institut Siantou Supérieur",
      "code": "ISS"
    }
  },
  "meta": { "message": "OK" },
  "errors": {}
}
FieldTypeMeaning
institution.idUUIDStable public school ID. Matches the {institution} you sent.
institution.namestringPublic institution name.
institution.codestringShort institution code.

List programmes

Returns the institution's publicly listed programmes, one page at a time.

GET/api/v1/public/site/{school}/institutions/{institution}/programmes
HTTP
GET /api/v1/public/site/siantou/institutions/3f2b6c1e-8a4d-4f7b-9c2e-5d1a0b7e4c93/programmes?per_page=20&sort=name HTTP/1.1
Host: api.lernmark.app
Accept: application/json

Query parameters

All parameters are optional.

ParameterDefaultRules
page1The page to return.
per_page25Programmes per page, from 1 to 100. Larger values are capped at 100.
searchnoneMatches any part of the programme title or code.
sortnameOne of name, code, or award. Other values fall back to name.
directionascasc or desc.

Response (200 OK):

JSON
{
  "data": {
    "programmes": [
      {
        "id": "8c4e2a17-5b3f-4d9a-a1c6-7e0f2b9d3a54",
        "title": "BTS Accounting and Management",
        "award": "BTS",
        "academic_unit": "School of Management",
        "duration": "2 years full-time",
        "summary": "Practical accounting, tax, and business management for the Cameroonian market.",
        "application_available": true,
        "slug": "bts-accounting-and-management",
        "last_updated": "2026-09-14T08:30:00+00:00"
      }
    ]
  },
  "meta": {
    "message": "OK",
    "pagination": {
      "current_page": 1,
      "from": 1,
      "last_page": 2,
      "per_page": 20,
      "to": 20,
      "total": 27
    }
  },
  "errors": {}
}

Programme fields

FieldTypeMeaning
idUUIDStable public programme ID.
titlestringProgramme title.
awardstring or nullAward or qualification, such as BTS or Licence.
academic_unitstring or nullDepartment or faculty that runs the programme.
durationstring or nullHuman-readable duration.
summarystring or nullShort public description.
application_availablebooleantrue while the programme takes applications. See Apply links.
slugstringURL-friendly name, unique within the institution. Useful for your own programme page URLs.
last_updatedISO 8601 string or nullWhen the programme was last changed.

Render nullable fields defensively: leave out a missing value, and never print the word null.

Pagination

meta.pagination carries current_page, from, last_page, per_page, to, and total. While current_page is less than last_page, request the next page. On an empty result, from and to are null.

Response envelope

Every response, success or error, has the same three keys:

JSON
{
  "data": {},
  "meta": { "message": "OK" },
  "errors": {}
}

meta.pagination appears only on the programme list. On an error, data is null and meta.message names the problem.

Response headers

HeaderMeaning
Cache-Control: no-store, max-age=0Lernmark always returns fresh data. Do your caching on your server.
X-RateLimit-LimitRequests allowed in the current one-minute window.
X-RateLimit-RemainingRequests left in that window.
Retry-AfterOn a 429, seconds to wait before trying again.
X-Request-IdA unique ID for the request. Include it when you contact support.

Rate limits

Limits apply per school slug and per calling IP address, and every request counts, including those that fail:

  • 60 requests per minute
  • 1,000 requests per day

A server-side integration makes every request from your server's IP, so all your visitors share one budget. A 10-minute cache keeps a typical site far below both limits. Avoid passing each visitor's search text straight to the API: every new search term is a cache miss.

Errors

StatusWhenWhat to do
404 Not FoundThe school slug or school ID is wrong, or listing is not turned on for the institution.Recheck both values. Show the unavailable message.
429 Too Many RequestsA rate limit was reached.Stop retrying, wait for Retry-After, and fix your caching. Show the unavailable message.
5xx or timeoutA temporary problem.Show the unavailable message and try again on a later request.

All 404 cases return the same response on purpose, so the API never reveals whether a school or institution exists:

JSON
{
  "data": null,
  "meta": { "message": "Not Found" },
  "errors": {}
}

Treat anything except 200 as unavailable

Set a 5-second timeout. On any non-200 response or timeout, show “Programme information is temporarily unavailable.” and do not fall back to expired cached data.

A listed institution with no listed programmes returns 200 OK with an empty programmes array, not a 404.