A **course** is sold through one or more products. Buying any of them in a paid order gives the shopper access, which they use in the store account under **My courses**. These endpoints are read-only; writing courses through the API is not available yet.

All endpoints require the **Courses module** to be enabled for the store (`404` when it is off) and the `courses:read` scope. Storefront keys (`storefront:read`) cannot read courses, because lessons carry unlisted YouTube IDs.

---

## List Courses

```
GET /api/v1/courses
```

Returns every course of the store, drafts included, ordered by title.

### Request

```bash
curl https://your-store.yns.store/api/v1/courses \
  -H "Authorization: Bearer $YNS_API_KEY"
```

### Response

```json
{
  "data": [
    {
      "id": "0191abc0-1234-7def-8000-000000000001",
      "slug": "mug-making",
      "title": "Mug making",
      "status": "published",
      "lessonCount": 8,
      "products": [{ "id": "0191abc0-aaaa-7def-8000-000000000010", "name": "Mug course" }],
      "updatedAt": "2026-11-02T14:50:00.000Z"
    }
  ]
}
```

| Field | Type | Description |
|-------|------|-------------|
| `status` | `string` | `draft` or `published` |
| `lessonCount` | `number` | Number of lessons |
| `products` | `array` | Products that grant access (`{ id, name }`) |

---

## Get Course

```
GET /api/v1/courses/:idOrSlug
```

Returns one course by UUID or slug, with its lessons in order and its files, whatever its status.

### Request

```bash
curl https://your-store.yns.store/api/v1/courses/mug-making \
  -H "Authorization: Bearer $YNS_API_KEY"
```

### Response

```json
{
  "course": {
    "id": "0191abc0-1234-7def-8000-000000000001",
    "slug": "mug-making",
    "title": "Mug making",
    "summary": "Make your first mug.",
    "content": { "type": "doc", "content": [] },
    "coverImage": "https://cdn.store.com/course.jpg",
    "status": "published",
    "products": [{ "id": "0191abc0-aaaa-7def-8000-000000000010", "name": "Mug course" }],
    "files": [
      {
        "id": "0191abc0-bbbb-7def-8000-000000000020",
        "label": "Clay guide",
        "filename": "clay-guide.pdf",
        "mimeType": "application/pdf",
        "sizeBytes": 482113
      }
    ],
    "lessons": [
      {
        "id": "0191abc0-cccc-7def-8000-000000000030",
        "position": 1,
        "title": "Preparing the clay",
        "content": { "type": "doc", "content": [] },
        "video": { "provider": "youtube", "videoId": "dQw4w9WgXcQ" },
        "files": []
      }
    ]
  }
}
```

| Field | Type | Description |
|-------|------|-------------|
| `content` | `object` | TipTap JSON document |
| `lessons[].video` | `object \| null` | `{ provider: "youtube", videoId }` or `null` |
| `files[]` | `object` | `{ id, label, filename, mimeType, sizeBytes }` |

Files never include their storage address. Students download them from the store account, which checks their access.

### Errors

| Status | Description |
|--------|-------------|
| `404` | Course not found, or the Courses module is not enabled |