{
	"info": {
		"_postman_id": "manabou-api-collection",
		"name": "Manabou API (Nihongo)",
		"description": "Postman collection for Manabou / Nihongo backend API.\nBase URL: https://nihongo-api.jabbar.id/\n\n**Auth:** Use Register or Login to get a token, then set the `token` collection variable. Protected requests use Bearer auth automatically.",
		"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
	},
	"variable": [
		{
			"key": "base_url",
			"value": "http://localhost:8000"
		},
		{
			"key": "token",
			"value": ""
		},
		{
			"key": "card_id",
			"value": "1"
		},
		{
			"key": "reading_id",
			"value": "1"
		},
		{
			"key": "item_id",
			"value": "1"
		},
		{
			"key": "session_id",
			"value": "1"
		},
		{
			"key": "mnemonic_id",
			"value": "1"
		},
		{
			"key": "deck_slug",
			"value": "general"
		},
		{
			"key": "practice_sentence_id",
			"value": "1"
		}
	],
	"auth": {
		"type": "bearer",
		"bearer": [
			{
				"key": "token",
				"value": "{{token}}",
				"type": "string"
			}
		]
	},
	"item": [
		{
			"name": "Health",
			"item": [
				{
					"name": "API Health",
					"request": {
						"auth": {
							"type": "noauth"
						},
						"method": "GET",
						"header": [],
						"url": "{{base_url}}/",
						"description": "Check API status (no auth required)."
					}
				}
			]
		},
		{
			"name": "Auth",
			"item": [
				{
					"name": "Register",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"if (pm.response.code === 201) {",
									"    const json = pm.response.json();",
									"    if (json.token) pm.collectionVariables.set('token', json.token);",
									"}"
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"auth": {
							"type": "noauth"
						},
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n  \"name\": \"Test User\",\n  \"email\": \"test@example.com\",\n  \"password\": \"password123\",\n  \"password_confirmation\": \"password123\"\n}"
						},
						"url": "{{base_url}}/api/v1/auth/register",
						"description": "Register a new user. Requires: name, email, password, password_confirmation (min 8 chars). Saves token to collection if successful."
					}
				},
				{
					"name": "Login",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"if (pm.response.code === 200) {",
									"    const json = pm.response.json();",
									"    if (json.token) pm.collectionVariables.set('token', json.token);",
									"}"
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"auth": {
							"type": "noauth"
						},
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n  \"email\": \"test@example.com\",\n  \"password\": \"password123\"\n}"
						},
						"url": "{{base_url}}/api/v1/auth/login",
						"description": "Login with email and password. Saves token to collection if successful."
					}
				},
				{
					"name": "Logout",
					"request": {
						"method": "POST",
						"header": [],
						"url": "{{base_url}}/api/v1/auth/logout",
						"description": "Invalidate current Bearer token (auth required)."
					}
				},
				{
					"name": "Me (current user)",
					"request": {
						"method": "GET",
						"header": [],
						"url": "{{base_url}}/api/v1/me",
						"description": "Get current authenticated user."
					}
				}
			]
		},
		{
			"name": "Profile",
			"item": [
				{
					"name": "Update profile",
					"request": {
						"method": "PUT",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n  \"name\": \"Updated Name\",\n  \"whatsapp_number\": \"+6281234567890\"\n}"
						},
						"url": "{{base_url}}/api/v1/profile/update",
						"description": "Update name and/or whatsapp_number. For profile_image use multipart/form-data."
					}
				}
			]
		},
		{
			"name": "Dashboard",
			"item": [
				{
					"name": "Dashboard",
					"request": {
						"method": "GET",
						"header": [],
						"url": "{{base_url}}/api/v1/dashboard",
						"description": "Get dashboard / progress data for the current user."
					}
				}
			]
		},
		{
			"name": "Decks (public)",
			"item": [
				{
					"name": "List decks",
					"request": {
						"auth": {
							"type": "noauth"
						},
						"method": "GET",
						"header": [],
						"url": "{{base_url}}/api/v1/decks",
						"description": "List all decks (no auth required)."
					}
				},
				{
					"name": "Get deck by slug",
					"request": {
						"auth": {
							"type": "noauth"
						},
						"method": "GET",
						"header": [],
						"url": "{{base_url}}/api/v1/decks/{{deck_slug}}",
						"description": "Get a single deck by slug (e.g. general, n5, n4)."
					}
				}
			]
		},
		{
			"name": "Review (SRS)",
			"item": [
				{
					"name": "Review queue",
					"request": {
						"method": "GET",
						"header": [],
						"url": "{{base_url}}/api/v1/review/queue?limit=50",
						"description": "Get cards due for review. Optional query: limit (1-200, default 50)."
					}
				},
				{
					"name": "Submit review",
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n  \"grade\": \"good\",\n  \"was_correct\": true,\n  \"response_time_ms\": 2500\n}"
						},
						"url": "{{base_url}}/api/v1/review/{{card_id}}",
						"description": "Submit a review for a card. grade: again|hard|good|easy. was_correct: boolean. response_time_ms optional."
					}
				}
			]
		},
		{
			"name": "Daily plan items",
			"item": [
				{
					"name": "Create daily plan item",
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n  \"tier\": \"quick\",\n  \"kind\": \"reviews_count\",\n  \"title\": \"Do 10 reviews\",\n  \"description\": \"Finish today's reviews\",\n  \"label\": \"Reviews\",\n  \"target\": 10,\n  \"due_at\": null,\n  \"status\": \"planned\"\n}"
						},
						"url": "{{base_url}}/api/v1/daily-plan/items",
						"description": "tier: quick|medium|main. kind: reviews_count|pomodoro_focus_sessions|pomodoro_focus_minutes. status: planned|in_progress|blocked|waiting_customer|done."
					}
				},
				{
					"name": "Update daily plan item",
					"request": {
						"method": "PUT",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n  \"tier\": \"medium\",\n  \"kind\": \"reviews_count\",\n  \"title\": \"Do 15 reviews\",\n  \"description\": \"Updated\",\n  \"label\": \"Reviews\",\n  \"target\": 15,\n  \"due_at\": null,\n  \"status\": \"in_progress\"\n}"
						},
						"url": "{{base_url}}/api/v1/daily-plan/items/{{item_id}}",
						"description": "Update an existing daily plan item. Use item_id variable."
					}
				},
				{
					"name": "Delete daily plan item",
					"request": {
						"method": "DELETE",
						"header": [],
						"url": "{{base_url}}/api/v1/daily-plan/items/{{item_id}}",
						"description": "Delete a daily plan item."
					}
				},
				{
					"name": "Toggle daily plan item",
					"request": {
						"method": "POST",
						"header": [],
						"url": "{{base_url}}/api/v1/daily-plan/items/{{item_id}}/toggle",
						"description": "Toggle item between done and planned."
					}
				},
				{
					"name": "Set daily plan item status",
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n  \"status\": \"done\"\n}"
						},
						"url": "{{base_url}}/api/v1/daily-plan/items/{{item_id}}/status",
						"description": "Set status: planned|in_progress|blocked|waiting_customer|done."
					}
				}
			]
		},
		{
			"name": "Readings",
			"item": [
				{
					"name": "List readings",
					"request": {
						"method": "GET",
						"header": [],
						"url": "{{base_url}}/api/v1/readings?type=article&q=&page=1",
						"description": "Query: type (article|conversation|story), q (search), pagination."
					}
				},
				{
					"name": "Create reading",
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n  \"type\": \"article\",\n  \"title\": \"Sample article\",\n  \"description\": \"Short description\",\n  \"source_url\": \"https://example.com\",\n  \"language\": \"ja\",\n  \"content\": \"Full text content here.\"\n}"
						},
						"url": "{{base_url}}/api/v1/readings",
						"description": "type: article|conversation|story. content required."
					}
				},
				{
					"name": "Get reading",
					"request": {
						"method": "GET",
						"header": [],
						"url": "{{base_url}}/api/v1/readings/{{reading_id}}",
						"description": "Get single reading with session stats."
					}
				},
				{
					"name": "Update reading",
					"request": {
						"method": "PUT",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n  \"type\": \"article\",\n  \"title\": \"Updated title\",\n  \"description\": \"Updated desc\",\n  \"source_url\": null,\n  \"language\": \"ja\",\n  \"content\": \"Updated content.\"\n}"
						},
						"url": "{{base_url}}/api/v1/readings/{{reading_id}}",
						"description": "Update a reading."
					}
				},
				{
					"name": "Delete reading",
					"request": {
						"method": "DELETE",
						"header": [],
						"url": "{{base_url}}/api/v1/readings/{{reading_id}}",
						"description": "Delete a reading."
					}
				}
			]
		},
		{
			"name": "Reading sessions",
			"item": [
				{
					"name": "Start reading session",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"if (pm.response.code === 200) {",
									"    const json = pm.response.json();",
									"    if (json.id) pm.collectionVariables.set('session_id', json.id);",
									"}"
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [],
						"url": "{{base_url}}/api/v1/readings/{{reading_id}}/sessions/start",
						"description": "Start a reading session for a reading. Can save session_id from response."
					}
				},
				{
					"name": "Stop reading session",
					"request": {
						"method": "POST",
						"header": [],
						"url": "{{base_url}}/api/v1/readings/sessions/{{session_id}}/stop",
						"description": "Stop a reading session. Use session_id from start response."
					}
				}
			]
		},
		{
			"name": "Pomodoro",
			"item": [
				{
					"name": "Start pomodoro session",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"if (pm.response.code === 200) {",
									"    const json = pm.response.json();",
									"    if (json.id) pm.collectionVariables.set('session_id', json.id);",
									"}"
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n  \"kind\": \"focus\",\n  \"planned_duration_seconds\": 1500,\n  \"cycle_index\": 1\n}"
						},
						"url": "{{base_url}}/api/v1/pomodoro/sessions/start",
						"description": "kind: focus|break. planned_duration_seconds required. cycle_index optional."
					}
				},
				{
					"name": "Complete pomodoro session",
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n  \"completed\": true,\n  \"actual_duration_seconds\": 1500\n}"
						},
						"url": "{{base_url}}/api/v1/pomodoro/sessions/{{session_id}}/complete",
						"description": "Mark session as complete. actual_duration_seconds optional."
					}
				}
			]
		},
		{
			"name": "Mnemonics",
			"item": [
				{
					"name": "Get mnemonic for card",
					"request": {
						"method": "GET",
						"header": [],
						"url": "{{base_url}}/api/v1/cards/{{card_id}}/mnemonic",
						"description": "Get user's mnemonic for a card (if any)."
					}
				},
				{
					"name": "Create mnemonic",
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n  \"content\": \"My mnemonic text here.\",\n  \"type\": \"custom\"\n}"
						},
						"url": "{{base_url}}/api/v1/cards/{{card_id}}/mnemonic",
						"description": "type: custom|keyword|story|absurd (optional, default custom)."
					}
				},
				{
					"name": "Generate mnemonics (AI)",
					"request": {
						"method": "POST",
						"header": [],
						"url": "{{base_url}}/api/v1/cards/{{card_id}}/mnemonic/generate",
						"description": "Generate mnemonic suggestions via AI (requires OpenAI config)."
					}
				},
				{
					"name": "Update mnemonic",
					"request": {
						"method": "PUT",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n  \"content\": \"Updated mnemonic content.\"\n}"
						},
						"url": "{{base_url}}/api/v1/mnemonics/{{mnemonic_id}}",
						"description": "Update a mnemonic by id."
					}
				},
				{
					"name": "Delete mnemonic",
					"request": {
						"method": "DELETE",
						"header": [],
						"url": "{{base_url}}/api/v1/mnemonics/{{mnemonic_id}}",
						"description": "Delete a mnemonic."
					}
				}
			]
		},
		{
			"name": "Cards (words)",
			"item": [
				{
					"name": "List cards",
					"request": {
						"method": "GET",
						"header": [],
						"url": "{{base_url}}/api/v1/cards?per_page=20&q=",
						"description": "Query: per_page (1-100), q (search kana/kanji/meaning)."
					}
				},
				{
					"name": "Create card",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"if (pm.response.code === 201) {",
									"    const json = pm.response.json();",
									"    if (json.id) pm.collectionVariables.set('card_id', json.id);",
									"}"
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n  \"kanji\": \"日本語\",\n  \"kana\": \"にほんご\",\n  \"meaning_id\": \"bahasa Jepang\",\n  \"meaning_en\": \"Japanese language\",\n  \"example_sentence_ja\": null,\n  \"example_sentence_id\": null,\n  \"audio_word_url\": null,\n  \"audio_sentence_url\": null,\n  \"tags\": [\"vocab\", \"n5\"]\n}"
						},
						"url": "{{base_url}}/api/v1/cards",
						"description": "kana and meaning_id required. tags: array or comma-separated string."
					}
				},
				{
					"name": "Get card",
					"request": {
						"method": "GET",
						"header": [],
						"url": "{{base_url}}/api/v1/cards/{{card_id}}",
						"description": "Get single card by id."
					}
				},
				{
					"name": "Update card",
					"request": {
						"method": "PUT",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n  \"kanji\": \"日本語\",\n  \"kana\": \"にほんご\",\n  \"meaning_id\": \"bahasa Jepang\",\n  \"meaning_en\": \"Japanese\",\n  \"example_sentence_ja\": null,\n  \"example_sentence_id\": null,\n  \"audio_word_url\": null,\n  \"audio_sentence_url\": null,\n  \"tags\": [\"vocab\"]\n}"
						},
						"url": "{{base_url}}/api/v1/cards/{{card_id}}",
						"description": "Update a card."
					}
				},
				{
					"name": "Delete card",
					"request": {
						"method": "DELETE",
						"header": [],
						"url": "{{base_url}}/api/v1/cards/{{card_id}}",
						"description": "Delete a card."
					}
				},
				{
					"name": "Similar cards",
					"request": {
						"method": "GET",
						"header": [],
						"url": "{{base_url}}/api/v1/cards/{{card_id}}/similar",
						"description": "Get cards similar to this one (by tags or meaning)."
					}
				},
				{
					"name": "Generate sentence",
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n  \"save\": true\n}"
						},
						"url": "{{base_url}}/api/v1/cards/{{card_id}}/generate-sentence",
						"description": "Generate an AI example sentence. Pass save=true to persist it in DB."
					}
				}
			]
		},
		{
			"name": "Practice Sentences",
			"item": [
				{
					"name": "Generate furigana",
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Accept",
								"value": "application/json"
							}
						],
						"url": "{{base_url}}/api/v1/practice-sentences/{{practice_sentence_id}}/furigana",
						"description": "Generate Ruby text annotations (furigana) for the sentence."
					}
				},
				{
					"name": "Generate translation",
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Accept",
								"value": "application/json"
							}
						],
						"url": "{{base_url}}/api/v1/practice-sentences/{{practice_sentence_id}}/translate?force=true",
						"description": "Generate ENG/IND translation + explanation. Use ?force=true to ignore DB cache and force regeneration."
					}
				}
			]
		},
		{
			"name": "Practice",
			"item": [
				{
					"name": "List practice sessions",
					"request": {
						"method": "GET",
						"header": [],
						"url": "{{base_url}}/api/v1/practice/sessions",
						"description": "List user's practice sessions."
					}
				},
				{
					"name": "Start practice session",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"if (pm.response.code === 201) {",
									"    const json = pm.response.json();",
									"    if (json.session && json.session.id) pm.collectionVariables.set('session_id', json.session.id);",
									"}"
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n  \"reading_id\": null,\n  \"context\": \"Short Japanese text to practice with.\",\n  \"title\": \"Practice session\"\n}"
						},
						"url": "{{base_url}}/api/v1/practice/sessions/start",
						"description": "Optional: reading_id, context, title. If reading_id provided, context/title can be omitted (from reading)."
					}
				},
				{
					"name": "Get practice session",
					"request": {
						"method": "GET",
						"header": [],
						"url": "{{base_url}}/api/v1/practice/sessions/{{session_id}}",
						"description": "Get a practice session with messages."
					}
				},
				{
					"name": "Send practice message",
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n  \"message\": \"User reply or question here.\"\n}"
						},
						"url": "{{base_url}}/api/v1/practice/sessions/{{session_id}}/message",
						"description": "Send a message in a practice conversation (AI reply returned)."
					}
				},
				{
					"name": "End practice session",
					"request": {
						"method": "POST",
						"header": [],
						"url": "{{base_url}}/api/v1/practice/sessions/{{session_id}}/end",
						"description": "End a practice session."
					}
				}
			]
		},
		{
			"name": "Dictionary",
			"item": [
				{
					"name": "Lookup word",
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							},
							{
								"key": "Accept",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n    \"word\": \"食べる\"\n}"
						},
						"url": {
							"raw": "{{base_url}}/api/v1/dictionary/lookup",
							"host": [
								"{{base_url}}"
							],
							"path": [
								"api",
								"v1",
								"dictionary",
								"lookup"
							]
						},
						"description": "Lookup a word in the dictionary (DB or AI)."
					}
				}
			]
		}
	]
}