Skip to main content
All of the app’s server-side logic lives in Next.js API routes under app/api/. The frontend calls model providers through these routes. The server injects keys, chooses the API URL, and adjusts request parameters.
These routes are internal to the app and are mainly used by the frontend. Their parameters may change between versions. If you call them from another program, treat the source code in the repository as the source of truth.

Shared conventions

Request headers

Shared parameters

All model-related routes accept these parameters:
The request body must not include apiUrl. The server returns 400 with the message 「客户端不再支持自定义 API URL,请在服务器环境变量中配置上游端点。」 (shown in the English interface as “Custom API URLs must be configured in the server environment.”). You can only set API URLs through DEEPSEEK_API_URL or GEMINI_API_URL.

Access verification

When CODE is configured, every route except /api/auth and /api/umami/script requires a valid ja_session cookie. Otherwise it returns:

Error format

On error, routes return the appropriate HTTP status code and an error in a uniform format:
  • message is always the original Simplified Chinese text and does not depend on X-App-Locale. The frontend translates known errors into the interface language before showing them.
  • Raw error messages from the model provider are forwarded as-is, and the frontend doesn’t translate them.
  • When the model provider takes longer than 60 seconds, non-streaming requests return 504 with 「上游接口请求超时,请稍后重试。」

Streaming responses

When streaming output is on, routes forward the upstream OpenAI-compatible Server-Sent Events stream directly, with a Content-Type of text/event-stream. When it’s off, they return the upstream’s complete JSON response. If streaming output produces no new data for 90 seconds, the server sends an error event in the stream and then closes the connection:

Routes

POST /api/analyze

The model returns structured JSON in the form {"tokens": [{"word", "pos", "furigana"}]}.

POST /api/translate

X-App-Locale determines the translation language. The translation keeps the paragraph and line-break structure of the original.

POST /api/word-detail

Word details return the fields chineseTranslation, dictionaryForm, explanation, conjugation, example, exampleTranslation, pos, and furigana. Phrase details also return category and breakdown.

POST /api/image-to-text

POST /api/chat

The server prepends a Japanese learning assistant system prompt to the message list.

POST /api/tts

On success, it returns Base64-encoded audio:

GET /api/daily-sentence

Returns today’s sentence of the day (Japan time), including date, text, tokens, and translation in four languages. The response’s Cache-Control expires at midnight Japan time. If the server has no usable key or generation fails, it returns 503, and the frontend falls back to a built-in backup sentence.

/api/auth

  • GET: Returns { "requiresAuth": boolean, "authenticated": boolean }.
  • POST: The request body is { "password": "..." }. If the password is correct, it returns { "success": true } and sets the session cookie. Otherwise it returns 401.