# img-infinite-canvas API Base path: `/api` ## Health `GET /api/health` ```json { "status": "ok", "service": "img_infinite_canvas-api", "time": "2026-07-04T03:20:00Z" } ``` ## Dashboard `GET /api/dashboard` Returns credits, quick actions, recent projects, and inspiration items for the Moteva-style home screen. ## Auth Global mode is enabled in `etc/config.yaml`. Email verification codes are stored through the cache abstraction for 10 minutes; with `Cache.Driver: redis`, the code only lives in Redis until TTL or successful consumption. SMTP is configured under `Auth.Email`: ```yaml Auth: Turnstile: Enabled: true SiteKey: 1x00000000000000000000AA SecretKey: 1x0000000000000000000000000000000AA SecretKeyEnv: TURNSTILE_SECRET_KEY SiteVerifyURL: https://challenges.cloudflare.com/turnstile/v0/siteverify TimeoutSeconds: 5 Email: Driver: smtp # none|smtp Host: smtp.example.com Port: 587 Username: user@example.com Password: app-password FromName: hello FromEmail: hello@example.com BrandName: Moteva UseTLS: false StartTLS: true TimeoutSeconds: 10 ``` When `Auth.Turnstile.Enabled` is `false`, `/api/auth/options` returns `turnstile.enabled=false`; the frontend hides the Cloudflare Turnstile widget and sends email-code requests without a Turnstile token. When enabled, the frontend must submit `turnstileToken`, and the API validates it before creating or emailing a verification code. `POST /api/auth/global/email-code` ```json { "email": "user@example.com", "turnstileToken": "client-widget-token" } ``` Development response includes an email preview so the frontend can render the same verification flow without a mail provider: ```json { "target": "user@example.com", "expiresIn": 600, "devCode": "263081", "email": { "fromName": "hello", "fromEmail": "hello@auth.moteva.local", "toEmail": "user@example.com", "subject": "Welcome to Moteva!", "code": "263081" } } ``` `POST /api/auth/global/email-login` ```json { "email": "user@example.com", "code": "263081" } ``` Returns an authenticated session with `accessToken`, `refreshToken`, and the user profile. Project creation, generation, upload, save, and deletion require this login token. `POST /api/auth/global/google-login` ```json { "idToken": "google-id-token" } ``` `POST /api/auth/china/wechat-login` First QR callback: ```json { "code": "wechat-oauth-code", "state": "signed-state" } ``` If the WeChat identity is already bound to a phone number, the response is authenticated. If not, the response has `status: "phone_binding_required"` and a short-lived `bindingToken`. Phone binding step: ```json { "bindingToken": "signed-binding-token", "phone": "13800138000", "countryCode": "+86", "smsCode": "123456" } ``` After binding succeeds, later QR logins use only `code` and `state`. ## Account All account endpoints require the bearer token returned by login. Account profile state is owned by the auth module and persisted in PostgreSQL or the configured in-memory store. `GET /api/account/profile` Returns the current authenticated user. `PATCH /api/account/profile` ```json { "name": "Xu Liang", "avatarUrl": "https://cdn.example.com/avatar.webp" } ``` Updates account display name and avatar URL. The frontend uploads avatar files through `/api/assets/upload-url` first, then stores the returned public URL on the profile. `GET /api/account/devices` Returns the current local web session. This version does not maintain a multi-device session registry yet, so the current device is read-only and cannot be removed. `DELETE /api/account/devices` Removes non-current devices when a future server-side session registry exists. In the current local-only implementation, it returns `{"removed": 0}`. `POST /api/account/logout` Records a logout request server-side and returns `{"removed": 0}`. The frontend then clears its local access token and cookies. ## Projects `GET /api/projects` Returns all project summaries, sorted by `updatedAt` descending. `POST /api/projects` ```json { "title": "still day 官网", "prompt": "为 still day 品牌服装独立站设计官网视觉方向", "imageModel": "gpt-image-2", "imageSize": "1024x1024", "enableWebSearch": true } ``` `enableWebSearch` only opens the web-search capability. The agent model still decides per request whether search is actually needed; if it is not needed, no web-search step is recorded. When search runs, result titles, URLs, snippets, and cleaned page-content excerpts are stored for the agent. `GET /api/projects/:id` Returns the full project, including viewport, nodes, connections, and agent messages. `PATCH /api/projects/:id/title` ```json { "title": "夏季活动主视觉" } ``` Renames the infinite canvas project and updates `updatedAt`. `DELETE /api/projects/:id` Deletes the project record. PostgreSQL cascades canvas nodes, chat messages, history, and connections; after the database delete succeeds, image assets referenced by the canvas and generated-file history are queued for asynchronous OSS deletion. ## Agent Chat `POST /api/projects/:id/agent/chat` ```json { "messages": [ { "role": "user", "contents": [{ "type": "text", "text": "继续优化首页首屏,但保留品牌色" }] } ], "enableWebSearch": false, "imageModel": "gpt-image-2", "imageSize": "1024x1024", "mode": "design" } ``` The harness builds short memory from the current turn, recent messages, and visible canvas state, and long memory from durable project decisions, prior artifacts, and previous research records with page-content excerpts. Image titles and assistant language are generated from the request context instead of fixed model labels. ## Generate `POST /api/projects/:id/generate` ```json { "prompt": "继续扩展产品详情页模块", "mode": "design" } ``` Returns the updated project, the assistant message, and generated nodes. The generation path uses the configured design agent runner. The default is the `sky-valley/pi` Go agent adapter, with local desktop/MCP agent behavior disabled. ## Chat History Replay `GET /api/projects/:id/history` Returns replayable assistant/user chat history for the project. ```json { "projectId": "project-id", "messages": [] } ``` ## Save Canvas `PATCH /api/projects/:id/canvas` ```json { "viewport": { "x": 420, "y": 260, "k": 0.72 }, "nodes": [], "connections": [] } ``` Saves canvas layout changes. The frontend uses this after dragging or zooming. When a canvas image node disappears from the saved node list, its backing OSS asset is queued for asynchronous deletion after the canvas save succeeds. ## Image Asset Upload `POST /api/assets/upload-url` ```json { "fileName": "reference.png", "contentType": "image/png", "size": 123456 } ``` Returns a signed upload URL for the configured storage backend. Supported drivers: - `memory` - `minio` - `s3` / `aws` - `r2` - `aliyun` ## Errors JSON error response: ```json { "error": "project not found", "code": 404 } ``` Common status codes: - `400`: invalid input - `404`: project not found - `500`: internal server error