# Canvas API

The Canvas API provides persistence for drag-and-drop cards and folders. Cards have a type, content, x/y position, optional folder assignment, and arbitrary metadata. Folders are ordered by creation date and can hold any number of cards.

## GET /api/v2/canvas/cards

List Cards -- Returns all canvas cards for the authenticated user, ordered by created_at descending. Optionally filter by folder.

**Authentication required**

### Query Parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| folder_id | string (UUID) | No | Filter cards belonging to a specific folder. Omit to return all cards. |

### Example Request

```bash
curl -X GET "https://api.lvng.ai/api/v2/canvas/cards?folder_id=d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
```

### Response (200)

```json
{
  "cards": [
    {
      "id": "7b8c9d0e-1f2a-3b4c-5d6e-7f8a9b0c1d2e",
      "type": "note",
      "content": "## Onboarding Flow\n1. Welcome email\n2. Profile setup",
      "position": { "x": 120, "y": 80 },
      "folder_id": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90",
      "metadata": { "color": "#3b82f6" },
      "created_at": "2026-03-12T09:00:00.000Z",
      "updated_at": "2026-03-18T15:30:00.000Z"
    },
    {
      "id": "2c3d4e5f-6a7b-8c9d-0e1f-2a3b4c5d6e7f",
      "type": "task",
      "content": "Audit rate-limiting config",
      "position": { "x": 450, "y": 80 },
      "folder_id": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90",
      "metadata": {},
      "created_at": "2026-03-14T11:20:00.000Z",
      "updated_at": "2026-03-14T11:20:00.000Z"
    }
  ]
}
```

## POST /api/v2/canvas/cards

Create Card -- Creates a new canvas card. The type field is required. Position defaults to (0, 0) if omitted.

**Authentication required**

### Body Parameters

| Name | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| type | string | Yes | -- | Card type identifier (e.g. "note", "task", "image", "link"). |
| content | string | No | "" | Card body content. Defaults to empty string. |
| position | object | No | { x: 0, y: 0 } | Coordinates as { x: number, y: number }. |
| folder_id | string (UUID) | No | null | Folder to place the card in. Null if not in a folder. |
| metadata | object | No | {} | Arbitrary JSON metadata (color, tags, etc.). |

### Example Request

```bash
curl -X POST https://api.lvng.ai/api/v2/canvas/cards \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "note",
    "content": "- Ship voice notes MVP\n- Fix calendar sync bug",
    "position": { "x": 200, "y": 300 },
    "folder_id": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90",
    "metadata": { "color": "#10b981" }
  }'
```

### Response (201)

```json
{
  "card": {
    "id": "9e0f1a2b-3c4d-5e6f-7a8b-9c0d1e2f3a4b",
    "type": "note",
    "content": "- Ship voice notes MVP\n- Fix calendar sync bug",
    "position": { "x": 200, "y": 300 },
    "folder_id": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90",
    "metadata": { "color": "#10b981" },
    "created_at": "2026-03-19T10:00:00.000Z",
    "updated_at": "2026-03-19T10:00:00.000Z"
  }
}
```

## PUT /api/v2/canvas/cards/:id

Update Card -- Updates an existing canvas card. Only provided fields are modified; the type field cannot be changed.

**Authentication required**

### Path Parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| id | string (UUID) | Yes | The card ID. |

### Body Parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| content | string | No | Updated card content. |
| position | object | No | Updated position as { x: number, y: number }. |
| folder_id | string (UUID) \| null | No | Move to a different folder, or null to unlink. |
| metadata | object | No | Replacement metadata object. |

### Example Request

```bash
curl -X PUT https://api.lvng.ai/api/v2/canvas/cards/9e0f1a2b-3c4d-5e6f-7a8b-9c0d1e2f3a4b \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "- Ship voice notes MVP\n- Fix calendar sync bug\n- Deploy knowledge base v2",
    "position": { "x": 200, "y": 350 }
  }'
```

### Response (200)

```json
{
  "card": {
    "id": "9e0f1a2b-3c4d-5e6f-7a8b-9c0d1e2f3a4b",
    "type": "note",
    "content": "- Ship voice notes MVP\n- Fix calendar sync bug\n- Deploy knowledge base v2",
    "position": { "x": 200, "y": 350 },
    "folder_id": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90",
    "metadata": { "color": "#10b981" },
    "created_at": "2026-03-19T10:00:00.000Z",
    "updated_at": "2026-03-19T10:25:00.000Z"
  }
}
```

## DELETE /api/v2/canvas/cards/:id

Delete Card -- Permanently deletes a canvas card. Returns 404 if the card does not exist or does not belong to the authenticated user.

**Authentication required**

### Path Parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| id | string (UUID) | Yes | The card ID to delete. |

### Example Request

```bash
curl -X DELETE https://api.lvng.ai/api/v2/canvas/cards/9e0f1a2b-3c4d-5e6f-7a8b-9c0d1e2f3a4b \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
```

### Response (200)

```json
{
  "success": true
}
```

## GET /api/v2/canvas/folders

List Folders -- Returns all canvas folders for the authenticated user, ordered by created_at ascending.

**Authentication required**

### Example Request

```bash
curl -X GET https://api.lvng.ai/api/v2/canvas/folders \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
```

### Response (200)

```json
{
  "folders": [
    {
      "id": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90",
      "customer_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "user_id": "f6a7b8c9-0d1e-2f3a-4b5c-6d7e8f901234",
      "name": "Product Roadmap",
      "color": "#6366f1",
      "created_at": "2026-02-01T08:00:00.000Z"
    },
    {
      "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
      "customer_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "user_id": "f6a7b8c9-0d1e-2f3a-4b5c-6d7e8f901234",
      "name": "Design System",
      "color": null,
      "created_at": "2026-02-15T10:00:00.000Z"
    }
  ]
}
```

## POST /api/v2/canvas/folders

Create Folder -- Creates a new folder to organize canvas cards. The name field is required.

**Authentication required**

### Body Parameters

| Name | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| name | string | Yes | -- | Folder display name. |
| color | string | No | null | Hex color code for the folder accent. |

### Example Request

```bash
curl -X POST https://api.lvng.ai/api/v2/canvas/folders \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Architecture Decisions",
    "color": "#f59e0b"
  }'
```

### Response (201)

```json
{
  "folder": {
    "id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
    "customer_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "user_id": "f6a7b8c9-0d1e-2f3a-4b5c-6d7e8f901234",
    "name": "Architecture Decisions",
    "color": "#f59e0b",
    "created_at": "2026-03-19T10:30:00.000Z"
  }
}
```

## DELETE /api/v2/canvas/folders/:id

Delete Folder -- Deletes a folder. Cards in the folder are unlinked (their folder_id is set to null) rather than deleted.

**Authentication required**

### Path Parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| id | string (UUID) | Yes | The folder ID to delete. |

### Example Request

```bash
curl -X DELETE https://api.lvng.ai/api/v2/canvas/folders/c3d4e5f6-a7b8-9012-cdef-123456789012 \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
```

### Response (200)

```json
{
  "success": true
}
```
