# The CoolRoom API

Build your app, widget or script on CoolRoom's data: homework, grades, timetable, lessons, exercises… Always with the student's consent, read only, with limits they choose.

API address: `https://api.coolroom.app/api/open/v1` · https://coolroom.app/en/developers/

## Get started

1. **Make a key**: In the app: Réglages › API et applications › Créer une clé. Tick the data, pick the expiry and the limits. Copy the key: it starts with crk_ and is shown only once.
2. **Call the API**: Send it in the Authorization header of each request. Answers are JSON, dates ISO 8601 (UTC).
3. **For a public app**: Never ask your users for a key: use the “Sign in with CoolRoom” link. The student approves in one tap and your app gets its key.

### Your first request

```sh
curl "https://api.coolroom.app/api/open/v1/homework" \
  -H "Authorization: Bearer crk_…"
```

## Authentication

Every /api/open/v1 route needs a key, in Authorization: Bearer crk_… (or X-API-Key: crk_…). A key reads one account's data, only its scopes, and nothing else of CoolRoom. The API is read only: no route writes, sends or deletes any of the student's data.

```http
Authorization: Bearer crk_Xb7Qm2LpV0x9…
```

- A key is a password: never in a public web page's code, never in a Git repository.
- CoolRoom only keeps the key's fingerprint (SHA-256): if it is lost, the student makes another.
- The student sees every key in Réglages › API et applications and can remove it at any time.
- Your app gets exactly what the student sees in the app: same classes, same rights. Never their passwords or their Pronote logins.

---

# Sign in with CoolRoom

The fastest way for a student: your app opens a link, the student sees your app's name, what it wants to read and for how long, then taps Autoriser. CoolRoom sends them back to your app with a one-time code, which your server (or your app, with PKCE) swaps for the key.

### GET /api/public/connect

**1. The “Sign in with CoolRoom” link** · no key

Open it in the student’s browser. CoolRoom checks the parameters, then shows the consent screen (the student signs in if needed). A broken link answers 400 with the reason.

| Parameters | | |
|---|---|---|
| `app_name` | query, **required** | Your app’s name (2 to 60 characters), shown to the student. |
| `redirect_uri` | query, **required** | Where to send the student back: https://…, http://localhost…, or your app’s scheme (myapp://callback). No #. |
| `scope` | query, **required** | Scopes, comma-separated. |
| `state` | query | Sent back as is: check it on return (200 characters at most). |
| `code_challenge` | query | PKCE: base64url(SHA-256(code_verifier)). Recommended, required for an app without a server. |
| `code_challenge_method` | query | S256 (the only one). |
| `expires_in` | query | Key lifetime in seconds (3,600 to 31,622,400). Without: until the student removes it. |
| `hourly_limit` | query | Requests per hour (1 to 3,600, 600 by default). |
| `total_limit` | query | Requests in all (without: unlimited). |

Request:

```sh
curl "https://api.coolroom.app/api/public/connect?app_name=Agenda%20Plus&redirect_uri=https%3A%2F%2Fagenda-plus.example%2Fcallback&scope=homework%2Ctimetable&state=k8Jd2&code_challenge=ITAt2F6NLydvh8G3CenAG9Ty-j_gUaFU1f886B2WqE0&code_challenge_method=S256&expires_in=2592000"
```

Response: 302 · Redirect to the consent screen.

### GET {redirect_uri}

**2. Back to your app** · no key

Approved: ?code=…&state=…. Refused: ?error=access_denied&state=…. The code works once, for 10 minutes.

Request:

```text
https://agenda-plus.example/callback?code=Qm9uam91ciBkw6l2ZWxvcHBldXI&state=k8Jd2
```

Response: 200 · No content.

### POST /api/public/connect/token

**3. Swap the code for the key** · no key

redirectUri must be exactly the link’s. codeVerifier is required when the link had a code_challenge. Keep apiKey safe: it is never given again.

| Parameters | | |
|---|---|---|
| `code` | body, **required** | The code you got. |
| `redirectUri` | body, **required** | The same as in the link. |
| `codeVerifier` | body | The PKCE secret (43 to 128 characters). |

Request:

```sh
curl -X POST "https://api.coolroom.app/api/public/connect/token" \
  -H "Content-Type: application/json" \
  -d '{"code":"Qm9uam91ciBkw6l2ZWxvcHBldXI","redirectUri":"https://agenda-plus.example/callback","codeVerifier":"dBjftJeZ4CVP-mJ92K9eQ_Ft_3zsHpPhEbbsvh3JJPA"}'
```

Response (200):

```json
{
  "apiKey": "crk_Xb7Qm2LpV0x9…",
  "keyId": "0f3b2a1c-9e8d-4c7b-a6f5-e4d3c2b1a090",
  "scopes": [
    "homework",
    "timetable"
  ],
  "expiresAt": "2026-11-20T08:12:40Z",
  "hourlyLimit": 600,
  "totalLimit": null,
  "user": {
    "id": "7b1e4c2a-5d3f-4e8a-9c61-2f0d8b3a4e15",
    "displayName": "Léa Martin",
    "accountType": "STUDENT"
  }
}
```

### GET /api/public/connect/scopes

**The scope list** · no key

Each scope with its French name and line, as the student sees them.

Request:

```sh
curl "https://api.coolroom.app/api/public/connect/scopes"
```

Response (200):

```json
[
  {
    "key": "homework",
    "label": "Devoirs",
    "description": "Les devoirs de tes classes et ce que tu as fini"
  }
]
```

## PKCE in JavaScript

For a mobile app or a page without a server: make a random secret, keep it, send its fingerprint in the link, then the secret in the swap. Even if someone steals the code, they can't use it.

---

# Limits

Each key has its limits, chosen when it is made (in the app, or by the link's parameters):

- **Per hour**: 1 to 3,600 requests (600 by default). Beyond: 429 with Retry-After.
- **In all**: Optional. Once reached: 429 quota_exceeded, for good.
- **Expiry**: 1 hour to 366 days, or never. After: 401 key_expired.
- **Keys per account**: 20 active keys at most.

Every answer says where you stand: X-RateLimit-Limit, X-RateLimit-Remaining (this hour) and X-Total-Remaining (when the key has a total limit).

Your app can also limit itself: PATCH /key to narrow its scopes, expiry or limits, DELETE /key to give the key back (a “Disconnect” button in your app). Never to get more.

# Errors

An error always has the same shape. Test code, show message (in French).

```json
{
  "status": 403,
  "code": "insufficient_scope",
  "message": "Cette clé n’a pas le scope « grades » (Notes)",
  "path": "/api/open/v1/grades",
  "timestamp": "2026-10-21T17:30:00Z"
}
```

| Status | code | When |
|---|---|---|
| 400 | `invalid_request` | A parameter is missing or wrong (the message says which). |
| 400 | `invalid_scope` | An unknown scope in the connect link. |
| 400 | `invalid_grant` | Connect code unknown, used, expired, or a different redirectUri / codeVerifier. |
| 401 | `missing_key` | No key in the request. |
| 401 | `invalid_key` | Unknown or malformed key (a key starts with crk_). |
| 401 | `key_revoked` | The student (or your app) revoked the key. |
| 401 | `key_expired` | The key is past its expiry date. |
| 403 | `insufficient_scope` | The key lacks this route’s scope. |
| 403 | `cannot_widen` | PATCH /key can only narrow a key. |
| 403 | `forbidden` | The student can’t see this in the app either. |
| 404 | `not_found` | Not found, or not this student’s. |
| 405 | `method_not_allowed` | The API is read only. |
| 409 | `too_many_keys` | The student already has 20 active keys. |
| 429 | `rate_limited` | Hourly limit reached: wait Retry-After seconds. |
| 429 | `quota_exceeded` | The key used all its requests (total limit). |
| 500 | `server_error` | Our side failed. Try again later. |

# Scopes

The data a key can read. In the link, separate them with commas (scope=homework,grades); all asks for every one.

| Scope | Gives access to |
|---|---|
| `profile` | **Profile** · Name, bio, account type, language. |
| `email` | **Email address** · Adds the email address to the profile (with profile). |
| `classes` | **Classes** · Classes, their members and their announcements. |
| `homework` | **Homework** · Each class’s homework, done or not, votes and notes. |
| `grades` | **Grades** · Grades, class averages and goals. |
| `timetable` | **Timetable** · Lessons, rooms, teachers, cancellations and detentions. |
| `school_life` | **School life** · Absences and late arrivals. |
| `mail` | **Mail** · School mail (Pronote, Skolengo), read only. |
| `school_accounts` | **School accounts** · Linked accounts and their sync. Never the logins. |
| `chat` | **Class chat** · Class chat messages. |
| `cours` | **Lessons** · The lesson library, each lesson in Markdown, the curriculum. |
| `exercises` | **Exercises** · Training: results card by card, mistakes, weak points. |
| `flashcards` | **Flash cards** · Card decks and the games played. |
| `progress` | **Level and CC** · Level, XP, CC, streak, season. |
| `notifications` | **Notifications** · The last 100 notifications. |
| `ai` | **AI** · The conversation with CoolRoom’s AI. |
| `family` | **Family** · For a parent account: linked children’s grades, homework and timetable. |

---

# Routes: The key itself

Scope: any key

No scope needed: any valid key can read its limits, narrow them, or revoke itself (a “Disconnect” button in your app).

### GET /api/open/v1/key

**Read the key**

Its scopes, expiry, limits and what is left this hour.

Request:

```sh
curl "https://api.coolroom.app/api/open/v1/key" \
  -H "Authorization: Bearer $COOLROOM_KEY"
```

Response (200):

```json
{
  "id": "0f3b2a1c-9e8d-4c7b-a6f5-e4d3c2b1a090",
  "name": "Agenda Plus",
  "prefix": "crk_Xb7Qm2Lp",
  "scopes": [
    "homework",
    "timetable"
  ],
  "createdAt": "2026-10-21T08:12:40Z",
  "expiresAt": "2026-11-20T08:12:40Z",
  "hourlyLimit": 600,
  "hourlyRemaining": 597,
  "totalLimit": null,
  "usedRequests": 214
}
```

### PATCH /api/open/v1/key

**Narrow the key**

Your app limits itself: fewer scopes, an earlier expiry, lower limits. Never the reverse (403 cannot_widen). What you leave out stays.

| Parameters | | |
|---|---|---|
| `scopes` | body | A subset of the current scopes. |
| `expiresAt` | body | ISO 8601 date, in the future and before the current expiry. |
| `hourlyLimit` | body | From 1 to the current limit. |
| `totalLimit` | body | Requests in all, at most the current limit. |

Request:

```sh
curl -X PATCH "https://api.coolroom.app/api/open/v1/key" \
  -H "Authorization: Bearer $COOLROOM_KEY" \
  -H "Content-Type: application/json" \
  -d '{"scopes":["homework"],"hourlyLimit":100,"totalLimit":5000}'
```

Response (200):

```json
{
  "id": "0f3b2a1c-9e8d-4c7b-a6f5-e4d3c2b1a090",
  "name": "Agenda Plus",
  "prefix": "crk_Xb7Qm2Lp",
  "scopes": [
    "homework"
  ],
  "createdAt": "2026-10-21T08:12:40Z",
  "expiresAt": "2026-11-20T08:12:40Z",
  "hourlyLimit": 100,
  "hourlyRemaining": 97,
  "totalLimit": 5000,
  "usedRequests": 214
}
```

### DELETE /api/open/v1/key

**Revoke the key**

The key stops at once, for good.

Request:

```sh
curl -X DELETE "https://api.coolroom.app/api/open/v1/key" \
  -H "Authorization: Bearer $COOLROOM_KEY"
```

Response: 204 · No content.

---

# Routes: Profile

Scope: `profile`

The account behind the key.

### GET /api/open/v1/me

**The account**

accountType is STUDENT or PARENT. email and emailVerified are only filled with the email scope (null otherwise).

Request:

```sh
curl "https://api.coolroom.app/api/open/v1/me" \
  -H "Authorization: Bearer $COOLROOM_KEY"
```

Response (200):

```json
{
  "id": "7b1e4c2a-5d3f-4e8a-9c61-2f0d8b3a4e15",
  "displayName": "Léa Martin",
  "bio": "Seconde 4, team SVT",
  "accountType": "STUDENT",
  "locale": "fr",
  "avatarIconId": "fox",
  "memberSince": "2026-09-02T17:21:05Z",
  "email": "lea.martin@example.fr",
  "emailVerified": true
}
```

---

# Routes: Classes

Scope: `classes`

The student’s classes. The invite code is never given.

### GET /api/open/v1/classes

**My classes**

myRole: MEMBER, CO_ADMIN or CLASS_MASTER. status: APPROVED, LOCKED, ARCHIVED…

Request:

```sh
curl "https://api.coolroom.app/api/open/v1/classes" \
  -H "Authorization: Bearer $COOLROOM_KEY"
```

Response (200):

```json
[
  {
    "id": "c1a55e00-2b7d-4f1e-8a3c-6d9e0f1a2b3c",
    "name": "2nde 4",
    "description": "La meilleure classe du lycée",
    "etablissementId": "e7ab1100-4c3d-4e2f-9a8b-7c6d5e4f3a2b",
    "etablissementName": "Lycée Jean Zay",
    "classMasterName": "Tom Durand",
    "status": "APPROVED",
    "memberCount": 28,
    "myRole": "MEMBER",
    "subjectColors": {
      "Mathématiques": "#3B82F6",
      "SVT": "#22C55E"
    },
    "languages": {
      "LV2": [
        "ESPAGNOL LV2",
        "ALLEMAND LV2"
      ]
    }
  }
]
```

### GET /api/open/v1/classes/{classId}

**One class**

Same shape as one item of /classes.

| Parameters | | |
|---|---|---|
| `classId` | path, **required** | One of the student’s classes. |

Request:

```sh
curl "https://api.coolroom.app/api/open/v1/classes/c1a55e00-2b7d-4f1e-8a3c-6d9e0f1a2b3c" \
  -H "Authorization: Bearer $COOLROOM_KEY"
```

Response (200):

```json
{
  "id": "c1a55e00-2b7d-4f1e-8a3c-6d9e0f1a2b3c",
  "name": "2nde 4",
  "memberCount": 28,
  "myRole": "MEMBER",
  "…": "…"
}
```

### GET /api/open/v1/classes/{classId}/members

**Members**

status: ONLINE, FOCUS, IN_LESSON, AWAY or OFFLINE. lastSeenAt is rounded to 5 minutes, null after a week.

Request:

```sh
curl "https://api.coolroom.app/api/open/v1/classes/c1a55e00-2b7d-4f1e-8a3c-6d9e0f1a2b3c/members" \
  -H "Authorization: Bearer $COOLROOM_KEY"
```

Response (200):

```json
[
  {
    "userId": "a2b3c4d5-e6f7-4a8b-9c0d-1e2f3a4b5c6d",
    "displayName": "Tom Durand",
    "avatarIconId": "owl",
    "avatarPhotoVersion": null,
    "bio": "Délégué",
    "role": "CLASS_MASTER",
    "online": true,
    "muted": false,
    "inFocus": false,
    "status": "ONLINE",
    "lastSeenAt": "2026-10-21T15:40:00Z",
    "frame": null
  }
]
```

### GET /api/open/v1/classes/{classId}/announcements

**Announcements**

The class’s announcements, newest first.

Request:

```sh
curl "https://api.coolroom.app/api/open/v1/classes/c1a55e00-2b7d-4f1e-8a3c-6d9e0f1a2b3c/announcements" \
  -H "Authorization: Bearer $COOLROOM_KEY"
```

Response (200):

```json
[
  {
    "id": "b1c2d3e4-f5a6-4b7c-8d9e-0f1a2b3c4d5e",
    "title": "Sortie au musée jeudi",
    "body": "Rendez-vous 8 h devant le lycée, prévoyez un pique-nique.",
    "authorName": "Tom Durand",
    "authorRole": "CLASS_MASTER",
    "createdAt": "2026-10-20T18:05:00Z",
    "seen": true,
    "canDelete": false
  }
]
```

---

# Routes: Class chat

Scope: `chat`

Messages, oldest to newest, by pages.

### GET /api/open/v1/classes/{classId}/chat

**Messages**

type: TEXT, LESSON, FLASHCARDS, GIVEAWAY, MEDIA, STICKER, ASSISTANT… Photos and videos are not served by the API (media only gives their details).

| Parameters | | |
|---|---|---|
| `before` | query | ISO date: messages before it (previous page). |
| `limit` | query | 1 to 100. |

Request:

```sh
curl "https://api.coolroom.app/api/open/v1/classes/c1a55e00-2b7d-4f1e-8a3c-6d9e0f1a2b3c/chat?limit=50" \
  -H "Authorization: Bearer $COOLROOM_KEY"
```

Response (200):

```json
{
  "pinned": null,
  "messages": [
    {
      "id": "d4e5f6a7-b8c9-4d0e-8f1a-2b3c4d5e6f7a",
      "type": "TEXT",
      "author": {
        "id": "a2b3c4d5-e6f7-4a8b-9c0d-1e2f3a4b5c6d",
        "displayName": "Tom Durand",
        "avatarIconId": "owl",
        "avatarPhotoVersion": null,
        "frame": null
      },
      "body": "Quelqu’un a compris l’exo 14 ?",
      "createdAt": "2026-10-21T16:02:33Z",
      "quote": null,
      "reactions": [
        {
          "emoji": "👀",
          "count": 3,
          "names": [
            "Léa",
            "Inès",
            "Hugo"
          ],
          "reactedByMe": true
        }
      ],
      "mentionedRaw": null,
      "pinned": false,
      "mine": false,
      "deck": null,
      "giveaway": null,
      "lesson": null,
      "sources": null,
      "media": null,
      "sticker": null
    }
  ],
  "typing": []
}
```

---

# Routes: Homework

Scope: `homework`

source: OFFICIAL (Pronote, school portal) or MANUAL (added by a student). status: OFFICIEL, CONFIRME or A_VERIFIER. done and snoozed belong to the student.

### GET /api/open/v1/homework

**Homework, by class**

Every class, or one with ?classId=.

| Parameters | | |
|---|---|---|
| `classId` | query | One class only. |

Request:

```sh
curl "https://api.coolroom.app/api/open/v1/homework" \
  -H "Authorization: Bearer $COOLROOM_KEY"
```

Response (200):

```json
{
  "classes": [
    {
      "classId": "c1a55e00-2b7d-4f1e-8a3c-6d9e0f1a2b3c",
      "className": "2nde 4",
      "homework": [
        {
          "id": "9d2f7a10-3b4c-4d5e-8f6a-7b8c9d0e1f2a",
          "subject": "Mathématiques",
          "title": "Exercices 12 à 15 p. 84",
          "description": "Faire les exercices sur les fonctions affines.",
          "dueAt": "2026-10-23T06:00:00Z",
          "source": "OFFICIAL",
          "status": "OFFICIEL",
          "isExam": false,
          "done": false,
          "completedAt": null,
          "snoozed": false,
          "submitterId": null,
          "submitterName": null,
          "confirmations": 0,
          "disagreements": 0,
          "myVote": null,
          "latestNote": "Le 15 b) est corrigé en classe",
          "latestNoteAuthor": "Tom",
          "photoVersion": null
        }
      ]
    }
  ]
}
```

### GET /api/open/v1/homework/{homeworkId}

**One homework**

The homework and all its notes.

Request:

```sh
curl "https://api.coolroom.app/api/open/v1/homework/9d2f7a10-3b4c-4d5e-8f6a-7b8c9d0e1f2a" \
  -H "Authorization: Bearer $COOLROOM_KEY"
```

Response (200):

```json
{
  "homework": {
    "id": "9d2f7a10-3b4c-4d5e-8f6a-7b8c9d0e1f2a",
    "subject": "Mathématiques",
    "title": "Exercices 12 à 15 p. 84",
    "description": "Faire les exercices sur les fonctions affines.",
    "dueAt": "2026-10-23T06:00:00Z",
    "source": "OFFICIAL",
    "status": "OFFICIEL",
    "isExam": false,
    "done": false,
    "completedAt": null,
    "snoozed": false,
    "submitterId": null,
    "submitterName": null,
    "confirmations": 0,
    "disagreements": 0,
    "myVote": null,
    "latestNote": "Le 15 b) est corrigé en classe",
    "latestNoteAuthor": "Tom",
    "photoVersion": null
  },
  "notes": [
    {
      "id": "e5f6a7b8-c9d0-4e1f-8a2b-3c4d5e6f7a8b",
      "authorId": "a2b3c4d5-e6f7-4a8b-9c0d-1e2f3a4b5c6d",
      "authorName": "Tom",
      "authorAvatarIconId": "owl",
      "authorPhotoVersion": null,
      "body": "Le 15 b) est corrigé en classe",
      "createdAt": "2026-10-21T12:30:00Z",
      "mine": false,
      "canDelete": false
    }
  ],
  "canEdit": false,
  "canVote": false,
  "confirmationThreshold": 3
}
```

---

# Routes: Grades

Scope: `grades`

The student’s grades, newest first. Numbers are decimals.

### GET /api/open/v1/grades

**Grades**

revealed: already opened in the app. The value is always given.

Request:

```sh
curl "https://api.coolroom.app/api/open/v1/grades" \
  -H "Authorization: Bearer $COOLROOM_KEY"
```

Response (200):

```json
[
  {
    "id": "3a4b5c6d-7e8f-4a1b-9c2d-3e4f5a6b7c8d",
    "subject": "Physique-Chimie",
    "title": "Contrôle : les ondes",
    "value": 15.5,
    "outOf": 20,
    "classAverage": 12.25,
    "classMin": 6,
    "classMax": 18.5,
    "coefficient": 2,
    "period": "Trimestre 1",
    "date": "2026-10-17",
    "revealed": true,
    "masked": false
  }
]
```

### GET /api/open/v1/grades/goals

**Goals**

Empty subject = the overall average.

Request:

```sh
curl "https://api.coolroom.app/api/open/v1/grades/goals" \
  -H "Authorization: Bearer $COOLROOM_KEY"
```

Response (200):

```json
[
  {
    "subject": "",
    "target": 14
  },
  {
    "subject": "Mathématiques",
    "target": 15
  }
]
```

---

# Routes: Timetable

Scope: `timetable`

Times are UTC (Z). detention: a detention.

### GET /api/open/v1/timetable

**Lessons between two dates**

From from to to included, 62 days at most (Paris time).

| Parameters | | |
|---|---|---|
| `from` | query, **required** | YYYY-MM-DD. |
| `to` | query, **required** | YYYY-MM-DD. |

Request:

```sh
curl "https://api.coolroom.app/api/open/v1/timetable?from=2026-10-19&to=2026-10-25" \
  -H "Authorization: Bearer $COOLROOM_KEY"
```

Response (200):

```json
[
  {
    "id": "6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e",
    "subject": "Histoire-Géographie",
    "teacher": "M. Laurent",
    "room": "B204",
    "startAt": "2026-10-22T07:00:00Z",
    "endAt": "2026-10-22T08:00:00Z",
    "canceled": false,
    "note": null,
    "detention": false
  },
  {
    "id": "7c8d9e0f-1a2b-4c3d-9e4f-5a6b7c8d9e0f",
    "subject": "Anglais",
    "teacher": "Mme Smith",
    "room": "A12",
    "startAt": "2026-10-22T08:00:00Z",
    "endAt": "2026-10-22T09:00:00Z",
    "canceled": true,
    "note": "Prof absente",
    "detention": false
  }
]
```

---

# Routes: School life

Scope: `school_life`

kind: ABSENCE or DELAY. Detentions are in the timetable.

### GET /api/open/v1/school-life

**Absences and late arrivals**

Newest first.

Request:

```sh
curl "https://api.coolroom.app/api/open/v1/school-life" \
  -H "Authorization: Bearer $COOLROOM_KEY"
```

Response (200):

```json
[
  {
    "id": "f6a7b8c9-d0e1-4f2a-9b3c-4d5e6f7a8b9c",
    "kind": "DELAY",
    "title": "Retard",
    "reason": "Transport",
    "detail": null,
    "giver": null,
    "startAt": "2026-10-20T07:05:00Z",
    "endAt": null,
    "scheduledAt": null,
    "durationMinutes": 10,
    "justified": true
  }
]
```

---

# Routes: Mail

Scope: `mail`

School mail, read only. Reading here doesn’t mark them read.

### GET /api/open/v1/mail

**Inbox**

type: TEACHER, ADMIN, SYSTEM or OTHER. q searches the subject, sender and text.

| Parameters | | |
|---|---|---|
| `q` | query | Search. |
| `type` | query | Filter by sender. |

Request:

```sh
curl "https://api.coolroom.app/api/open/v1/mail?type=TEACHER" \
  -H "Authorization: Bearer $COOLROOM_KEY"
```

Response (200):

```json
{
  "messages": [
    {
      "id": "a7b8c9d0-e1f2-4a3b-8c4d-5e6f7a8b9c0d",
      "provider": "PRONOTE",
      "providers": [
        "PRONOTE"
      ],
      "subject": "Conseil de classe",
      "snippet": "Bonjour, le conseil de classe aura lieu le…",
      "senderName": "Mme Bernard",
      "senderType": "TEACHER",
      "receivedAt": "2026-10-21T10:15:00Z",
      "read": false,
      "messageCount": 1,
      "sharedAt": null
    }
  ],
  "unreadCount": 1,
  "countsByType": {
    "TEACHER": 4,
    "ADMIN": 2,
    "SYSTEM": 0,
    "OTHER": 1
  }
}
```

### GET /api/open/v1/mail/{mailId}

**One mail and its thread**

Can take a few seconds the first time (CoolRoom fetches the text from Pronote or Skolengo).

Request:

```sh
curl "https://api.coolroom.app/api/open/v1/mail/a7b8c9d0-e1f2-4a3b-8c4d-5e6f7a8b9c0d" \
  -H "Authorization: Bearer $COOLROOM_KEY"
```

Response (200):

```json
{
  "mail": {
    "id": "a7b8c9d0-e1f2-4a3b-8c4d-5e6f7a8b9c0d",
    "subject": "Conseil de classe",
    "senderName": "Mme Bernard",
    "…": "…"
  },
  "thread": [
    {
      "author": "Mme Bernard",
      "sentAt": "2026-10-21T10:15:00Z",
      "content": "Bonjour, le conseil de classe aura lieu le 4 décembre.",
      "fromMe": false
    }
  ]
}
```

---

# Routes: School accounts

Scope: `school_accounts`

Linked accounts and their sync. Logins never leave the server.

### GET /api/open/v1/school-accounts

**Linked accounts**

provider: PRONOTE, SKOLENGO or PRONOTE_ENT_AURA. status: PENDING, CONNECTED, ERROR or DISCONNECTED.

Request:

```sh
curl "https://api.coolroom.app/api/open/v1/school-accounts" \
  -H "Authorization: Bearer $COOLROOM_KEY"
```

Response (200):

```json
[
  {
    "id": "b8c9d0e1-f2a3-4b4c-9d5e-6f7a8b9c0d1e",
    "provider": "PRONOTE",
    "status": "CONNECTED",
    "schoolLabel": "Lycée Jean Zay",
    "lastSyncAt": "2026-10-21T16:00:00Z",
    "lastLogonRefreshAt": "2026-10-21T16:04:00Z",
    "lastError": null,
    "syncMail": true,
    "syncHomework": true,
    "syncGrades": true,
    "syncTimetable": true,
    "available": [
      "GRADES",
      "HOMEWORK",
      "MAIL",
      "SCHOOL_LIFE",
      "TIMETABLE"
    ],
    "unavailable": []
  }
]
```

---

# Routes: Lessons

Scope: `cours`

Each class’s lesson library. Each lesson is Markdown.

### GET /api/open/v1/cours/classes/{classId}

**The library**

Subjects, folders, lessons (without their text), links and tags.

Request:

```sh
curl "https://api.coolroom.app/api/open/v1/cours/classes/c1a55e00-2b7d-4f1e-8a3c-6d9e0f1a2b3c" \
  -H "Authorization: Bearer $COOLROOM_KEY"
```

Response (200):

```json
{
  "classId": "c1a55e00-2b7d-4f1e-8a3c-6d9e0f1a2b3c",
  "className": "2nde 4",
  "subjects": [
    {
      "key": "svt",
      "name": "SVT",
      "icon": "microscope",
      "lessonCount": 7,
      "folderCount": 2,
      "fromTimetable": true,
      "lastUpdated": "2026-10-15T09:40:00Z"
    }
  ],
  "folders": [
    {
      "id": "1d2e3f4a-5b6c-4d7e-8f9a-0b1c2d3e4f5a",
      "subjectKey": "svt",
      "parentId": null,
      "title": "Chapitre 2",
      "icon": null,
      "aiMade": false,
      "position": 0
    }
  ],
  "lessons": [
    {
      "id": "5e550a11-8c2d-4b7a-9f3e-1d2c3b4a5f60",
      "subjectKey": "svt",
      "subjectName": "SVT",
      "folderId": null,
      "title": "La cellule, unité du vivant",
      "tags": [
        "chapitre-2",
        "cellule"
      ],
      "visibility": "CLASS",
      "status": "COMPLETE",
      "givenOn": "2026-10-14",
      "createdAt": "2026-10-14T16:02:11Z",
      "updatedAt": "2026-10-15T09:40:00Z",
      "revision": 3,
      "readingMinutes": 6,
      "author": {
        "id": "7b1e4c2a-5d3f-4e8a-9c61-2f0d8b3a4e15",
        "displayName": "Léa Martin",
        "avatarIconId": "fox",
        "avatarPhotoVersion": null
      },
      "badges": [
        "NEW"
      ]
    }
  ],
  "links": [],
  "tags": [
    {
      "path": "cellule",
      "count": 3
    }
  ],
  "canManage": false
}
```

### GET /api/open/v1/cours/classes/{classId}/search

**Search lessons**

Lessons that mention q, with an excerpt.

| Parameters | | |
|---|---|---|
| `q` | query, **required** | Search words. |
| `subject` | query | One subject (subjectKey). |

Request:

```sh
curl "https://api.coolroom.app/api/open/v1/cours/classes/c1a55e00-2b7d-4f1e-8a3c-6d9e0f1a2b3c/search?q=mitochondrie" \
  -H "Authorization: Bearer $COOLROOM_KEY"
```

Response (200):

```json
[
  {
    "lesson": {
      "id": "5e550a11-8c2d-4b7a-9f3e-1d2c3b4a5f60",
      "subjectKey": "svt",
      "subjectName": "SVT",
      "folderId": null,
      "title": "La cellule, unité du vivant",
      "tags": [
        "chapitre-2",
        "cellule"
      ],
      "visibility": "CLASS",
      "status": "COMPLETE",
      "givenOn": "2026-10-14",
      "createdAt": "2026-10-14T16:02:11Z",
      "updatedAt": "2026-10-15T09:40:00Z",
      "revision": 3,
      "readingMinutes": 6,
      "author": {
        "id": "7b1e4c2a-5d3f-4e8a-9c61-2f0d8b3a4e15",
        "displayName": "Léa Martin",
        "avatarIconId": "fox",
        "avatarPhotoVersion": null
      },
      "badges": [
        "NEW"
      ]
    },
    "excerpt": "…la **mitochondrie** produit l’énergie de la cellule…",
    "anchor": "les-organites",
    "score": 12
  }
]
```

### GET /api/open/v1/cours/classes/{classId}/programme

**The curriculum**

Each chapter of the official curriculum: COMPLETE, PARTIAL or MISSING given the class’s lessons.

Request:

```sh
curl "https://api.coolroom.app/api/open/v1/cours/classes/c1a55e00-2b7d-4f1e-8a3c-6d9e0f1a2b3c/programme" \
  -H "Authorization: Bearer $COOLROOM_KEY"
```

Response (200):

```json
{
  "classId": "c1a55e00-2b7d-4f1e-8a3c-6d9e0f1a2b3c",
  "level": "SECONDE",
  "levelGuessed": false,
  "canManage": false,
  "levels": [
    "SIXIEME",
    "CINQUIEME",
    "QUATRIEME",
    "TROISIEME",
    "SECONDE",
    "PREMIERE",
    "TERMINALE"
  ],
  "subjects": [
    {
      "subjectKey": "svt",
      "subjectName": "SVT",
      "programmeKey": "SVT",
      "total": 8,
      "complete": 2,
      "partial": 1,
      "chapters": [
        {
          "id": "2e3f4a5b-6c7d-4e8f-9a0b-1c2d3e4f5a6b",
          "title": "La cellule",
          "state": "COMPLETE",
          "lessons": [
            {
              "id": "5e550a11-8c2d-4b7a-9f3e-1d2c3b4a5f60",
              "title": "La cellule, unité du vivant",
              "pinned": false
            }
          ],
          "requestId": null
        }
      ]
    }
  ]
}
```

### GET /api/open/v1/cours/lessons/{lessonId}

**One lesson**

The lesson in Markdown (CoolRoom blocks included), its path, authors and links.

Request:

```sh
curl "https://api.coolroom.app/api/open/v1/cours/lessons/5e550a11-8c2d-4b7a-9f3e-1d2c3b4a5f60" \
  -H "Authorization: Bearer $COOLROOM_KEY"
```

Response (200):

```json
{
  "classId": "c1a55e00-2b7d-4f1e-8a3c-6d9e0f1a2b3c",
  "lesson": {
    "id": "5e550a11-8c2d-4b7a-9f3e-1d2c3b4a5f60",
    "subjectKey": "svt",
    "subjectName": "SVT",
    "folderId": null,
    "title": "La cellule, unité du vivant",
    "tags": [
      "chapitre-2",
      "cellule"
    ],
    "visibility": "CLASS",
    "status": "COMPLETE",
    "givenOn": "2026-10-14",
    "createdAt": "2026-10-14T16:02:11Z",
    "updatedAt": "2026-10-15T09:40:00Z",
    "revision": 3,
    "readingMinutes": 6,
    "author": {
      "id": "7b1e4c2a-5d3f-4e8a-9c61-2f0d8b3a4e15",
      "displayName": "Léa Martin",
      "avatarIconId": "fox",
      "avatarPhotoVersion": null
    },
    "badges": [
      "NEW"
    ]
  },
  "markdown": "# La cellule, unité du vivant\n\n## Le noyau\n\nLe noyau contient l’ADN…",
  "path": [
    "Chapitre 2"
  ],
  "contributors": [
    {
      "id": "7b1e4c2a-5d3f-4e8a-9c61-2f0d8b3a4e15",
      "displayName": "Léa Martin",
      "avatarIconId": "fox",
      "avatarPhotoVersion": null
    }
  ],
  "links": [],
  "canEdit": false,
  "canDelete": false,
  "canManage": false,
  "social": {
    "thanks": 4,
    "thanked": true,
    "reported": false,
    "reports": 0,
    "hidden": false
  }
}
```

---

# Routes: Exercises

Scope: `exercises`

Training and Learning: each training card, what the student got right or wrong, their mistakes and weak points.

### GET /api/open/v1/exercises/classes/{classId}/results

**Results card by card**

Each card played: seen, right, missed (lapses), in the mistakes notebook or not, next review (dueOn). Most recent first.

Request:

```sh
curl "https://api.coolroom.app/api/open/v1/exercises/classes/c1a55e00-2b7d-4f1e-8a3c-6d9e0f1a2b3c/results" \
  -H "Authorization: Bearer $COOLROOM_KEY"
```

Response (200):

```json
{
  "classId": "c1a55e00-2b7d-4f1e-8a3c-6d9e0f1a2b3c",
  "total": 42,
  "inMistakes": 3,
  "due": 5,
  "results": [
    {
      "itemKey": "svt-cellule-q3",
      "lessonId": "5e550a11-8c2d-4b7a-9f3e-1d2c3b4a5f60",
      "lessonTitle": "La cellule, unité du vivant",
      "seen": 4,
      "correct": 2,
      "lapses": 2,
      "inMistakes": true,
      "reps": 0,
      "intervalDays": 1,
      "dueOn": "2026-10-22",
      "lastAnswerAt": "2026-10-21T17:10:00Z"
    }
  ]
}
```

### GET /api/open/v1/exercises/classes/{classId}/mistakes

**The mistakes notebook**

The missed cards (20 at most), with the question and the right answer. kind: FLASH, QCM, VF, CLOZE, ORDER, MATCH…

Request:

```sh
curl "https://api.coolroom.app/api/open/v1/exercises/classes/c1a55e00-2b7d-4f1e-8a3c-6d9e0f1a2b3c/mistakes" \
  -H "Authorization: Bearer $COOLROOM_KEY"
```

Response (200):

```json
{
  "scope": "errors",
  "title": "Mes erreurs",
  "subtitle": "Les cartes ratées reviennent jusqu’à deux bonnes réponses d’affilée",
  "timed": false,
  "secondsPerItem": 0,
  "items": [
    {
      "key": "svt-cellule-q3",
      "lessonId": "5e550a11-8c2d-4b7a-9f3e-1d2c3b4a5f60",
      "lessonTitle": "La cellule, unité du vivant",
      "kind": "QCM",
      "anchor": "le-noyau",
      "source": "LESSON",
      "prompt": "Où se trouve l’ADN dans une cellule animale ?",
      "answer": null,
      "options": [
        "Dans le noyau",
        "Dans la membrane",
        "Dans le cytoplasme seulement"
      ],
      "correct": [
        0
      ],
      "explanation": "L’ADN est dans le noyau (et un peu dans les mitochondries).",
      "sequence": null,
      "pairs": null,
      "truth": null,
      "game": "quiz"
    }
  ]
}
```

### GET /api/open/v1/exercises/classes/{classId}/weak

**Weak points**

The lessons the student misses most.

Request:

```sh
curl "https://api.coolroom.app/api/open/v1/exercises/classes/c1a55e00-2b7d-4f1e-8a3c-6d9e0f1a2b3c/weak" \
  -H "Authorization: Bearer $COOLROOM_KEY"
```

Response (200):

```json
[
  {
    "lessonId": "5e550a11-8c2d-4b7a-9f3e-1d2c3b4a5f60",
    "seen": 12,
    "missed": 5,
    "errors": 3
  }
]
```

### GET /api/open/v1/exercises/classes/{classId}

**Training summary**

Cards due, mistakes, revision plans before a test and the class challenge.

Request:

```sh
curl "https://api.coolroom.app/api/open/v1/exercises/classes/c1a55e00-2b7d-4f1e-8a3c-6d9e0f1a2b3c" \
  -H "Authorization: Bearer $COOLROOM_KEY"
```

Response (200):

```json
{
  "due": 5,
  "errors": 3,
  "weekLessons": 4,
  "challenge": {
    "goal": 300,
    "done": 212,
    "players": 17,
    "reached": false,
    "rewardCc": 20
  },
  "plans": [
    {
      "id": "3f4a5b6c-7d8e-4f9a-0b1c-2d3e4f5a6b7c",
      "title": "Contrôle SVT",
      "examOn": "2026-10-28",
      "daysLeft": 7,
      "lessons": [
        {
          "id": "5e550a11-8c2d-4b7a-9f3e-1d2c3b4a5f60",
          "title": "La cellule, unité du vivant",
          "subjectKey": "svt"
        }
      ],
      "total": 30,
      "seen": 18,
      "mastered": 9,
      "doneToday": false,
      "examDay": false,
      "sessionDays": [
        "2026-10-20"
      ]
    }
  ],
  "suggestions": []
}
```

### GET /api/open/v1/exercises/classes/{classId}/learn

**Learn**

Each lesson with games, and how much of each is learnt.

Request:

```sh
curl "https://api.coolroom.app/api/open/v1/exercises/classes/c1a55e00-2b7d-4f1e-8a3c-6d9e0f1a2b3c/learn" \
  -H "Authorization: Bearer $COOLROOM_KEY"
```

Response (200):

```json
{
  "lessons": [
    {
      "lessonId": "5e550a11-8c2d-4b7a-9f3e-1d2c3b4a5f60",
      "title": "La cellule, unité du vivant",
      "subjectKey": "svt",
      "subjectName": "SVT",
      "givenOn": "2026-10-14",
      "total": 24,
      "seen": 20,
      "mastered": 11,
      "due": 3,
      "games": [
        {
          "game": "quiz",
          "label": "Quiz",
          "count": 8,
          "mastered": 5
        }
      ],
      "decks": []
    }
  ]
}
```

### GET /api/open/v1/exercises/lessons/{lessonId}

**A lesson’s cards**

All the lesson’s training cards and the student’s counts.

Request:

```sh
curl "https://api.coolroom.app/api/open/v1/exercises/lessons/5e550a11-8c2d-4b7a-9f3e-1d2c3b4a5f60" \
  -H "Authorization: Bearer $COOLROOM_KEY"
```

Response (200):

```json
{
  "lessonId": "5e550a11-8c2d-4b7a-9f3e-1d2c3b4a5f60",
  "items": [
    {
      "key": "svt-cellule-q3",
      "lessonId": "5e550a11-8c2d-4b7a-9f3e-1d2c3b4a5f60",
      "lessonTitle": "La cellule, unité du vivant",
      "kind": "QCM",
      "anchor": "le-noyau",
      "source": "LESSON",
      "prompt": "Où se trouve l’ADN dans une cellule animale ?",
      "answer": null,
      "options": [
        "Dans le noyau",
        "Dans la membrane",
        "Dans le cytoplasme seulement"
      ],
      "correct": [
        0
      ],
      "explanation": "L’ADN est dans le noyau (et un peu dans les mitochondries).",
      "sequence": null,
      "pairs": null,
      "truth": null,
      "game": "quiz"
    }
  ],
  "sections": [
    {
      "anchor": "le-noyau",
      "title": "Le noyau",
      "ai": true
    }
  ],
  "sectionsToGenerate": 0,
  "errors": 1,
  "due": 2,
  "seen": 20,
  "mastered": 11
}
```

---

# Routes: Flash cards

Scope: `flashcards`

The student’s decks, the ones shared with them, and their games.

### GET /api/open/v1/flashcards/decks

**Decks**

kind: VOCAB or DEFINITION. myBest: best game, null if never played.

Request:

```sh
curl "https://api.coolroom.app/api/open/v1/flashcards/decks" \
  -H "Authorization: Bearer $COOLROOM_KEY"
```

Response (200):

```json
{
  "mine": [
    {
      "id": "4a5b6c7d-8e9f-4a0b-1c2d-3e4f5a6b7c8d",
      "title": "Verbes irréguliers",
      "subject": "Anglais",
      "emoji": "🇬🇧",
      "cardCount": 40,
      "owner": {
        "id": "7b1e4c2a-5d3f-4e8a-9c61-2f0d8b3a4e15",
        "displayName": "Léa Martin",
        "avatarIconId": "fox",
        "avatarPhotoVersion": null
      },
      "mine": true,
      "sharedIn": [
        {
          "classId": "c1a55e00-2b7d-4f1e-8a3c-6d9e0f1a2b3c",
          "className": "2nde 4"
        }
      ],
      "myBest": {
        "correct": 37,
        "total": 40
      },
      "myPlays": 6,
      "updatedAt": "2026-10-18T19:00:00Z",
      "lessonId": null,
      "kind": "VOCAB"
    }
  ],
  "shared": [],
  "stats": {
    "points": 1240,
    "runs": 18,
    "cardsReviewed": 610,
    "accuracy": 87,
    "perfectRuns": 2,
    "decksCreated": 3
  }
}
```

### GET /api/open/v1/flashcards/decks/{deckId}

**One deck and its cards**

Card images are not served by the API.

Request:

```sh
curl "https://api.coolroom.app/api/open/v1/flashcards/decks/4a5b6c7d-8e9f-4a0b-1c2d-3e4f5a6b7c8d" \
  -H "Authorization: Bearer $COOLROOM_KEY"
```

Response (200):

```json
{
  "deck": {
    "id": "4a5b6c7d-8e9f-4a0b-1c2d-3e4f5a6b7c8d",
    "title": "Verbes irréguliers",
    "…": "…"
  },
  "cards": [
    {
      "id": "5b6c7d8e-9f0a-4b1c-2d3e-4f5a6b7c8d9e",
      "position": 0,
      "frontText": "to begin",
      "backText": "began, begun",
      "frontImageVersion": null,
      "backImageVersion": null
    }
  ]
}
```

### GET /api/open/v1/flashcards/runs

**Games played**

The last 200, newest first.

Request:

```sh
curl "https://api.coolroom.app/api/open/v1/flashcards/runs" \
  -H "Authorization: Bearer $COOLROOM_KEY"
```

Response (200):

```json
[
  {
    "id": "6c7d8e9f-0a1b-4c2d-3e4f-5a6b7c8d9e0f",
    "deckId": "4a5b6c7d-8e9f-4a0b-1c2d-3e4f5a6b7c8d",
    "deckTitle": "Verbes irréguliers",
    "correct": 37,
    "total": 40,
    "durationMs": 182000,
    "playedAt": "2026-10-18T19:04:00Z"
  }
]
```

---

# Routes: Level and CC

Scope: `progress`

Student accounts only.

### GET /api/open/v1/progress

**Progress**

level.into / level.needed: XP in the current level / for the next one.

Request:

```sh
curl "https://api.coolroom.app/api/open/v1/progress" \
  -H "Authorization: Bearer $COOLROOM_KEY"
```

Response (200):

```json
{
  "level": {
    "level": 9,
    "xp": 4210,
    "into": 310,
    "needed": 600
  },
  "cc": 185,
  "loginStreak": 12,
  "bestLoginStreak": 21,
  "season": {
    "season": {
      "id": "7d8e9f0a-1b2c-4d3e-4f5a-6b7c8d9e0f1a",
      "name": "Saison d’automne",
      "beta": false,
      "startsAt": "2026-09-01T00:00:00Z",
      "endsAt": "2026-12-20T00:00:00Z",
      "colorA": "#31AAA9",
      "colorB": "#A82020",
      "backgroundVersion": null
    },
    "level": {
      "level": 14,
      "xp": 2100,
      "into": 100,
      "needed": 200
    },
    "seenLevel": 14,
    "passMax": 50
  },
  "stats": {
    "questsDone": 34,
    "homeworkVerified": 12,
    "homeworkDone": 88,
    "flashGames": 18,
    "cosmeticsOwned": 7,
    "ccEarned": 640
  }
}
```

---

# Routes: Notifications

Scope: `notifications`

The last 100, newest first.

### GET /api/open/v1/notifications

**Notifications**

type: NEW_HOMEWORK, NEW_GRADE, NEW_MAIL, LESSON_CHANGED, MENTION, CHAT_MESSAGE… relatedId: the thing it is about (homework, grade…).

Request:

```sh
curl "https://api.coolroom.app/api/open/v1/notifications" \
  -H "Authorization: Bearer $COOLROOM_KEY"
```

Response (200):

```json
[
  {
    "id": "8e9f0a1b-2c3d-4e4f-5a6b-7c8d9e0f1a2b",
    "type": "NEW_HOMEWORK",
    "category": "DEVOIRS",
    "title": "Nouveau devoir en Mathématiques",
    "body": "Exercices 12 à 15 p. 84, pour jeudi",
    "relatedId": "9d2f7a10-3b4c-4d5e-8f6a-7b8c9d0e1f2a",
    "classId": "c1a55e00-2b7d-4f1e-8a3c-6d9e0f1a2b3c",
    "read": false,
    "silent": false,
    "createdAt": "2026-10-21T16:00:05Z"
  }
]
```

---

# Routes: AI

Scope: `ai`

The student’s conversation with CoolRoom’s AI.

### GET /api/open/v1/ai/chat

**The conversation**

role: user or assistant. degree: the chosen help level (1 to 3).

Request:

```sh
curl "https://api.coolroom.app/api/open/v1/ai/chat" \
  -H "Authorization: Bearer $COOLROOM_KEY"
```

Response (200):

```json
[
  {
    "id": "9f0a1b2c-3d4e-4f5a-6b7c-8d9e0f1a2b3c",
    "role": "user",
    "content": "Explique-moi la mitose simplement",
    "degree": 2,
    "createdAt": "2026-10-21T17:20:00Z"
  },
  {
    "id": "0a1b2c3d-4e5f-4a6b-7c8d-9e0f1a2b3c4d",
    "role": "assistant",
    "content": "La mitose, c’est quand une cellule se divise en deux cellules identiques…",
    "degree": 2,
    "createdAt": "2026-10-21T17:20:09Z"
  }
]
```

---

# Routes: Family (parent accounts)

Scope: `family`

For a parent account: linked children and their data. 403 for a student account.

### GET /api/open/v1/family/children

**Linked children**

status: APPROVED once the child agreed.

Request:

```sh
curl "https://api.coolroom.app/api/open/v1/family/children" \
  -H "Authorization: Bearer $COOLROOM_KEY"
```

Response (200):

```json
[
  {
    "linkId": "1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
    "userId": "7b1e4c2a-5d3f-4e8a-9c61-2f0d8b3a4e15",
    "displayName": "Léa Martin",
    "avatarIconId": "fox",
    "avatarPhotoVersion": null,
    "status": "APPROVED",
    "createdAt": "2026-09-05T18:00:00Z",
    "approvedAt": "2026-09-05T18:03:00Z",
    "classNames": [
      "2nde 4"
    ]
  }
]
```

### GET /api/open/v1/family/children/{studentId}/grades

**A child’s grades**

Same shape as /grades.

Request:

```sh
curl "https://api.coolroom.app/api/open/v1/family/children/7b1e4c2a-5d3f-4e8a-9c61-2f0d8b3a4e15/grades" \
  -H "Authorization: Bearer $COOLROOM_KEY"
```

Response (200):

```json
[
  {
    "id": "3a4b5c6d-7e8f-4a1b-9c2d-3e4f5a6b7c8d",
    "subject": "Physique-Chimie",
    "title": "Contrôle : les ondes",
    "value": 15.5,
    "outOf": 20,
    "classAverage": 12.25,
    "classMin": 6,
    "classMax": 18.5,
    "coefficient": 2,
    "period": "Trimestre 1",
    "date": "2026-10-17",
    "revealed": true,
    "masked": false
  }
]
```

### GET /api/open/v1/family/children/{studentId}/homework

**A child’s homework**

With each homework’s class.

Request:

```sh
curl "https://api.coolroom.app/api/open/v1/family/children/7b1e4c2a-5d3f-4e8a-9c61-2f0d8b3a4e15/homework" \
  -H "Authorization: Bearer $COOLROOM_KEY"
```

Response (200):

```json
[
  {
    "id": "9d2f7a10-3b4c-4d5e-8f6a-7b8c9d0e1f2a",
    "subject": "Mathématiques",
    "title": "Exercices 12 à 15 p. 84",
    "description": "Faire les exercices sur les fonctions affines.",
    "dueAt": "2026-10-23T06:00:00Z",
    "status": "OFFICIEL",
    "isExam": false,
    "done": true,
    "completedAt": "2026-10-21T19:30:00Z",
    "className": "2nde 4"
  }
]
```

### GET /api/open/v1/family/children/{studentId}/timetable

**A child’s timetable**

Like /timetable: from and to, 62 days at most.

Request:

```sh
curl "https://api.coolroom.app/api/open/v1/family/children/7b1e4c2a-5d3f-4e8a-9c61-2f0d8b3a4e15/timetable?from=2026-10-19&to=2026-10-25" \
  -H "Authorization: Bearer $COOLROOM_KEY"
```

Response (200):

```json
[
  {
    "id": "6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e",
    "subject": "Histoire-Géographie",
    "teacher": "M. Laurent",
    "room": "B204",
    "startAt": "2026-10-22T07:00:00Z",
    "endAt": "2026-10-22T08:00:00Z",
    "canceled": false,
    "note": null,
    "detention": false
  }
]
```

---

# Terms of use

By using the API you respect students: use their data only for what your app tells them, never sell it, don't keep it longer than needed, and delete it when the student removes access. CoolRoom's conditions of use apply.

https://coolroom.app/en/terms/
