# TuraLula API reference

**Base URL:** `https://www.turalula.com/api/v1`

**Authentication:** `Authorization: Bearer <API_KEY>` on every request. Keys from [turalogin.com/dashboard/keys](https://www.turalogin.com/dashboard/keys).

**Rate limit:** 60 requests/minute per key.

---

## Lessons

### Create lesson

```
POST /lula/lessons
```

**Request body:**

```typescript
{
  title: string;           // Required
  description?: string;
  coverImage?: string;     // URL
  steps?: Array<{
    type: "text" | "image" | "quiz" | "embed";
    content?: string;      // For text type
    url?: string;          // For image/embed type
    caption?: string;      // For image type
    question?: string;     // For quiz type
    options?: string[];    // For quiz type
    answer?: string;       // For quiz type
    embedUrl?: string;     // For embed type
    provider?: string;     // For embed type
  }>;
  tags?: string[];
  status?: string;         // "draft" (default), "published", "archived"
  gated?: boolean;
  metadata?: object;
}
```

**Response:** `201 Created`

```json
{ "data": { "id": "uuid", "title": "...", "status": "draft", "stepCount": 5, ... } }
```

### List lessons

```
GET /lula/lessons?status=published&search=color&page=1&limit=20
```

**Query params:** `status`, `search` (title match), `tags` (comma-separated), `page`, `limit` (max 100).

### Get lesson

```
GET /lula/lessons/:id
```

Returns the lesson with all steps included.

### Update lesson

```
PUT /lula/lessons/:id
```

Same body fields as create. Only provided fields are updated.

### Delete lesson

```
DELETE /lula/lessons/:id
```

---

## Quizzes

### Create quiz

```
POST /lula/quizzes
```

**Request body:**

```typescript
{
  title: string;           // Required
  description?: string;
  questions?: Array<{
    type: "multiple-choice" | "fill-in" | "image-pick";
    question: string;
    options?: string[];          // For multiple-choice
    images?: string[];           // For image-pick (URLs)
    correctIndex?: number;       // For image-pick
    answer?: string;             // For multiple-choice and fill-in
  }>;
  passingScore?: number;   // 0-100, default 70
  tags?: string[];
  status?: string;
  gated?: boolean;
  metadata?: object;
}
```

### List quizzes

```
GET /lula/quizzes?status=published&page=1&limit=20
```

### Get quiz

```
GET /lula/quizzes/:id
```

### Update quiz

```
PUT /lula/quizzes/:id
```

### Delete quiz

```
DELETE /lula/quizzes/:id
```

### Submit quiz answers

```
POST /lula/quizzes/:id/submit
```

**Body:** `{ "answers": ["Red", "green"] }` (array matching question order)

**Response:**

```json
{
  "data": {
    "score": 100,
    "passed": true,
    "correctCount": 2,
    "totalQuestions": 2,
    "results": [
      { "question": "Which is a primary color?", "correct": true, "yourAnswer": "Red" },
      { "question": "Blue and yellow make ___", "correct": true, "yourAnswer": "green" }
    ]
  }
}
```

---

## Stories

### Create story

```
POST /lula/stories
```

**Request body:**

```typescript
{
  title: string;           // Required
  cards?: Array<{
    image?: string;        // URL
    text?: string;         // Short text (max 280 chars)
    emoji?: string;
    backgroundColor?: string; // Hex color
  }>;
  tags?: string[];
  status?: string;
  gated?: boolean;
  metadata?: object;
}
```

### List stories

```
GET /lula/stories?status=published&page=1&limit=20
```

### Get story

```
GET /lula/stories/:id
```

### Update story

```
PUT /lula/stories/:id
```

### Delete story

```
DELETE /lula/stories/:id
```

---

## Reactions

### Add reaction

```
POST /lula/reactions
```

**Body:** `{ "contentType": "lesson", "contentId": "uuid", "emoji": "🔥" }`

### Get reactions

```
GET /lula/reactions/:contentType/:contentId
```

**Response:**

```json
{ "data": { "total": 42, "breakdown": { "🔥": 15, "💡": 12, "❤️": 10, "😂": 5 } } }
```

### Remove reaction

```
DELETE /lula/reactions/:id
```

---

## Learning paths

### Create path

```
POST /lula/paths
```

**Body:** `title` (required), `description`, `items` (array of `{ contentType, contentId, position }`), `tags`, `status`, `metadata`.

### List paths

```
GET /lula/paths?status=published&page=1&limit=20
```

### Get path

```
GET /lula/paths/:id
```

Returns path with resolved item titles and types.

### Update path

```
PUT /lula/paths/:id
```

### Delete path

```
DELETE /lula/paths/:id
```

---

## Stats

```
GET /lula/stats
```

**Response:**

```json
{
  "data": {
    "lessons": { "total": 24, "published": 18, "draft": 6 },
    "quizzes": { "total": 12, "published": 10 },
    "stories": { "total": 30, "published": 25 },
    "paths": { "total": 5 },
    "reactions": { "total": 340 }
  }
}
```

---

## Error codes

| Status | Meaning |
|--------|---------|
| 400 | Bad request (missing required fields, invalid input) |
| 401 | Unauthorized (missing or invalid API key) |
| 404 | Not found |
| 429 | Rate limited (60 req/min) |
| 500 | Server error |

Error response shape: `{ "error": "message" }`
