# API Reference

Last source audit: 2026-05-12, based on git commit `8ee86a9`.

All routes are Next.js App Router route handlers under `src/app/api/**/route.ts`.

## Auth Conventions

- Bearer token: `Authorization: Bearer <token>`.
- Token creation and verification: `src/lib/session-auth.ts`.
- Authenticated user helpers:
  - `getAuthenticatedUser(request)`
  - `getAuthenticatedUserId(request)`
  - `requireAdminUser(request)`
  - `requireAdmin(request)` from `src/lib/admin-auth.ts`
- Internal generation requests use header `x-miaojing-generation-internal`, generated by `src/lib/server-api-config.ts`.

## Response Conventions

- Success responses are JSON unless the route explicitly streams/downloads a file.
- Error responses usually use `{ "error": "message" }` with an HTTP status.
- Admin-only routes return 401 when not logged in and 403 when role is not `admin` or `enterprise_admin`.

## Public/System Routes

| Method | Path | Auth | Source | Purpose |
| --- | --- | --- | --- | --- |
| GET | `/api/health` | Public | `src/app/api/health/route.ts` | Health check. |
| GET | `/api/site-stats` | Public | `src/app/api/site-stats/route.ts` | Read total visits. |
| POST | `/api/site-stats` | Public | `src/app/api/site-stats/route.ts` | Increment visits. |
| GET | `/api/site-config` | Public | `src/app/api/site-config/route.ts` | Read site config, policy Markdown, filing, membership flag. |
| PUT | `/api/site-config` | Admin | `src/app/api/site-config/route.ts` | Update site config and upload logo/favicon data URLs. |
| GET | `/api/announcements` | Public | `src/app/api/announcements/route.ts` | List announcements. |
| POST | `/api/announcements` | Admin | `src/app/api/announcements/route.ts` | Create announcement. Body: `title`, `content`, `startDate`, `endDate`, `enabled`. |
| PUT | `/api/announcements` | Admin | `src/app/api/announcements/route.ts` | Update announcement. Body includes `id` and changed fields. |
| DELETE | `/api/announcements?id=...` | Admin | `src/app/api/announcements/route.ts` | Delete announcement. |
| GET | `/api/model-config` | Public | `src/app/api/model-config/route.ts` | Read managed provider/model configuration for clients. |
| GET | `/api/style-presets` | Public | `src/app/api/style-presets/route.ts` | Returns active image style presets from `image_style_presets`, sorted by usage count. |
| GET | `/api/local-storage/[...path]` | Public by URL | `src/app/api/local-storage/[...path]/route.ts` | Serve local storage object by key. |
| GET | `/api/download?url=...&filename=...` | Public by URL | `src/app/api/download/route.ts` | Download proxy for remote, same-origin, and local-storage URLs. |

## Auth And Account Routes

| Method | Path | Auth | Source | Request | Response |
| --- | --- | --- | --- | --- | --- |
| POST | `/api/auth/login` | Public | `src/app/api/auth/login/route.ts` | `account` or `email` or `phone`, `password`, optional `adminOnly` | User profile data and session token. |
| POST | `/api/auth/register` | Public | `src/app/api/auth/register/route.ts` | `email`, `password`, `nickname` as login username, `phone`, `inviteCode`, `emailCode`, `acceptedTerms` | Created profile/session flow. New normal users receive a random Chinese display nickname and default 3D cartoon avatar. |
| GET | `/api/auth/admin-exists` | Public | `src/app/api/auth/admin-exists/route.ts` | None | Whether an admin profile exists. |
| POST | `/api/auth/test-api` | Public/auth context depends caller | `src/app/api/auth/test-api/route.ts` | Provider/API config | Tests upstream API. |
| POST | `/api/auth/fetch-models` | Public/auth context depends caller | `src/app/api/auth/fetch-models/route.ts` | Endpoint/API key | Fetch model list from provider. |
| GET | `/api/profile` | User | `src/app/api/profile/route.ts` | None | `{ profile }`. |
| PUT | `/api/profile` | User | `src/app/api/profile/route.ts` | `email`, `username`, `displayNickname`/`nickname`, `phone`, `avatarUrl`, password fields | Updated profile. `username` remains usable for login; display nickname is returned as `nickname` for UI and gallery display. |
| PUT | `/api/profile/theme` | User | `src/app/api/profile/theme/route.ts` | `theme` | `{ success, preferred_theme }`. |
| GET | `/api/user-api-keys` | User | `src/app/api/user-api-keys/route.ts` | None | `{ keys }`, with previews only. |
| POST | `/api/user-api-keys` | User | `src/app/api/user-api-keys/route.ts` | Single key or `{ keys: [...] }`; fields `provider`, `supplierName`, `apiUrl`, `modelName`, `apiKey`, `type`, `isActive` | Saved keys. |
| PUT | `/api/user-api-keys` | User | `src/app/api/user-api-keys/route.ts` | Same as POST | Saved keys. |
| DELETE | `/api/user-api-keys?id=...` | User | `src/app/api/user-api-keys/route.ts` | Query `id` | `{ success: true }`. |

## Email Routes

| Method | Path | Auth | Source | Purpose |
| --- | --- | --- | --- | --- |
| POST | `/api/email/send-register-code` | Public | `src/app/api/email/send-register-code/route.ts` | Send registration verification code. |
| POST | `/api/email/send-reset-code` | Public | `src/app/api/email/send-reset-code/route.ts` | Send password reset code. |
| POST | `/api/email/reset-password` | Public | `src/app/api/email/reset-password/route.ts` | Reset password with verification code. |
| POST | `/api/email/send-profile-code` | User | `src/app/api/email/send-profile-code/route.ts` | Send profile email-binding code. |
| POST | `/api/email/verify-profile` | User | `src/app/api/email/verify-profile/route.ts` | Verify profile email code. |
| POST | `/api/email/send-notification` | Internal/admin-oriented | `src/app/api/email/send-notification/route.ts` | Send notification email. |

All email sends route through `src/lib/email-service.ts`, which renders HTML and plain-text multipart messages and sends them via the configured SMTP server. Keep MIME body encoding standards-compliant: base64 body parts must be folded to safe line lengths and both text/plain and text/html parts should be non-empty, otherwise SMTP can accept the message while some mailbox clients render a blank email.

## Generation Routes

| Method | Path | Auth | Source | Request | Response/Side Effects |
| --- | --- | --- | --- | --- | --- |
| POST | `/api/generation-jobs` | User | `src/app/api/generation-jobs/route.ts` | `{ type: "image"|"video", payload: {...} }` | Inserts `generation_jobs`, starts worker, increments selected image `styleLabel` usage, returns `202` with `jobId`, `status`, `estimateSeconds`, `eta`. |
| GET | `/api/generation-jobs/[id]` | User/admin | `src/app/api/generation-jobs/[id]/route.ts` | Path UUID | Job status/result/error/progress. Owner or admin only. |
| POST | `/api/generate/image` | Trusted internal or resolved user/system API context | `src/app/api/generate/image/route.ts` | Image generation payload; supports prompt, negative prompt, reference images, model/system/custom API config, aspect/size/resolution/count/quality. | Calls SDK or OpenAI/New API-compatible endpoint, persists result to local storage, updates job progress when headers include job ID. |
| POST | `/api/generate/video` | Trusted internal or resolved user/system API context | `src/app/api/generate/video/route.ts` | Video generation payload; supports prompt, reference image, model/system/custom API config, ratio/duration/fps-like params. | Calls SDK or custom endpoint, persists media to local storage. |
| POST | `/api/generate/reverse-prompt` | Uses supplied/resolved API config | `src/app/api/generate/reverse-prompt/route.ts` | `image`, `outputMode`, `language`, optional `customApiConfig`/system/custom IDs | Returns prompt fields and may persist reference image. |
| POST | `/api/generate/suggest-prompt` | Uses supplied/resolved API config | `src/app/api/generate/suggest-prompt/route.ts` | `prompt`, optional `customApiConfig`, `systemPrefix` | Returns optimized `prompt` and optional `negativePrompt`. |

Important generation helpers:

- `src/lib/generation-job-client.ts`: frontend create/poll helper.
- `src/lib/generation-job-worker.ts`: queued job processor.
- `src/lib/generation-job-runner.ts`: internal call into generate routes.
- `src/lib/generation-job-estimates.ts`: ETA/progress schema and estimates.
- `src/lib/server-api-config.ts`: resolves `customApiKeyId` and `systemApiId`.
- `src/lib/custom-api-fetch.ts`: upstream request/retry/error parsing.

## Creation History And Gallery

| Method | Path | Auth | Source | Request | Response/Side Effects |
| --- | --- | --- | --- | --- | --- |
| GET | `/api/creation-history` | User | `src/app/api/creation-history/route.ts` | None | Latest 300 completed user works as `records`. |
| POST | `/api/creation-history` | User | `src/app/api/creation-history/route.ts` | Single record or `{ records: [...] }` | Inserts/deduplicates completed works into `works`. |
| DELETE | `/api/creation-history?id=...` | User | `src/app/api/creation-history/route.ts` | Optional `id`; omit to delete all user history | Deletes user's private history rows by `id` and `user_id`. Creation detail deletion waits for this server delete before refreshing local history. |
| GET | `/api/gallery` | Public | `src/app/api/gallery/route.ts` | Query `type=image|video`, `limit`, `offset`, `sort=newest|popular`, `q`/`search` | Public completed works and total. |
| DELETE | `/api/gallery` | Admin | `src/app/api/gallery/route.ts` | Query `id` or body `{ ids: [...] }` | Unpublishes up to 100 works by setting `is_public=false`. |
| POST | `/api/gallery/publish` | User | `src/app/api/gallery/publish/route.ts` | Work metadata, `resultUrl`, optional thumbnail/reference/model fields | Copies media into gallery folders and inserts public completed work. |

## Canvas Routes

The public `/canvas` page is currently disabled and returns 404. These authenticated API routes remain in source as legacy canvas persistence endpoints; do not surface them in UI unless the canvas feature is explicitly re-enabled.

| Method | Path | Auth | Source | Request | Response |
| --- | --- | --- | --- | --- | --- |
| GET | `/api/canvas/projects` | User | `src/app/api/canvas/projects/route.ts` | None | `{ projects }`. |
| POST | `/api/canvas/projects` | User | `src/app/api/canvas/projects/route.ts` | Optional `title` | Created `{ project }`. |
| GET | `/api/canvas/projects/[id]` | User | `src/app/api/canvas/projects/[id]/route.ts` | Project ID | `{ project }` or 404. |
| PUT | `/api/canvas/projects/[id]` | User | `src/app/api/canvas/projects/[id]/route.ts` | `title`, `state` | Normalizes state and returns `{ project }`. |
| DELETE | `/api/canvas/projects/[id]` | User | `src/app/api/canvas/projects/[id]/route.ts` | Project ID | `{ ok: true }`. |

## Admin Routes

All routes in this section require admin unless noted.

| Method | Path | Source | Purpose |
| --- | --- | --- | --- |
| GET | `/api/admin/dashboard` | `src/app/api/admin/dashboard/route.ts` | Console dashboard aggregate stats and recent activity. |
| GET | `/api/admin/stats` | `src/app/api/admin/stats/route.ts` | Additional admin stats. |
| GET/PUT/DELETE | `/api/admin/users` | `src/app/api/admin/users/route.ts` | List/update/delete users. |
| POST | `/api/admin/clear-users` | `src/app/api/admin/clear-users/route.ts` | Dangerous user cleanup controlled by env switch. |
| GET/POST/PUT | `/api/admin/orders` | `src/app/api/admin/orders/route.ts` | List/create/update orders. |
| GET/PUT | `/api/admin/payment-methods` | `src/app/api/admin/payment-methods/route.ts` | Payment config. |
| GET/POST/PUT/DELETE | `/api/admin/providers` | `src/app/api/admin/providers/route.ts` | Provider registry CRUD. GET is currently not guarded in source; mutations require admin. |
| GET/POST/PUT/DELETE | `/api/admin/system-apis` | `src/app/api/admin/system-apis/route.ts` | System API config CRUD with encrypted keys and pricing metadata. |
| GET/POST/PUT/DELETE | `/api/admin/model-recommendations` | `src/app/api/admin/model-recommendations/route.ts` | Managed model recommendations. |
| GET/DELETE | `/api/admin/generation-jobs` | `src/app/api/admin/generation-jobs/route.ts` | Admin task listing and deletion. |
| GET | `/api/admin/data-export` | `src/app/api/admin/data-export/route.ts` | Export business data plus `_media` entries for local-storage assets referenced by works and site config. `_meta` reports media count/bytes/missing/skipped. |
| POST | `/api/admin/data-import` | `src/app/api/admin/data-import/route.ts` | Import business data. Accepts optional `_media`; restores media to sha-based keys, remaps users/custom API keys/works, imports in a transaction with per-row savepoints, and dedupes works by URL/source URL/media SHA. |
| GET/PUT/POST | `/api/admin/email-settings` | `src/app/api/admin/email-settings/route.ts` | Read/update/test email settings. |
| GET | `/api/admin/email-recipients` | `src/app/api/admin/email-recipients/route.ts` | Email recipient list. |
| POST | `/api/admin/send-email` | `src/app/api/admin/send-email/route.ts` | Send admin email. |
| GET/POST | `/api/admin/upgrade` | `src/app/api/admin/upgrade/route.ts` | Read upgrade runtime/status/history; upload/start dry run or upgrade package. New deployable work should be classified against this path: static/public asset-only payloads may be hot-update candidates after preflight, while source/API/server/dependency/schema/env/runtime/script changes are cold-update candidates. |

## Persistence Tables Mentioned By APIs

Primary SQL tables touched directly in API routes include:

- `profiles`
- `auth.users`
- `works`
- `credit_transactions`
- `orders`
- `user_api_keys`
- `site_config`
- `site_stats`
- `announcements`
- `generation_jobs`
- `api_providers`
- `system_api_configs`
- `platform_logs`

`src/storage/database/shared/schema.ts` contains a Drizzle snapshot of core tables, while several runtime APIs add compatibility columns/tables with `CREATE TABLE IF NOT EXISTS` or `ALTER TABLE ... ADD COLUMN IF NOT EXISTS`.

Profile naming convention: `profiles.nickname` is the stable login username; `profiles.display_nickname` is the public nickname shown in navbar/gallery/profile UI. APIs return `username` plus `nickname`/`display_nickname` so older clients can keep reading `nickname` as the display name.
