API Reference
REST API
Base URL: /api · 所有端點回傳 JSON。價格以港幣分為單位(如 3800 = HK$38.00)。
概述
Zest 提供完整的 REST API,涵蓋菜品、訂單、桌位、訂位、設定、變體和時段。所有端點回傳 JSON 格式。
認證
受保護的端點需要 API Key。可透過以下方式傳遞:
Authorization: Bearer ***x-api-key: ***?api_key=sk-...角色
super_admin — 完整權限:管理用戶、所有菜品操作
admin — 管理菜品、管理自己的 API Key
staff — 唯讀:查看菜品、管理自己的 API Key
錯誤格式
{"error": {"code": "missing_api_key", "message": "..."}}| Status | Code | 含義 |
|---|---|---|
| 401 | missing_api_key | 未提供 API Key |
| 401 | invalid_api_key | Key 無效、格式錯誤或已過期 |
| 403 | insufficient_role | 角色權限不足 |
| 404 | not_found | 資源不存在 |
| 409 | conflict | 重複或衝突 |
| 422 | validation_error | 缺少或無效的請求體 |
| 429 | rate_limited | 請求過多 |
認證端點
/api/auth/register註冊首位用戶(super_admin)。
請求體:
{"username": "owner", "password": "password123"}回應:
{"api_key": "sk-...", "user": {"id": "...", "username": "owner", "role": "super_admin"}}錯誤: 422, 409, 403
/api/auth/login使用用戶名/密碼認證。
請求體:
{"username": "owner", "password": "password123"}回應:
{"api_key": "sk-...", "user": {"id": "...", "username": "owner", "role": "..."}}錯誤: 422, 401
/api/auth/keys列出用戶的 API Key。
回應:
Array of {id, key_prefix, name, last_used_at, created_at, expires_at}/api/auth/keys產生新的 API Key。
請求體:
{"name": "office laptop", "expires_at": "2026-12-31T23:59:59Z"}回應:
{"api_key": "sk-...", "key": {"id": "...", "key_prefix": "sk-a1b2...", "name": "office laptop"}}錯誤: 422
/api/auth/keys/:idAny (own) / super_admin (any)撤銷 API Key。
回應:
{"deleted": true}錯誤: 404, 403
管理端點
/api/admin/userssuper_admin列出所有用戶。
回應:
Array of {id, username, role, created_at}/api/admin/userssuper_admin建立新用戶。
請求體:
{"username": "staff1", "password": "pass123", "role": "staff"}錯誤: 422, 409
/api/admin/users/:idsuper_admin更新用戶。
錯誤: 404, 422, 409
/api/admin/users/:idsuper_admin刪除用戶。
錯誤: 404, 422
/api/admin/ai-fill-dishadmin+AI 生成菜品名稱。
請求體:
{"hint": "salmon teriyaki"}回應:
{name_ja, name_en, name_zh, description_ja/en/zh, category}/api/admin/upload-dish-imageadmin+上傳菜品圖片。
回應:
{"image_url": "/dishes/123456-abc.jpg"}菜品端點
/api/dishesAny列出菜品。按 sort_order 排序。
請求體:
?category=sashimi (opt) · ?time_slot_id=1 (opt)回應:
Array of {id, name_ja, name_en, name_zh, category, price_hkd, image_url, variant_groups, ...}/api/dishes/topAny按銷量取得暢銷菜品。
請求體:
?limit=4 (opt, max 50)回應:
Array of dishes with extra total_sold and revenue_hkd/api/dishes/:idAny取得單道菜品。
錯誤: 404
/api/dishesadmin+建立菜品。
請求體:
{"name_ja": "...", "name_en": "...", "name_zh": "...", "category": "sashimi", "price_hkd": 8800}錯誤: 422
/api/dishes/:idadmin+更新菜品。
錯誤: 404, 422
/api/dishes/:idadmin+刪除菜品。
回應:
{"deleted": true}錯誤: 404
分類
| Slug | 日本語 | English | 中文 |
|---|---|---|---|
| appetizer | 前菜 | Appetizer | 前菜 |
| sashimi | 刺身 | Sashimi | 刺身 |
| grilled | 焼物 | Grilled | 烤物 |
| fried | 揚物 | Fried | 炸物 |
| rice_bowl | 丼物 | Rice Bowl | 盖饭 |
| noodles | 麺類 | Noodles | 面类 |
| dessert | 甘味 | Dessert | 甜品 |
| drink | 飲物 | Drink | 饮品 |
桌位端點
/api/tablesAny列出活躍桌位。
請求體:
?qr_code=... (opt)回應:
Array of {id, label, qr_code, capacity, section, is_active, has_active_order}/api/tablesadmin+建立桌位。
請求體:
{"label": "Table 1", "capacity": 4, "section": "main"}錯誤: 422, 409
/api/tables/:idadmin+更新桌位。
錯誤: 404
/api/tables/:idadmin+刪除桌位。
錯誤: 404
訂單端點
/api/ordersAny列出訂單及明細。
請求體:
?status=... &table_id=... &offset=0 &limit=50回應:
Array of orders with items, table info, service charge, totals/api/orders/:idAny取得單筆訂單。
錯誤: 404
/api/orders從 QR 掃描下單(公開端點)。
請求體:
{"table_qr_code": "...", "items": [{"dish_id": 1, "quantity": 2}], "party_size": 4}錯誤: 422, 404, 409, 429
/api/orders/:id/items追加一輪菜品。
請求體:
{"table_qr_code": "...", "items": [{"dish_id": 3, "quantity": 1}]}錯誤: 403, 404, 409, 429
/api/orders/:idstaff+更新訂單狀態。
請求體:
{"status": "preparing|served|paid|cancelled"}錯誤: 404, 409, 422
/api/orders/:id/items/:itemIdstaff+取消菜品(軟刪除)。
錯誤: 400, 404, 409
/api/orders/streamstaff / table_qr_codeSSE 端點,用於即時訂單更新。
回應:
Events: connected, initial_order, order_created, order_updated, items_added, item_removed, keepalive訂位端點
/api/bookingsAny列出訂位。
請求體:
?date=2026-05-10 (opt)回應:
Array of {id, customer_name, party_size, booking_date, booking_time, status, table_id, ...}/api/bookings建立訂位(公開端點)。
請求體:
{"customer_name": "John", "booking_date": "2026-05-10", "booking_time": "19:00", "party_size": 4}錯誤: 422
/api/bookings/:idstaff+更新訂位。
請求體:
{"status": "confirmed|arrived|cancelled|no_show", "table_id": 1}錯誤: 404, 422
/api/bookings/:idadmin+刪除訂位。
錯誤: 404
設定端點
/api/settings取得餐廳設定。
回應:
{theme, dark_mode, service_charge_enabled, service_charge_percentage, basic_fee_enabled, basic_fee_per_person, restaurant_address, restaurant_phone}/api/settingsadmin+更新設定。
請求體:
{"service_charge_percentage": 10}錯誤: 400
時段端點
/api/time-slotsAny列出所有時段。
回應:
Array of {id, name, display_name_ja/en/zh, start_time, end_time, is_active, sort_order}/api/time-slots/currentAny取得當前活躍時段。
錯誤: 404
/api/time-slotsadmin+建立時段。
請求體:
{"name": "dinner", "start_time": "18:00", "end_time": "22:00"}錯誤: 422
/api/time-slots/:idadmin+更新時段。
錯誤: 404
/api/time-slots/:idadmin+刪除時段。
錯誤: 404, 409
變體端點
/api/admin/variant-groupsAny列出變體群組及其選項。
回應:
Array of {id, name, sort_order, options: [{id, name, price_adjustment, is_default}]}/api/admin/variant-groupsadmin+建立變體群組。
請求體:
{"name": "Temperature", "sort_order": 1}錯誤: 422
/api/admin/variant-groups/:id/optionsadmin+向變體群組新增選項。
請求體:
{"name": "Medium Rare", "price_adjustment": 0}/api/admin/dishes/:id/variantsAny取得菜品已分配的變體群組。
/api/admin/dishes/:id/variantsadmin+將變體群組分配給菜品。
請求體:
{"variant_group_id": 1, "is_required": true}錯誤: 422, 409
curl Examples
curl -X POST http://localhost:3898/api/auth/register \\ -H "Content-Type: application/json" \\ -d '{"username":"owner","password":"password123"}'curl -X POST http://localhost:3898/api/auth/login \\ -H "Content-Type: application/json" \\ -d '{"username":"owner","password":"password123"}'curl http://localhost:3898/api/dishes \\ -H "Authorization: Bearer ***"curl -X POST http://localhost:3898/api/orders \\ -H "Content-Type: application/json" \\ -d '{"table_qr_code":"a1b2c3d4-...","items":[{"dish_id":1,"quantity":2}]}'