[CodeTrain](https://codetrain.ai/) / Developers

# CodeTrain developer API

A public, read-only HTTP API over the CodeTrain course catalog, changelog and roadmap. No account, no key, no signup. Base URL `https://api.codetrain.ai`.

## Quickstart

```
$ curl -s https://api.codetrain.ai/v1/catalog
```

That is the whole setup. Every endpoint below is a `GET`, returns JSON, and needs no credentials. If you would rather read prose than JSON, every page on this site also serves markdown: ask for it with `Accept: text/markdown`.

```
$ curl -s -H "Accept: text/markdown" https://codetrain.ai/learn/
```

## Endpoints

| Method | Path | Returns |
| --- | --- | --- |
| `GET` | `/v1/health` | Liveness and the current API version. |
| `GET` | `/v1/catalog` | Every published course, its classes and their lessons. |
| `GET` | `/v1/courses/{course_id}` | One course with its live classes. |
| `GET` | `/v1/lessons/{lesson_id}` | Metadata for one curated lesson: title, blurb, language and step count. Never the step content, because writing the steps is what the learner is here to do. |
| `GET` | `/v1/changelog` | What shipped, newest first. The same entries as /changelog/. |
| `GET` | `/v1/roadmap` | Roadmap items grouped by stage. The same data as /roadmap/. |
| `GET` | `/v1/referrals/{code}` | Whether a Conductor Network referral code belongs to somebody. A bare boolean and nothing else: no name, no id. |

## Each endpoint in full

### `GET /v1/health`

Liveness and the current API version.

```
$ curl -s https://api.codetrain.ai/v1/health
{"status": "ok", "version": "v1"}
```

### `GET /v1/catalog`

Every published course, its classes and their lessons.

```
$ curl -s https://api.codetrain.ai/v1/catalog
{"courses": [{"id": "python-intro", "title": "...", "classes": [...]}]}
```

### `GET /v1/courses/{course_id}`

One course with its live classes.

```
$ curl -s https://api.codetrain.ai/v1/courses/python-intro
{"id": "python-intro", "title": "...", "classes": [...]}
```

### `GET /v1/lessons/{lesson_id}`

Metadata for one curated lesson: title, blurb, language and step count. Never the step content, because writing the steps is what the learner is here to do.

```
$ curl -s https://api.codetrain.ai/v1/lessons/python-basics
{"id": "python-basics", "title": "...", "lang": "python", "steps": 4}
```

### `GET /v1/changelog`

What shipped, newest first. The same entries as /changelog/.

```
$ curl -s https://api.codetrain.ai/v1/changelog
{"entries": [{"id": "tutor-examples-2026-08-28", "date": "2026-08-28", "kind": "feature"}]}
```

### `GET /v1/roadmap`

Roadmap items grouped by stage. The same data as /roadmap/.

```
$ curl -s https://api.codetrain.ai/v1/roadmap
{"stages": [{"key": "shipped", "label": "Shipped", "items": [...]}]}
```

### `GET /v1/referrals/{code}`

Whether a Conductor Network referral code belongs to somebody. A bare boolean and nothing else: no name, no id.

```
$ curl -s https://api.codetrain.ai/v1/referrals/ada
{"valid": true}
```

## Authentication

The `/v1` endpoints listed above need none. Everything they return is already published as a web page on this domain, so putting a key in front of it would protect nothing and stop an agent reading it.

CodeTrain does have an authenticated API behind the dashboard and the CLI, and it is **not part of this public contract**. It is versioned separately, changes without notice, and is not documented here on purpose: it is an implementation detail of our own clients rather than an integration surface. If you need something from it, write to [support@codetrain.ai](mailto:support@codetrain.ai) and tell us the job you are trying to do, and we will either add it to `/v1` or explain why not.

## Rate limits

Read endpoints allow **120 requests per minute per IP address**. The referral lookup allows **60 per hour per IP address**, because it answers a question about real people to a stranger.

Every response carries the current state of your budget, so a client can slow down before it is refused rather than after:

| Header | Meaning |
| --- | --- |
| `RateLimit-Limit` | Requests allowed in the current window. |
| `RateLimit-Remaining` | Requests left in the current window. |
| `RateLimit-Reset` | Seconds until the window resets. |
| `RateLimit-Policy` | The window itself, for example `120;w=60`. |
| `Retry-After` | Sent only with a `429`. Seconds to wait. Honour this one and you will not see another 429. |

## Versioning and deprecation

- The major version is in the path. `/v1` is the only version today.
- **Additive changes ship without a version bump.** New endpoints and new fields on an existing response can appear at any time, so parse defensively and ignore what you do not recognise.
- Nothing is removed or renamed inside a version. A breaking change means `/v2`, and `/v1` keeps working.
- When an endpoint is on its way out it answers with a `Deprecation` header and a `Sunset` header giving the date it stops. The gap is **at least 90 days**, and the same notice goes in the [changelog](https://codetrain.ai/changelog/).
- Errors are JSON with a `detail` string and a real HTTP status. A missing course or lesson is a `404`, never a `200` with an empty body.

## Command line

The CodeTrain CLI runs the tutor locally and serves its own interface on `127.0.0.1`. Install it either way round:

```
$ pip install codetrain-cli
$ curl -fsSL https://codetrain.ai/install.sh | sh
```

Both put the agent in the same place and install the same launcher, so it does not matter which you pick, and using both does no harm. It keeps itself current: once a day it checks whether the published bundle changed and replaces its own copy if it did. There is nothing to reinstall to get a newer agent.

Four commands need no account at all, which makes them safe for a script to call before anything is set up:

```
$ codetrain doctor      # is the service up, is this install healthy. --json, exit 0 or 1
$ codetrain version     # installed agent bundle against the published one
$ codetrain catalog     # the curated courses
$ codetrain update      # fetch the newest bundle now
```

The installer checks the bundle against a published SHA-256 before it unpacks anything. The bundle and its checksum are at [/dist/codetrain-agent.tar.gz](https://codetrain.ai/dist/codetrain-agent.tar.gz). The CLI needs Python and nothing else, and it talks to `https://api.codetrain.ai` by default.

It keeps itself current. Once a day it checks whether the published bundle has changed, and replaces its own copy if it has, verifying the checksum the same way the installer does. To force it, run `codetrain update`. To switch it off, set `CODETRAIN_NO_UPDATE=1` and update by hand.

## Machine-readable

- [OpenAPI 3.1 document](https://api.codetrain.ai/openapi.json) for the public API.
- [Interactive reference](https://api.codetrain.ai/docs), generated from the same document.
- [/llms.txt](https://codetrain.ai/llms.txt), which says when to reach for CodeTrain and links every page in markdown.
- [/llms-full.txt](https://codetrain.ai/llms-full.txt), the whole public site as one markdown file.
- [/sitemap.xml](https://codetrain.ai/sitemap.xml) for the canonical URL list.

[Open the API reference](https://api.codetrain.ai/docs) [All documentation](https://codetrain.ai/docs/)

---

Source: https://codetrain.ai/developers/

This is the markdown twin of the page above. Every public CodeTrain page serves one on `Accept: text/markdown`. Start at https://codetrain.ai/llms.txt for the full map, or https://codetrain.ai/developers/ for the API.
