Course catalogue API

This API is for AI agents helping a person choose an online CPR or first aid course from Mandatory Training. It answers which courses we offer in a country, what they cost and cover, and what we say about whether an employer will accept the certificate. It is read-only, needs no key, and answers in JSON.

Give people the wording as it is

Every answer carries employer_acceptance: our wording on whether an employer will accept the certificate. Give people the employer_acceptance wording as it is. Don't paraphrase it, shorten it or turn it into a yes: whether a certificate is enough is up to their employer or licensing body.

Authentication

Reading the catalogue needs no key, token or registration: the /agent/ endpoints and the MCP server at https://getmandatorytraining.com/mcp answer anyone.

An assistant can also connect for one learner, with their consent, to read that learner's own account (their details, courses, progress and certificates) through the account MCP server. That uses OAuth, in five steps:

  1. Register as a public client (dynamic client registration). You get a client_id and no secret.
    curl -X POST https://getmandatorytraining.com/oauth/register -H 'Content-Type: application/json' \
      -d '{"client_name":"<your app>","redirect_uris":["https://<your app>/callback"]}'
  2. Send the learner to the authorization endpoint, with PKCE (S256) and the account server as the resource. They sign in with a code we email them, see what you're asking for, and choose Allow or Deny.
    https://getmandatorytraining.com/oauth/authorize?response_type=code&client_id=<client_id>&redirect_uri=<redirect_uri>&code_challenge=<code_challenge>&code_challenge_method=S256&scope=<scopes>&state=<state>&resource=https://getmandatorytraining.com/mcp/account
  3. Exchange the code for tokens.
    curl -X POST https://getmandatorytraining.com/oauth/token -d grant_type=authorization_code -d code=<code> \
      -d redirect_uri=<redirect_uri> -d client_id=<client_id> -d code_verifier=<code_verifier>
  4. Call the account MCP server with the access token.
    curl -X POST https://getmandatorytraining.com/mcp/account -H 'Authorization: Bearer <access token>' \
      -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' \
      -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
  5. Revoke your tokens when you're done (the learner can also disconnect you from their account page).
    curl -X POST https://getmandatorytraining.com/oauth/revoke -d token=<refresh token> -d client_id=<client_id>

Scopes:

Access tokens last 60 minutes, and refresh tokens rotate on every use. A connection lasts 30 days from the learner's consent. The full description is in auth.md, with the authorization server metadata and the protected resource metadata.

Access and limits

Everything here is free: there's no paid tier, no sign-up and no API key. Reads change nothing, so there's no separate sandbox; call the live API. Enrolling and allowing account access are always done by the person themselves, and connecting for a learner is self-serve, with no approval from us. Client registration and token requests are throttled per address.

Endpoints

GET /agent/courses

The courses for a country, with prices in that country's currency. country is a two-letter code (US, CA, GB, NZ and others); without it, the answer is for the requester's own country as we estimate it.

curl 'https://getmandatorytraining.com/agent/courses?country=NZ'

GET /agent/courses/{slug}

One course: its description, lesson titles, the size and pass mark of its test, and its versions for other countries. An unknown slug answers 404 with a not_found problem (see Errors).

curl 'https://getmandatorytraining.com/agent/courses/first-aid-nz'

GET /agent/acceptance

Our employer-acceptance wording for a country on its own, with the same country parameter.

curl 'https://getmandatorytraining.com/agent/acceptance?country=GB'

Enrolling

Enrolment happens on the site, not through this API. Send the person to the course's url: they enter and confirm their own details there, and we email them a sign-in link that starts the course.

MCP

The same three reads are an MCP server, for assistants that connect to one (as a custom connector, for example). It needs no sign-in and changes nothing: list_courses, get_course and employer_acceptance, each with an optional country.

https://getmandatorytraining.com/mcp

Enrolment stays on the site: send the person to the course's url.

The account MCP server

A second MCP server, https://getmandatorytraining.com/mcp/account, reads one learner's own account, read-only, with a token the learner granted (see Authentication). It can never take lessons or tests, get or pay for certificates, or change anything.

Agents in the browser

On our pages, an agent in the person's browser can use our WebMCP tools instead: list_courses, get_course, employer_acceptance, set_country and start_enrolment, which asks the person to confirm before it sends anything.

Errors

Every error from /agent/, and a missing page asked for as JSON, is an RFC 9457 problem served as application/problem+json: type (a link here), title, status, code, detail and hint, which says what to do next. Errors from the read API also keep result, the same code, for clients written before problem details.

{"type":"https://getmandatorytraining.com/agent/docs#errors","title":"Not found","status":404,"code":"not_found","detail":"No course with that slug is offered.","hint":"List the courses offered with GET https://getmandatorytraining.com/agent/courses, and use a slug from that list.","result":"not_found"}

API conventions

Conventions: this is version 1.0; a breaking change comes with a new version, and additive changes don't. Reads aren't rate-limited, so no rate-limit headers are sent. Pagination, batch requests, async jobs and idempotency keys don't apply: every documented operation is a read-only GET returning a complete, short list or one item.

Machine-readable

The OpenAPI description (version 1.0, also at /openapi.json, /swagger.json, /api/openapi.json and /.well-known/openapi.json) and the API catalog. Every public page links to both in its Link header.