Skill: celend/memo-api (version 1.1.0)

--- name: memo-api description: > 墨墨背单词 MaiMemo Open API skill for vocabulary learning. Handles: 单词 vocabulary lookup (voc_id), 释义 interpretations (CRUD), 助记 mnemonics/notes, 云词本 notepads/word lists, 例句 phrases/example sentences, 学习数据 study progress/review schedule/study records. Triggers on: 墨墨, maimemo, 背单词, 释义, 助记, 云词本, 例句, study progress, review schedule, words due, forgotten words, study time, export study data. metadata: openclaw: requires: env: - MAIMEMO_TOKEN binds: - curl --- # MaiMemo Open API ## Auth & Base - **Base URL**: `https://open.maimemo.com/open/api/v1` - **Token**: env var `$MAIMEMO_TOKEN` — set via app (墨墨背单词 → 开放 API) - **Auth header**: `Authorization: Bearer $MAIMEMO_TOKEN` ```bash curl -s -X ${METHOD} "${BASE}/${PATH}" \ -H "Authorization: Bearer $MAIMEMO_TOKEN" \ -H "Content-Type: application/json" \ -d '${BODY}' ``` **Rate limits**: 20/10s, 40/60s, 2000/5h ## Key Concepts - **voc_id resolution**: Most endpoints need `voc_id`, not spelling. Resolve via `GET /vocabulary?spelling=word` or `POST /vocabulary/query` (batch up to 1000). - **POST for updates**: Update endpoints use `POST /resource/{id}`, not PUT/PATCH. - **Status values**: Resources use status enums (`PUBLISHED`, `UNPUBLISHED`, `DELETED`) — vary by domain. - **Timestamps**: All times are ISO 8601. Study date filters use Beijing timezone (UTC+8). ## Domain Routing | Task | Read reference file | |------|-------------------| | Look up voc_id / spelling → id | `vocabulary-api.md` | | CRUD custom definitions | `interpretations-api.md` | | CRUD mnemonics (联想/谐音/派生/词根/词源/固搭/语法/对比 etc.) | `notes-api.md` | | Manage word lists / cloud notepads | `notepads-api.md` | | CRUD example sentences | `phrases-api.md` | | Study progress, records, schedules | `study-api.md` | **Before calling any endpoint**, read the corresponding reference file for exact params, body schema, and curl examples. ## Study Usage Scenes All study endpoints are **POST** and **beta** (需要打开自动同步). ### Today's Progress **Endpoint**: `POST /study/get_study_progress` (empty body) Returns: `finished` (done count), `total` (target count), `study_time` (ms) | Scene | Endpoint | Key params | |-------|----------|-----------| | Words left today | `get_study_progress` | compute `total - finished` | | Study time today | `get_study_progress` | `study_time` (ms → min) | ### Today's Words **Endpoint**: `POST /study/get_today_items` | Scene | Endpoint | Key params | |-------|----------|-----------| | Forgotten words today | `get_today_items` | `is_finished: true`, filter `first_response = "FORGET"` | | New words today | `get_today_items` | `is_new: true` | | Unfinished words | `get_today_items` | `is_finished: false` | | Specific word history | `get_today_items` | `spellings: ["word"]` or `voc_ids: ["id"]` | ### Study Records **Endpoint**: `POST /study/query_study_records` | Scene | Endpoint | Key params | |-------|----------|-----------| | Words due in next N days | `query_study_records` | `next_study_date.end: "YYYY-MM-DDT00:00:00+08:00"`, `as_count: true` | | Total words in plan | `query_study_records` | `as_count: true` (no filters) | | Frequently forgotten (sticky) | `query_study_records` | iterate pages, filter `tags = "STICKING"` | | Well-familiar words | `query_study_records` | iterate pages, filter `tags = "WELL_FAMILIAR"` | | Export all study data | `query_study_records` | paginate via sliding `next_study_date` window, `limit: 1000` | ### Adding Words **Endpoint**: `POST /study/add_words` | Scene | Endpoint | Key params | |-------|----------|-----------| | Add words to plan | `add_words` | `words: [{"id": "voc_id"}]`, max 1000 | | Add and advance review | `add_words` | `advance: true` (also triggers immediate review, no level limit) | ### Advance Review **Endpoint**: `POST /study/advance_study` | Scene | Endpoint | Key params | |-------|----------|-----------| | Advance words for immediate review | `advance_study` | `voc_ids: ["voc_id1", ...]`, max 1000 | | Requires level 10+ to unlock advance review feature | | | ## Multi-domain Workflow Hints - **Add mnemonic to word**: Vocabulary (get voc_id) → Notes (create) - **Add example sentence**: Vocabulary (get voc_id) → Phrases (create) - **Add custom definition**: Vocabulary (get voc_id) → Interpretations (create) - **Build word list from study data**: Study records (query) → Notepads (create with spellings) - **Full word info**: Vocabulary (get voc_id) → Interpretations + Notes + Phrases (list all)

path: references/interpretations-api.md
content: # Interpretations API (释义)

CRUD for custom word definitions. All scoped to the authenticated user.

## Endpoints

### GET /interpretations — List interpretations

| Param | In | Required | Description |
|-------|----|----------|-------------|
| `voc_id` | query | yes | Word id |

**Response**: `{ "interpretations": [Interpretation, ...] }`

```bash
curl -s "https://open.maimemo.com/open/api/v1/interpretations?voc_id=VOC_ID" \
  -H "Authorization: Bearer $MAIMEMO_TOKEN"
```

### POST /interpretations — Create interpretation

**Body**:
```json
{
  "interpretation": {
    "voc_id": "VOC_ID",
    "interpretation": "n. 苹果",
    "tags": ["简明"],
    "status": "PUBLISHED"
  }
}
```

**Response**: `{ "interpretation": Interpretation }`

```bash
curl -s -X POST "https://open.maimemo.com/open/api/v1/interpretations" \
  -H "Authorization: Bearer $MAIMEMO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"interpretation":{"voc_id":"VOC_ID","interpretation":"n. 苹果","tags":["考研"],"status":"PUBLISHED"}}'
```

### POST /interpretations/{id} — Update interpretation

**Body**:
```json
{
  "interpretation": {
    "interpretation": "n. 苹果; 苹果公司",
    "tags": ["简明"],
    "status": "PUBLISHED"
  }
}
```

**Response**: `{ "interpretation": Interpretation }`

### DELETE /interpretations/{id} — Delete interpretation

No body. No response body.

## Valid Tags (multi-select, max 3)

`简明` · `详细` · `英英` · `小学` · `初中` · `高中` · `四级` · `六级` · `专升本` · `专四` · `专八` · `考研` · `考博` · `雅思` · `托福` · `托业` · `新概念` · `GRE` · `GMAT` · `BEC` · `MBA` · `SAT` · `ACT` · `法学` · `医学`

## InterpretationStatus Enum

| Value | Description |
|-------|-------------|
| `PUBLISHED` | 发布 |
| `UNPUBLISHED` | 未发布 |
| `DELETED` | 删除 |

## Interpretation Schema

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `id` | string | yes | Interpretation id |
| `interpretation` | string | yes | Definition text |
| `tags` | string[] | yes | Tags |
| `status` | InterpretationStatus | yes | Status |
| `created_time` | ISO 8601 | yes | Created at |
| `updated_time` | ISO 8601 | yes | Updated at |


path: references/notepads-api.md
content: # Notepads API (云词本)

CRUD for cloud word lists. Supports pagination, chapters, and bulk word import.

## Endpoints

### GET /notepads — List notepads

| Param | In | Required | Description |
|-------|----|----------|-------------|
| `limit` | query | yes | Page size |
| `offset` | query | yes | Skip count |
| `ids` | query | no | Filter by notepad ids |

**Response**: `{ "notepads": [BriefNotepad, ...] }`

```bash
curl -s "https://open.maimemo.com/open/api/v1/notepads?limit=10&offset=0" \
  -H "Authorization: Bearer $MAIMEMO_TOKEN"
```

### GET /notepads/{id} — Get notepad (full)

Returns full notepad with `content` and parsed `list`.

**Response**: `{ "notepad": Notepad }`

```bash
curl -s "https://open.maimemo.com/open/api/v1/notepads/NOTEPAD_ID" \
  -H "Authorization: Bearer $MAIMEMO_TOKEN"
```

### POST /notepads — Create notepad

**Body**:
```json
{
  "notepad": {
    "title": "GRE高频词",
    "brief": "GRE常考词汇",
    "content": "# Chapter 1\napple\nbanana\n# Chapter 2\ncat\ndog",
    "tags": ["GRE"],
    "status": "PUBLISHED"
  }
}
```

**Response**: `{ "notepad": Notepad }`

```bash
curl -s -X POST "https://open.maimemo.com/open/api/v1/notepads" \
  -H "Authorization: Bearer $MAIMEMO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"notepad":{"title":"GRE高频词","brief":"GRE常考词汇","content":"# Chapter 1\napple\nbanana","tags":["GRE"],"status":"PUBLISHED"}}'
```

### POST /notepads/{id} — Update notepad

Same body structure as create. All fields required.

**Response**: `{ "notepad": Notepad }`

### DELETE /notepads/{id} — Delete notepad

**Response**: `{ "notepad": Notepad }`

## Content Format

- One word per line
- Lines starting with `#` are chapter headings
- Example: `# Chapter 1\napple\nbanana\n# Chapter 2\ncat`

## NotepadStatus Enum

| Value | Description |
|-------|-------------|
| `PUBLISHED` | 发布 |
| `UNPUBLISHED` | 未发布 |
| `DELETED` | 删除 |

## NotepadType Enum

| Value | Description |
|-------|-------------|
| `FAVORITE` | 我的收藏 |
| `NOTEPAD` | 云词本 |

## BriefNotepad Schema

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `id` | string | yes | Notepad id |
| `type` | NotepadType | yes | Type |
| `creator` | integer | yes | Creator user id |
| `status` | NotepadStatus | yes | Status |
| `title` | string | yes | Title |
| `brief` | string | yes | Description |
| `tags` | string[] | yes | Tags |
| `created_time` | ISO 8601 | yes | Created at |
| `updated_time` | ISO 8601 | yes | Updated at |

## Notepad Schema (extends BriefNotepad)

Additional fields:

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `content` | string | yes | Raw content (newline-separated words, `#` chapters) |
| `list` | NotepadParsedItem[] | yes | Parsed content |

### NotepadParsedItem

| Field | Type | Description |
|-------|------|-------------|
| `type` | `"CHAPTER"` \| `"WORD"` | Item type |
| `data.chapter` | string | Chapter name (always present) |
| `data.word` | string | Word spelling (only when type=WORD) |


path: references/notes-api.md
content: # Notes API (助记)

CRUD for word mnemonics. All scoped to the authenticated user.

## Endpoints

### GET /notes — List notes

| Param | In | Required | Description |
|-------|----|----------|-------------|
| `voc_id` | query | yes | Word id |

**Response**: `{ "notes": [Note, ...] }`

```bash
curl -s "https://open.maimemo.com/open/api/v1/notes?voc_id=VOC_ID" \
  -H "Authorization: Bearer $MAIMEMO_TOKEN"
```

### POST /notes — Create note

**Body**:
```json
{
  "note": {
    "voc_id": "VOC_ID",
    "note_type": "谐音",
    "note": "apple 谐音 '阿婆' → 阿婆在吃苹果"
  }
}
```

**Response**: `{ "note": Note }`

```bash
curl -s -X POST "https://open.maimemo.com/open/api/v1/notes" \
  -H "Authorization: Bearer $MAIMEMO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"note":{"voc_id":"VOC_ID","note_type":"谐音","note":"apple 谐音 阿婆 → 阿婆在吃苹果"}}'
```

### POST /notes/{id} — Update note

**Body**:
```json
{
  "note": {
    "note_type": "词根",
    "note": "updated mnemonic text"
  }
}
```

**Response**: `{ "note": Note }`

### DELETE /notes/{id} — Delete note

No body. No response body.

## note_type Values

`联想` · `谐音` · `派生` · `词根` · `词源` · `固搭` · `语法` · `对比` · `近义` · `反义` · `扩展` · `串记` · `口诀` · `合成` · `吐槽` · `其他` · `固定搭配` · `词根词缀` · `辨析` · `近反义词` · `图例`

## NoteStatus Enum

| Value | Description |
|-------|-------------|
| `PUBLISHED` | 发布 |
| `DELETED` | 删除 |

## Note Schema

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `id` | string | yes | Note id |
| `note_type` | string | yes | Mnemonic type |
| `note` | string | yes | Mnemonic content |
| `status` | NoteStatus | yes | Status |
| `created_time` | ISO 8601 | yes | Created at |
| `updated_time` | ISO 8601 | yes | Updated at |


path: references/phrases-api.md
content: # Phrases API (例句)

CRUD for example sentences. All scoped to the authenticated user.

## Endpoints

### GET /phrases — List phrases

| Param | In | Required | Description |
|-------|----|----------|-------------|
| `voc_id` | query | yes | Word id |

**Response**: `{ "phrases": [Phrase, ...] }`

```bash
curl -s "https://open.maimemo.com/open/api/v1/phrases?voc_id=VOC_ID" \
  -H "Authorization: Bearer $MAIMEMO_TOKEN"
```

### POST /phrases — Create phrase

**Body**:
```json
{
  "phrase": {
    "voc_id": "VOC_ID",
    "phrase": "This is an apple.",
    "interpretation": "这是一个苹果。",
    "tags": ["词典"],
    "origin": "自编"
  }
}
```

**Response**: `{ "phrase": Phrase }`

```bash
curl -s -X POST "https://open.maimemo.com/open/api/v1/phrases" \
  -H "Authorization: Bearer $MAIMEMO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"phrase":{"voc_id":"VOC_ID","phrase":"This is an apple.","interpretation":"这是一个苹果。","tags":["词典"],"origin":"自编"}}'
```

### POST /phrases/{id} — Update phrase

**Body**:
```json
{
  "phrase": {
    "phrase": "I ate an apple.",
    "interpretation": "我吃了一个苹果。",
    "tags": ["词典"],
    "origin": "自编"
  }
}
```

**Response**: `{ "phrase": Phrase }`

### DELETE /phrases/{id} — Delete phrase

**Response**: `{ "phrase": Phrase }`

## Valid Tags (multi-select, max 3)

`小学` · `初中` · `高中` · `四级` · `六级` · `专升本` · `专四` · `专八` · `考研` · `考博` · `雅思` · `托福` · `托业` · `新概念` · `GRE` · `GMAT` · `BEC` · `MBA` · `SAT` · `ACT` · `法学` · `医学` · `词典` · `短语`

## PhraseStatus Enum

| Value | Description |
|-------|-------------|
| `PUBLISHED` | 发布 |
| `DELETED` | 删除 |

## PhraseHighlightRange

Marks the word position in the sentence. Half-open interval `[start, end)`.

| Field | Type | Description |
|-------|------|-------------|
| `start` | integer | Start index |
| `end` | integer | End index (exclusive) |

## Phrase Schema

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `id` | string | yes | Phrase id |
| `phrase` | string | yes | Sentence text |
| `interpretation` | string | yes | Translation |
| `tags` | string[] | yes | Tags |
| `highlight` | PhraseHighlightRange[] | yes | Word highlight ranges |
| `status` | PhraseStatus | yes | Status |
| `origin` | string | yes | Source/origin |
| `created_time` | ISO 8601 | yes | Created at |
| `updated_time` | ISO 8601 | yes | Updated at |


path: references/study-api.md
content: # Study API (学习数据)

**Beta (公测)**: 限时试用，不保证可用性，可能随时调整。需要打开自动同步。如果当日未打开 App 进行初始化则无法准确计算。

## Endpoints

### POST /study/get_study_progress — Today's progress

No request body needed.

**Response**:
```json
{
  "progress": {
    "finished": 10,
    "total": 20,
    "study_time": 114514
  }
}
```

```bash
curl -s -X POST "https://open.maimemo.com/open/api/v1/study/get_study_progress" \
  -H "Authorization: Bearer $MAIMEMO_TOKEN"
```

### POST /study/get_today_items — Today's word list

**Body params** (all optional):

| Field | Type | Description |
|-------|------|-------------|
| `is_finished` | boolean | Filter by completion status |
| `is_new` | boolean | Filter new words only |
| `voc_ids` | string[] | Query by voc_ids (max 1000, ignores other filters) |
| `spellings` | string[] | Query by spellings (max 1000, ignores other filters, mutually exclusive with voc_ids) |
| `limit` | integer | Max results by study order (default 50, max 1000) |

**Response**: `{ "today_items": [StudyTodayItem, ...] }`

```bash
# Unfinished words
curl -s -X POST "https://open.maimemo.com/open/api/v1/study/get_today_items" \
  -H "Authorization: Bearer $MAIMEMO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"is_finished": false, "limit": 1000}'
```

### POST /study/query_study_records — Query study records

**Body params** (all optional):

| Field | Type | Description |
|-------|------|-------------|
| `next_study_date.start` | ISO 8601 | Filter ≥ date (Beijing timezone) |
| `next_study_date.end` | ISO 8601 | Filter ≤ date (Beijing timezone) |
| `voc_ids` | string[] | Query by voc_ids (ignores other filters) |
| `spellings` | string[] | Query by spellings (max 1000, ignores other filters, mutually exclusive with voc_ids) |
| `as_count` | boolean | Return count only, no data list |
| `limit` | integer | Max results by next_study_date order (default 50, max 1000) |

**Response**: `{ "records": [StudyRecord, ...], "count": 114514 }`

- When `as_count=true`: `records` is empty, `count` has the total.
- When `as_count=false`: `records` has data, `count` is 0.

```bash
# Total words in plan
curl -s -X POST "https://open.maimemo.com/open/api/v1/study/query_study_records" \
  -H "Authorization: Bearer $MAIMEMO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"as_count": true}'
```

### POST /study/add_words — Add words to study plan

Add words to your study plan. Optionally advance them to immediate review.

**Body params**:

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `words` | array | yes | List of word objects, max 1000 |
| `words[].id` | string | yes | Word ID (voc_id), get via vocabulary API |
| `advance` | boolean | yes | Also advance to immediate review (no level limit) |

**Response**: `{ "added_count": 114 }`

- `added_count`: Number successfully added (may be less than requested due to word limits or already in plan)

```bash
# Add words without advancing
curl -s -X POST "https://open.maimemo.com/open/api/v1/study/add_words" \
  -H "Authorization: Bearer $MAIMEMO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "words": [
      {"id": "word_id_1"},
      {"id": "word_id_2"}
    ],
    "advance": false
  }'

# Add and advance immediately
curl -s -X POST "https://open.maimemo.com/open/api/v1/study/add_words" \
  -H "Authorization: Bearer $MAIMEMO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "words": [{"id": "word_id_1"}],
    "advance": true
  }'
```

### POST /study/advance_study — Advance words to immediate review

Move words to immediate review (next study date = now). Requires level 10+ to unlock advance review feature.

**Body params**:

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `voc_ids` | string[] | yes | Word IDs to advance, max 1000 |

**Response**: `{ "advanced_count": 514 }`

- `advanced_count`: Number successfully advanced (may be less if words not in plan)

```bash
curl -s -X POST "https://open.maimemo.com/open/api/v1/study/advance_study" \
  -H "Authorization: Bearer $MAIMEMO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "voc_ids": ["word_id_1", "word_id_2"]
  }'
```

## Usage Scenes

### 1. Words left today / study time
```bash
curl -s -X POST ".../study/get_study_progress" \
  -H "Authorization: Bearer $MAIMEMO_TOKEN"
# → total - finished = remaining; study_time / 60000 = minutes
```

### 2. Forgotten words today
```bash
curl -s -X POST ".../study/get_today_items" \
  -H "Authorization: Bearer $MAIMEMO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"is_finished": true, "limit": 1000}'
# → filter items where first_response = "FORGET"
```

### 3. New words today
```bash
curl -s -X POST ".../study/get_today_items" \
  -H "Authorization: Bearer $MAIMEMO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"is_new": true, "limit": 1000}'
```

### 4. Unfinished words
```bash
curl -s -X POST ".../study/get_today_items" \
  -H "Authorization: Bearer $MAIMEMO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"is_finished": false, "limit": 1000}'
```

### 5. Specific word study history
```bash
curl -s -X POST ".../study/get_today_items" \
  -H "Authorization: Bearer $MAIMEMO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"spellings": ["apple"]}'
# For full history use query_study_records:
curl -s -X POST ".../study/query_study_records" \
  -H "Authorization: Bearer $MAIMEMO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"spellings": ["apple"]}'
```

### 6. Words due in next N days
```bash
# Example: words due by April 1st
curl -s -X POST ".../study/query_study_records" \
  -H "Authorization: Bearer $MAIMEMO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"next_study_date": {"end": "2026-04-01T00:00:00+08:00"}, "as_count": true}'
```

### 7. Total words in plan
```bash
curl -s -X POST ".../study/query_study_records" \
  -H "Authorization: Bearer $MAIMEMO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"as_count": true}'
```

### 8. Frequently forgotten words (sticky)
```bash
# Paginate with sliding date window, filter tags = "STICKING"
curl -s -X POST ".../study/query_study_records" \
  -H "Authorization: Bearer $MAIMEMO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"limit": 1000}'
# → filter records where tags = "STICKING"
```

### 9. Well-familiar words
```bash
curl -s -X POST ".../study/query_study_records" \
  -H "Authorization: Bearer $MAIMEMO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"limit": 1000}'
# → filter records where tags = "WELL_FAMILIAR"
```

### 10. Export all study data
Paginate via sliding `next_study_date` window since API returns max 1000 per call:
```bash
# Page 1: earliest records
curl -s -X POST ".../study/query_study_records" \
  -H "Authorization: Bearer $MAIMEMO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"limit": 1000}'
# Page 2+: use last record's next_study_date as new start
# -d '{"next_study_date": {"start": "LAST_RECORD_DATE"}, "limit": 1000}'
# Repeat until fewer than 1000 records returned.
```

### 11. Words due on a specific date range
```bash
curl -s -X POST ".../study/query_study_records" \
  -H "Authorization: Bearer $MAIMEMO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"next_study_date": {"start": "2026-03-20T00:00:00+08:00", "end": "2026-03-25T00:00:00+08:00"}, "limit": 1000}'
```

### 12. Words due on a date
```bash
curl -s -X POST ".../study/query_study_records" \
  -H "Authorization: Bearer $MAIMEMO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"next_study_date": {"end": "2026-03-25T00:00:00+08:00"}, "limit": 1000}'
```

### 13. Add words to study plan
```bash
# First lookup word IDs
curl -s -X POST ".../vocabulary/query" \
  -H "Authorization: Bearer $MAIMEMO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"spellings": ["apple", "banana"]}'

# Then add them
curl -s -X POST ".../study/add_words" \
  -H "Authorization: Bearer $MAIMEMO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "words": [
      {"id": "voc_id_1"},
      {"id": "voc_id_2"}
    ],
    "advance": false
  }'
```

### 14. Add and immediately review words
```bash
# Add words and advance them for immediate review (no level limit)
curl -s -X POST ".../study/add_words" \
  -H "Authorization: Bearer $MAIMEMO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "words": [{"id": "voc_id_1"}, {"id": "voc_id_2"}],
    "advance": true
  }'
```

### 15. Advance existing words for immediate review
```bash
# Advance words already in your plan (requires level 10+)
curl -s -X POST ".../study/advance_study" \
  -H "Authorization: Bearer $MAIMEMO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"voc_ids": ["voc_id_1", "voc_id_2"]}'
```

## StudyResponse Enum

| Value | Description |
|-------|-------------|
| `FAMILIAR` | 认识 |
| `VAGUE` | 模糊 |
| `FORGET` | 忘记 |
| `WELL_FAMILIAR` | 熟知 |
| `CANCEL_WELL_FAMILIAR` | 取消熟知 |

## StudyProgress Schema

| Field | Type | Description |
|-------|------|-------------|
| `finished` | integer | Words completed today |
| `total` | integer | Target word count today |
| `study_time` | integer | Study time in milliseconds |

## StudyTodayItem Schema

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `voc_id` | string | yes | Word id |
| `voc_spelling` | string | yes | Word spelling |
| `order` | integer | yes | Study order |
| `first_response` | StudyResponse | no | First response today |
| `is_new` | boolean | yes | Is new word |
| `is_finished` | boolean | yes | Finished today |

## StudyRecord Schema

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `voc_id` | string | yes | Word id |
| `voc_spelling` | string | yes | Word spelling |
| `add_date` | ISO 8601 | yes | Date added |
| `first_study_date` | ISO 8601 | no | First study date |
| `last_study_date` | ISO 8601 | no | Last study date |
| `next_study_date` | ISO 8601 | no | Next study date |
| `last_response` | StudyResponse | no | Last response |
| `study_count` | integer | yes | Study count (max 1/day) |
| `tags` | `"STICKING"` \| `"WELL_FAMILIAR"` | yes | Record tag |


path: references/vocabulary-api.md
content: # Vocabulary API

Read-only endpoints to resolve `voc_id` from spelling (or vice versa). Most other APIs require `voc_id`.

## Endpoints

### GET /vocabulary — Get single word

| Param | In | Required | Description |
|-------|----|----------|-------------|
| `spelling` | query | yes | Word spelling (e.g. `apple`) |

**Response**: `{ "voc": { "id": "...", "spelling": "..." } }`

```bash
curl -s "https://open.maimemo.com/open/api/v1/vocabulary?spelling=apple" \
  -H "Authorization: Bearer $MAIMEMO_TOKEN"
```

### POST /vocabulary/query — Batch query

Query by spellings or ids (mutually exclusive, max 1000 each).

**Body**:
```json
{ "spellings": ["apple", "banana"] }
// or
{ "ids": ["id1", "id2"] }
```

**Response**: `{ "voc": [{ "id": "...", "spelling": "..." }, ...] }`

```bash
curl -s -X POST "https://open.maimemo.com/open/api/v1/vocabulary/query" \
  -H "Authorization: Bearer $MAIMEMO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"spellings": ["apple", "banana"]}'
```

## Vocabulary Schema

| Field | Type | Description |
|-------|------|-------------|
| `id` | string | Unique voc_id |
| `spelling` | string | Word spelling |


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (HIGH)