メトリクス (Metrics/Alerts)
ダッシュボード指標・アラート。
GET/api/metrics/overview公開live 200
Headline KPI cards (revenue forecast, MRR, pipeline, kitting count, gross margin, recurring customers) with display strings byte-matched to the inline demo plus counts derived from live shared collections.
レスポンス例
{"ok":true,"month":"令和8年7月度","revenueForecast":{"display":"¥1.86","unit":"M","total":1860000,"oneTime":930000,"recurring":930000,"deltaPct":12.4},"mrr":{"display":"¥930","unit":"K","amount":930000,"projected":1400000,"invoiceRecurring":550},"pipeline":{"display":"¥6.4","unit":"M","amount":6400000,"deals":3},"kittingMonth":{"display":"412","unit":"台","count":412,"jobs":N,"shipments":N},"grossMargin":{"display":"54.2","unit":"%","bar":54,"pct":54.2},"recurringCustomers":{"display":"2","unit":"社","active":N,"proposed":N,"rows":[{"label":"北斗商事(500台・Intune)","amount":"¥380K/月"}]},"aggregates":{"customers":N,"jobs":N,"shipments":N,"invoices":N}}
GET/api/revenue/mix公開live 200
12-month revenue-mix series (months labels, recurring, onetime 万円 arrays) for #revChart; optional ?months=N trims to last N points.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
months | query | integer | | Return only the last N points. Must be 1..120 or a 400 is returned. Default = full 12-point series. |
レスポンス例
{"ok":true,"months":["25/8","25/9","25/10","25/11","25/12","26/1","26/2","26/3","26/4","26/5","26/6","26/7"],"recurring":[38,40,42,46,46,48,50,50,93,93,140,140],"onetime":[22,65,18,120,34,52,88,93,318,282,60,72]}
GET/api/ops/today公開live 200
Today's operation rows (#todayList): id/time/chip/chipLabel/title/detail/status/statusColor, clipped to length limits.
レスポンス例
{"ok":true,"ops":[{"id":"op-001","time":"09:30","chip":"c-cyan","chipLabel":"作業","title":"北斗商事 交換12台 再キッティング(Intune再登録)","detail":"担当:佐々木 | Zone A | チェックリスト 8/12 完了","status":"進行中","statusColor":"var(--cyan)"}]}
GET/api/alerts公開live 200
Alert list (#alertList) with per-alert action (label/danger/toast) plus lateCount = number of unacked late alerts.
レスポンス例
{"ok":true,"alerts":[{"id":"alert-001","label":"出荷漏れ","late":true,"ack":false,"chip":"c-red","chipLabel":"重大","what":"北斗商事 交換2台 — 予定 07/10 を超過","detail":"...","action":{"label":"対応","danger":true,"toast":"本日出荷便に組込みました…(デモ)"}}],"lateCount":1}
POST/api/alert/:id/ack公開
Mark one alert acknowledged (sets ack=true, acked=timestamp) and returns the updated alert.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
id | path | string | ○ | Alert id from metrics-alerts seed, e.g. 'alert-001'. 404 {ok:false,error:'alert not found'} if unknown. |
レスポンス例
{"ok":true,"alert":{"id":"alert-001","label":"出荷漏れ","ack":true,"acked":1710000000000,...}} 端末台帳 (Devices)
IMEI単位の端末台帳 CRUD・検索・一括操作。
GET/api/devices公開live 200
List all devices in the ledger collection (seeded with 178 mulberry(42)-generated records keyed by imei).
レスポンス例
{"ok":true,"devices":[{"imei":"356247446539346","serial":"F2LXD73EB4","asset":"HK-26-1001","model":"iPhone 15","maker":"Apple","cust":"北斗商事","mdm":"Intune","status":"保管中","chip":"c-blue",...}],"count":178}
POST/api/device公開
Create one device from partial input; generates a fresh unique imei if absent, fills defaults via makeDevice.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
imei | body | string | | Device IMEI (max 40 chars). If omitted, a fresh 35+13-digit imei is generated. |
model | body | string | | Device model (max 60), default 'iPhone 16'. iPad-* switches OS defaults. |
cust | body | string | | Customer (max 60), default '社内検証機'. |
status | body | string | | Status (max 20), default '入荷待ち'; sets chip color via chipFor. |
mdm | body | string | | MDM platform (max 40), default 'Intune'. |
serial | body | string | | Serial (max 40); defaulted from model prefix + padded index. |
asset | body | string | | Asset tag (max 40), default 'HK-26-<n>'. |
bat | body | number | | Battery %, default 100 (passed through, not clipped). |
note | body | string | | Free note (max 300). |
リクエスト
{"imei?":"str","model?":"str","cust?":"str","status?":"str","mdm?":"str","serial?":"str","asset?":"str","bat?":100,"...other device fields":"str"}レスポンス例
{"ok":true,"device":{"imei":"35...","model":"iPhone 16","cust":"社内検証機","status":"入荷待ち","chip":"c-gray",...}}
POST/api/devices/bulk公開
Create N devices from {model,cust,mdm,status,qty}; returns the created[] array.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
qty | body | number | ○ | Count to create; clamped to 1..1000. Missing/0 -> 400. |
model | body | string | | Model applied to all created devices. |
cust | body | string | | Customer applied to all created devices. |
mdm | body | string | | MDM applied to all created devices. |
status | body | string | | Status applied to all created devices. |
リクエスト
{"qty":5,"model?":"iPhone 16","cust?":"北斗商事","mdm?":"Intune","status?":"保管中"}レスポンス例
{"ok":true,"created":[{"imei":"35...","model":"iPhone 16",...}],"count":5}
POST/api/device/:imei公開
Update fields of an existing device by imei; imei key is immutable, bat passed raw, other fields clipped, chip recomputed when status changes.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
imei | path | string | ○ | IMEI of the device to update (e.g. seed value 356247446539346). |
status | body | string | | New status; triggers chip color recompute via chipFor. |
bat | body | number | | Battery %, assigned raw (not clipped). |
note | body | string | | Note (clipped to 300); all other string fields clipped to 120. |
リクエスト
{"status?":"作業中","loc?":"B-05","user?":"佐藤 健","bat?":88,"note?":"str"}レスポンス例
{"ok":true,"device":{"imei":"356247446539346","status":"作業中","chip":"c-cyan",...}}
POST/api/device/:imei/delete公開
Remove one device by imei from the collection.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
imei | path | string | ○ | IMEI of the device to delete (e.g. seed value 356247446539346). |
レスポンス例
{"ok":true,"imei":"356247446539346"} ヘルプデスク (Tickets)
サポートチケットと対応履歴。
GET/api/tickets公開live 200
List all support tickets from the tickets collection (seeded with 6 demo tickets TK-0667..TK-0672).
レスポンス例
{"ok":true,"tickets":[{"id":"TK-0672","cust":"北斗商事","kind":"紛失","subject":"営業車内で紛失 → 位置特定&リモートワイプ要請","owner":"佐々木","sla":"1h 12m","status":"対応中"}]}
POST/api/ticket公開
Create a new ticket; auto-assigns id TK-0<next num> (starts at 673) and created timestamp, clips input fields.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
cust | body | string | | Customer name (alias: customer); default '—', clipped to 120. |
kind | body | string | | Ticket type; default '問合せ', clipped to 60. |
subject | body | string | | Subject text; default '', clipped to 300. |
owner | body | string | | Assigned owner; default '—', clipped to 60. |
sla | body | string | | SLA label; default '4h 00m', clipped to 60. |
status | body | string | | Status; default '受付', clipped to 40. |
priority | body | string | | Priority; default '', clipped to 40. |
リクエスト
{"cust":"string","kind":"string","subject":"string","owner":"string","sla":"string","status":"string","priority":"string"}レスポンス例
{"ok":true,"ticket":{"id":"TK-0673","cust":"—","kind":"問合せ","subject":"","owner":"—","sla":"4h 00m","status":"受付","priority":"","created":1700000000000}}
POST/api/ticket/:id公開
Update an existing ticket's status/owner/sla/subject/cust/kind/priority (only provided non-null fields).
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
id | path | string | ○ | Ticket id, e.g. TK-0672. |
status | body | string | | New status, clipped to 40. |
owner | body | string | | New owner, clipped to 60. |
sla | body | string | | New SLA label, clipped to 60. |
subject | body | string | | New subject, clipped to 300. |
cust | body | string | | New customer, clipped to 120. |
kind | body | string | | New kind, clipped to 60. |
priority | body | string | | New priority, clipped to 40. |
リクエスト
{"status":"string","owner":"string","sla":"string","subject":"string","cust":"string","kind":"string","priority":"string"}レスポンス例
{"ok":true,"ticket":{"id":"TK-0672","status":"解決",...}}
POST/api/ticket/:id/delete公開
Delete a ticket and its associated messages.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
id | path | string | ○ | Ticket id to delete, e.g. TK-0672. |
レスポンス例
{"ok":true}
GET/api/ticket/:id/messages公開live 200
List all messages for a given ticket (empty array if none recorded).
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
id | path | string | ○ | Ticket id, e.g. TK-0672. |
レスポンス例
{"ok":true,"messages":[]}
POST/api/ticket/:id/message公開
Append a message {from,text} to a ticket's message list; assigns msg id and timestamp.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
id | path | string | ○ | Ticket id, e.g. TK-0672. |
from | body | string | | Sender label; default '—', clipped to 60. |
text | body | string | ○ | Message body, clipped to 2000; required (400 if empty). |
リクエスト
{"from":"string","text":"string (required)"}レスポンス例
{"ok":true,"message":{"id":"msg-xxxx","from":"田中","text":"...","ts":1700000000000}} 顧客管理 (Customers)
顧客アカウント・更新・商談。
GET/api/customers公開live 200
List all customer accounts (id, name, industry, mdm, monthly, devices, since, status, note, renew).
レスポンス例
{"ok":true,"customers":[{"id":"cust-mrv8frxlg","key":"hokuto","name":"北斗商事","industry":"大手商社 | 500台(iPhone)","mdm":"Intune(Clomo→移行済)","monthly":"¥380,000","devices":"500 台","since":"2025/04","status":"運用中","statusChip":"c-green","note":"豊島倉庫 専用エリア ¥45K/月","renew":{"date":"2027-03-31",...}}]}
POST/api/customer公開
Create a new customer account; requires name; returns generated id and full record.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
name | body | string | ○ | Account name (required; 400 if missing) |
industry | body | string | | Industry / device summary line |
mdm | body | string | | MDM platform |
monthly | body | string | | Monthly fee (default '—') |
devices | body | string | | Device count (default '—') |
since | body | string | | Start month (default '—') |
status | body | string | | Status label |
statusChip | body | string | | Status chip class (default 'c-gray') |
note | body | string | | Free-text note |
key | body | string | | Short account key |
renew | body | object | | Renewal/deal object {date,dateLabel,year,kind,kindChip,what,detail,confidence,confColor} or null |
リクエスト
{"name":"...","industry":"...","mdm":"...","monthly":"...","devices":"...","since":"...","status":"...","statusChip":"...","note":"...","key":"...","renew":{...}|null}レスポンス例
{"ok":true,"id":"cust-xxxx","customer":{"id":"cust-xxxx","name":"...","industry":"","mdm":"","monthly":"—","devices":"—","since":"—","status":"","statusChip":"c-gray","note":"","renew":null}}
POST/api/customer/:id公開
Update fields of an existing customer by id; 404 if id not found.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
id | path | string | ○ | Customer id (e.g. cust-mrv8frxlg) |
name | body | string | | Any of the shape() string fields to update |
renew | body | object | | Renewal object or null to overwrite renew |
リクエスト
{"name":"...","industry":"...","note":"...","renew":{...}|null, ...any shape fields}レスポンス例
{"ok":true,"customer":{"id":"cust-mrv8frxlg","name":"...",...}}
POST/api/customer/:id/delete公開
Delete a customer by id; 404 if not present.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
id | path | string | ○ | Customer id to delete |
レスポンス例
{"ok":true,"id":"cust-mrv8frxlg"}
GET/api/renewals公開live 200
Renewal/deal calendar derived from customers with a renew.date; sorted ascending by date.
レスポンス例
{"ok":true,"renewals":[{"id":"ren-cust-mrv8frxli","customerId":"cust-mrv8frxli","customer":"科研製薬","date":"2026-08-31","dateLabel":"08/31","year":"2026","kind":"商談","kindChip":"c-orange","what":"最終見積回答期限","detail":"...","confidence":"確度 80%","confColor":"orange"}]} 見積 (Quote)
見積の作成・改訂・PDF元データ。
GET/api/quote/catalog公開live 200
Returns the constant INITIAL/RUNNING line-item catalog master (mirrors app.html).
レスポンス例
{"ok":true,"catalog":{"initial":[{"n":"プロジェクト管理費","q":1,"p":300000,"d":"..."}, ...],"running":[{"n":"サービス管理・月次報告","q":1,"p":125000,"d":"..."}, ...]}}
GET/api/quotes公開live 200
Lists all saved quotes, each augmented with a computed totals snapshot.
レスポンス例
{"ok":true,"quotes":[{"id":"Q-KAKEN-001","cust":"科研製薬 御中","pattern":"A","costRate":45,"ini":[...],"run":[...],"signId":null,"totals":{"ini":...,"iniTax":...,"iniTotal":...,"run":...,"arr":...,"y1":...}}]}
GET/api/quote/:id公開live 200
Returns one saved quote by id with computed totals, or 404 if not found.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
id | path | string | ○ | Quote id, e.g. 'Q-KAKEN-001' |
レスポンス例
{"ok":true,"quote":{"id":"Q-KAKEN-001","cust":"科研製薬 御中","pattern":"A","costRate":45,"ini":[...],"run":[...],"signId":null,"totals":{...}}}
POST/api/quote公開
Saves a new quote with a generated id (Q-...), normalizing line items and totals.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
cust | body | string | | Customer name (clipped 200 chars, defaults '御中') |
pattern | body | string | | 'A' or 'B' (defaults 'A') |
costRate | body | number | | Cost rate percent (defaults 45) |
ini | body | array | | Initial line items [{n,q,p,d}] |
run | body | array | | Running line items [{n,q,p,d}] |
signId | body | string | | Optional linked sign id (clipped 120 chars) |
リクエスト
{"cust":"...","pattern":"A","costRate":45,"ini":[{"n":"...","q":1,"p":100,"d":"..."}],"run":[...],"signId":null}レスポンス例
{"ok":true,"quote":{"id":"Q-...","cust":"...",...,"totals":{...}}}
POST/api/quote/:id公開
Updates an existing quote in place (patch semantics), or 404 if not found.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
id | path | string | ○ | Quote id to update |
cust | body | string | | Updated customer name |
pattern | body | string | | 'A' or 'B' |
costRate | body | number | | Cost rate; falls back to current if 0/invalid |
ini | body | array | | Initial line items to replace |
run | body | array | | Running line items to replace |
signId | body | string | | Sign id to link (or null to clear) |
リクエスト
{"signId":"S-123"} (any subset of: cust,pattern,costRate,ini,run,signId)レスポンス例
{"ok":true,"quote":{"id":"Q-KAKEN-001",...,"updatedAt":...,"totals":{...}}} 請求 (Invoices/Billing)
請求書・売上サマリ。
GET/api/invoices公開live 200
List all invoices sorted newest-id first (descending localeCompare on id).
レスポンス例
{"ok":true,"invoices":[{"id":"INV-2607-004","cust":"三峰精機","month":"2607","desc":"新入社員向けキッティング 8台+送料","amount":19800,"due":"08/15","status":"draft","recurring":false}],"count":5}
POST/api/invoice公開
Create an invoice; auto-generates sequential id (INV-YYMM-NNN) unless a fresh INV- id is supplied.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
cust | body | string | ○ | Customer name, trimmed, clipped to 120 chars; 400 if empty. |
amount | body | number | ○ | Invoice amount; must be finite and >= 0, rounded; 400 if invalid. |
status | body | string | | One of draft|issued|paid|overdue; defaults to draft if omitted/invalid. |
month | body | string | | Billing month YYMM (clip 8); defaults to current YYMM. |
desc | body | string | | Line-item description, clip 300. |
due | body | string | | Due date string, clip 20. |
id | body | string | | Optional custom id; used only if matches /^INV-/ and not already present, else auto-assigned. |
recurring | body | boolean | | Recurring flag (coerced to bool). |
リクエスト
{"cust":"string(req)","amount":number(req),"status":"draft|issued|paid|overdue","month":"YYMM","desc":"string","due":"string","id":"INV-...","recurring":bool}レスポンス例
{"ok":true,"invoice":{"id":"INV-2607-005","cust":"北斗商事","month":"2607","desc":"","amount":10000,"due":"","status":"draft","recurring":false}}
POST/api/invoice/:id公開
Update status and/or fields on one existing invoice; validates status enum and amount.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
id | path | string | ○ | Invoice id to update, e.g. INV-2607-004; 404 if not found. |
status | body | string | | New status; must be in draft|issued|paid|overdue else 400. |
cust | body | string | | Customer name, clip 120. |
desc | body | string | | Description, clip 300. |
month | body | string | | Billing month, clip 8. |
due | body | string | | Due date, clip 20. |
amount | body | number | | Amount; must be finite and >= 0 else 400. |
recurring | body | boolean | | Recurring flag (coerced to bool). |
リクエスト
{"status":"...","cust":"string","desc":"string","month":"YYMM","due":"string","amount":number,"recurring":bool} (all optional)レスポンス例
{"ok":true,"invoice":{"id":"INV-2607-004","cust":"三峰精機","month":"2607","desc":"新入社員向けキッティング 8台+送料","amount":19800,"due":"08/15","status":"issued","recurring":false}}
POST/api/invoices/issue公開
Bulk-issue: flips all draft invoices in a given (or current) month to issued, returns count.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
month | body | string | | Target YYMM month, clip 8; defaults to current month (e.g. 2607). |
リクエスト
{"month":"YYMM"} (optional; defaults to current month)レスポンス例
{"ok":true,"count":1}
GET/api/billing/summary公開live 200
Compute billing summary: MRR/ARR, billed/paid/unpaid/overdue/draft totals, recurring:oneshot ratio and paid ratio.
レスポンス例
{"ok":true,"summary":{"mrr":550000,"arr":6600000,"billed":632500,"paid":550000,"unpaid":82500,"overdue":49500,"draft":19800,"recurring":550000,"oneshot":82500,"ratio":"87:13","recurringPct":87,"paidRatio":87,"month":"2607","count":5}} ネットワーク (Network)
拠点回線・機器監視。
GET/api/network/deals公開live 200
Return the capacity-network deal board (provide/accept/request deals), newest-first.
レスポンス例
{"ok":true,"deals":[{"id":"dmrv8fry22c","dir":"provide","partner":"ネットワーク公開","kind":"キッティング枠","units":40,"period":"7/15–7/22","rate":1200,"status":"募集中"}]}
POST/api/network/deal公開
Add a deal to the board (list surplus capacity or request capacity); prepends to deals array.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
units | body | integer | ○ | Number of units/slots; parsed as int, must be > 0 else 400. |
dir | body | string | | Direction: provide|accept|request; anything else coerced to 'provide' (clipped 16). |
partner | body | string | | Partner/counterparty name (clipped 120); defaults 'ネットワーク公開'. |
kind | body | string | | Capacity kind (clipped 40); defaults 'キッティング枠'. |
period | body | string | | Date range label (clipped 40); defaults '—'. |
rate | body | integer | | Unit rate; parsed int, defaults 0. |
status | body | string | | Status label (clipped 24); defaults by dir (承認待ち/対応中/募集中). |
リクエスト
{"dir":"provide","partner":"ネットワーク公開","kind":"キッティング枠","units":40,"period":"7/15–7/22","rate":1200,"status":"募集中"}レスポンス例
{"ok":true,"deal":{"id":"d...","dir":"provide","partner":"...","kind":"キッティング枠","units":40,"period":"—","rate":0,"status":"募集中"},"deals":[...]}
GET/api/network/centers公開live 200
Return the certified kitting-center directory / marketplace (5 seeded centers).
レスポンス例
{"ok":true,"centers":[{"id":"c-tsm","name":"豊島 近接センター","region":"東京","mdm":["Intune","Workspace ONE"],"slots":80,"shelf":40,"rate":1100,"certs":["ISMS","Pマーク"]}]}
GET/api/network/oem公開live 200
Return the white-label / OEM tenant config (brand, logo, domain, plan).
レスポンス例
{"ok":true,"oem":{"brand":"","logo":"","domain":"","plan":"seat"}}
POST/api/network/oem公開
Save the OEM tenant config; overwrites the single 'oem' doc.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
brand | body | string | | Brand name (clipped 24). |
logo | body | string | | Logo (clipped 2 chars — likely an emoji/initial). |
domain | body | string | | Custom domain (clipped 48). |
plan | body | string | | Billing plan: seat|rev; anything else coerced to 'seat' (clipped 8). |
リクエスト
{"brand":"Acme","logo":"A","domain":"acme.example","plan":"seat"}レスポンス例
{"ok":true,"oem":{"brand":"Acme","logo":"A","domain":"acme.example","plan":"seat"}} オンボーディング (Onboarding)
導入チェックリスト。
GET/api/onboarding/projects公開live 200
Returns the current onboarding projects state {sel,tab,projects} (7-step MDM/ABM flow per customer), self-seeding demo data if missing.
レスポンス例
{"ok":true,"state":{"sel":"北斗商事","tab":"cust","projects":{"北斗商事":{"mdm":"Intune","steps":{"kickoff":"done","abm":"done","apns":"done","design":"done","pilot":"done","rollout":"done","handover":"wip"},"start":"2026-06-27"},"三峰精機":{...},"科研製薬":{...}}}}
PUT/api/onboarding/projects公開
Replaces the projects state; requires a projects object, sanitizes sel (clip 120) and tab (emp|cust).
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
sel | body | string | | selected customer key, clipped to 120 chars |
tab | body | string | | active tab; coerced to 'emp' if === 'emp' else 'cust' |
projects | body | object | ○ | map of customer -> {mdm,steps,start}; missing/non-object -> 400 |
リクエスト
{"sel":"北斗商事","tab":"cust","projects":{"北斗商事":{"mdm":"Intune","steps":{...},"start":"2026-06-27"}}}レスポンス例
{"ok":true,"state":{"sel":"...","tab":"cust","projects":{...}}}
GET/api/onboarding/requests公開live 200
Lists all employee device requests, sorted ascending by ts. Seed is empty (mirrors client).
レスポンス例
{"ok":true,"requests":[]}
POST/api/onboarding/request公開
Creates a pending device request; honors a client-provided id so ids stay in sync. Requires name and dept.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
id | body | string | | optional client id, clipped 60; defaults to generated id('REQ') |
name | body | string | ○ | employee name, clip 120; empty -> 400 |
dept | body | string | ○ | department, clip 120; empty -> 400 |
model | body | string | | device model, clip 120 |
mdm | body | string | | MDM platform, clip 60, default 'Intune' |
use | body | string | | usage/purpose, clip 60 |
ticket | body | string | | ticket ref, clip 60 |
ts | body | number | | timestamp; defaults to Date.now() if not a number |
リクエスト
{"name":"山田太郎","dept":"営業部","model":"iPhone 15","mdm":"Intune","use":"field","ticket":"T-100"}レスポンス例
{"ok":true,"request":{"id":"REQ-...","name":"山田太郎","dept":"営業部","model":"iPhone 15","mdm":"Intune","use":"field","ticket":"T-100","status":"pending","ts":1700000000000}}
POST/api/onboarding/request/:id公開
Approve/reject/reset an existing request by id via {status}; on 'approved' sets a lead-time (optional lead days else random 0.8-2.4).
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
id | path | string | ○ | request id; unknown -> 404 {error:'request not found'} |
status | body | string | ○ | one of approved|rejected|pending; else 400 {error:'invalid status'} |
lead | body | number | | lead days when approving; if not a number, random 0.8-2.4 rounded to 1dp |
リクエスト
{"status":"approved","lead":1.5}レスポンス例
{"ok":true,"request":{"id":"REQ-...","status":"approved","lead":1.5,...}} コンプライアンス (Compliance)
ISMS/Pマーク/SOC2/APPI・監査ログ・CAPA。
GET/api/compliance公開live 200
Returns control checklists per standard (isms/pmark/soc2/appi) plus the full CAPA corrective-action list.
レスポンス例
{"ok":true,"controls":{"isms":[true,true,true,true,false,true],"pmark":[...],"soc2":[...],"appi":[...]},"capa":[{"id":"CAPA-2026-014","src":"SOC 2","finding":"変更管理の承認記録に一部欠落","due":"2026-07-25","owner":"佐々木 玲","state":"対応中"}]}
POST/api/compliance/capa/:id公開
Updates the state of a single corrective action (CAPA) identified by id.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
id | path | string | ○ | CAPA id, e.g. CAPA-2026-014 |
state | body | string | ○ | New state string, clipped to 20 chars; must be non-empty after trim |
リクエスト
{"state":"是正待ち"}レスポンス例
{"ok":true,"capa":{"id":"CAPA-2026-014","src":"SOC 2","finding":"...","due":"2026-07-25","owner":"佐々木 玲","state":"是正待ち"}}
PUT/api/compliance/controls/:key公開
Replaces a standard's control checklist with a new boolean array.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
key | path | string | ○ | Control set key: isms | pmark | soc2 | appi |
controls | body | boolean[] | ○ | Array of booleans (coerced via !!), first 100 kept |
リクエスト
{"controls":[true,true,false,true,false,true]}レスポンス例
{"ok":true,"key":"isms","controls":[true,true,false,true,false,true]}
GET/api/audit-log公開live 200
Returns the tamper-evident audit trail as newest-first rows, each [ts,user,action,target,result,cat].
レスポンス例
{"ok":true,"logs":[["2026-07-11 09:02","佐々木 玲","ログイン(多要素認証)","管制コンソール","成功","login"],["2026-07-11 09:14","田中 亮","端末台帳 更新(ステータス変更)","IMEI 356821…4471","成功","ledger"]]}
POST/api/audit-log公開
Appends a new audit entry; auto-fills ts/user/target/result/cat defaults when omitted.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
action | body | string | ○ | Action description, clipped 200, must be non-empty after trim |
ts | body | string | | Timestamp, clipped 25; defaults to server now() 'YYYY-MM-DD HH:mm' |
user | body | string | | Actor, clipped 60; defaults to 'システム' |
target | body | string | | Target, clipped 200; defaults to '—' |
result | body | string | | Result, clipped 20; defaults to '成功' |
cat | body | string | | Category, clipped 20; defaults to 'audit' |
リクエスト
{"action":"消去実行","user":"山本 佳奈","target":"北斗商事 45台","result":"成功","cat":"erase"}レスポンス例
{"ok":true,"entry":["2026-07-22 10:15","山本 佳奈","消去実行","北斗商事 45台","成功","erase"]} ワークデスク (Workdesk)
社内ナレッジ・依頼。
GET/api/workdesk/docs公開live 200
List source-library documents, newest user-added first then seed docs in original order.
レスポンス例
{"ok":true,"docs":[{"id":"sop","name":"キッティング手順書","type":"SOP","size":184320,"status":"索引済","date":"2026/07/21","created":0,"seedIdx":0}]}
POST/api/workdesk/doc公開
Create/upsert a document; all body fields optional, defaults applied.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
id | body | string | | Doc id (clip 60); auto-generated 'doc-...' if omitted |
name | body | string | | Doc name (clip 200); defaults '資料-<timestamp>' |
type | body | string | | Doc type (clip 40); defaults 'FILE' |
size | body | number | | Byte size; defaults 0 |
status | body | string | | Index status (clip 40); defaults '索引済' |
date | body | string | | Display date (clip 40); defaults today() JA date |
リクエスト
{"name":"...","type":"...","size":123,"status":"...","date":"...","id":"..."}レスポンス例
{"ok":true,"doc":{"id":"doc-...","name":"...","type":"FILE","size":0,"status":"索引済","date":"2026/07/22","created":1700000000000}}
POST/api/workdesk/doc/:id/delete公開
Delete a document by id; 404 if not found.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
id | path | string | ○ | Doc id to delete (e.g. 'sop') |
レスポンス例
{"ok":true}
GET/api/workdesk/threads公開live 200
List AI chat threads, newest first (created desc); seed is empty.
レスポンス例
{"ok":true,"threads":[]}
POST/api/workdesk/thread公開
Create/upsert a full chat thread; body optional, sanitizes msgs.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
id | body | string | | Thread id (clip 60); auto-generated 'thr-...' if omitted |
title | body | string | | Title (clip 120); defaults '新しいチャット' |
ts | body | string | | Timestamp label (clip 40) |
msgs | body | array | | Messages [{role,text?,html?,srcs?,typing?}], each sanitized via cleanMsg |
リクエスト
{"id":"...","title":"...","ts":"...","msgs":[{"role":"user","text":"..."}]}レスポンス例
{"ok":true,"thread":{"id":"thr-...","title":"新しいチャット","ts":"","msgs":[],"created":1700000000000}}
POST/api/workdesk/thread/:id公開
Append/replace msgs or rename a thread; creates thread on-append if missing.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
id | path | string | ○ | Thread id |
title | body | string | | Rename thread (clip 120) |
ts | body | string | | Timestamp label (clip 40) |
msgs | body | array | | Replace whole msgs list |
append | body | array | | Append msgs to existing list |
リクエスト
{"title":"...","ts":"...","msgs":[...],"append":[{"role":"ai","text":"..."}]}レスポンス例
{"ok":true,"thread":{"id":"...","title":"...","ts":"...","msgs":[...],"created":1700000000000}}
POST/api/workdesk/conn公開
Persist connector on/off map {id:bool,...}, coerced to booleans.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
map | body | object | | {id:bool} map; body itself used as map if no .map key. Keys clip 40, values coerced !! |
リクエスト
{"slack":true,"teams":false} OR {"map":{"slack":true}}レスポンス例
{"ok":true,"conn":{"slack":true,"teams":false}}
GET/api/workdesk/conn公開live 200
Read persisted connector on/off map (hydration convenience).
レスポンス例
{"ok":true,"conn":{}} 管理者 (Admin)
主管理者認証・テナント管理・サブ管理者CRUD。要adminトークン
POST/api/admin/login公開
Master-admin login; returns an 8h HMAC-signed bearer token when the password matches ADMIN_PASSWORD.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
password | body | string | ○ | Master admin password (env ADMIN_PASSWORD, default 'kitting-admin') |
リクエスト
{"password":"kitting-admin"}レスポンス例
{"ok":true,"token":"<body>.<sig>"} | 401 {"ok":false,"error":"パスワードが違います"}
GET/api/admin/tenantsadminlive 401
List all tenants plus aggregate stats (totals, active/trial/suspended counts, MRR, devices, seats, sites, clients).
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
token | query | string | | Admin token (alternative to Authorization: Bearer header) |
レスポンス例
{"ok":true,"tenants":[{"id":"t-itabashi","name":"板橋キッティングセンター","plan":"Business","seats":180,"used":120,"status":"active","mrr":582000,"devices":1204,"clients":[...],"features":{...}}],"stats":{"total":5,"active":3,"trial":1,"suspended":1,"mrr":2487000,...},"origin":"https://..."}
GET/api/admin/tenant/:idadminlive 401
Get one tenant with derived client dashboard URLs and published-site URLs.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
id | path | string | ○ | Tenant id, e.g. t-itabashi |
token | query | string | | Admin token (alt to Bearer header) |
レスポンス例
{"ok":true,"tenant":{...},"dashboards":[{"client":"北斗商事","url":".../portal.html?c=..."}],"published":[{"slug":"itabashi-kitting","url":".../site/itabashi-kitting","live":true}],"origin":"https://..."}
POST/api/admin/tenant/:idadmin
Update an existing tenant's editable fields (name, plan, seats, used, status, email, devices, mrr, features, clients).
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
id | path | string | ○ | Tenant id to update |
name | body | string | | Tenant display name |
plan | body | string | | Starter|Business|Enterprise |
seats | body | number | | Licensed seats |
used | body | number | | Seats used |
status | body | string | | active|trial|suspended |
email | body | string | | Contact email |
devices | body | number | | Managed device count |
mrr | body | number | | Monthly recurring revenue |
features | body | object | | Feature-flag object merged into existing |
clients | body | array | | Client name array (capped at 200) |
リクエスト
{"plan":"Enterprise","seats":300,"status":"active","features":{"daas":true}}レスポンス例
{"ok":true,"tenant":{...updated...}}
POST/api/admin/tenantadmin
Create a new tenant (auto-generated id 't-<slug>-<hex>'), defaults to Starter/trial with base feature flags.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
name | body | string | | Tenant name (default '新規テナント', 80-char cap) |
plan | body | string | | Plan (default Starter) |
seats | body | number | | Seats (default 3) |
email | body | string | | Contact email |
リクエスト
{"name":"新規センター","plan":"Business","seats":50,"email":"x@example.jp"}レスポンス例
{"ok":true,"tenant":{"id":"t-...-a1b2","status":"trial","used":0,"mrr":0,"features":{...}}}
POST/api/admin/tenant/:id/deleteadmin
Delete a tenant from the store and persist.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
id | path | string | ○ | Tenant id to delete |
レスポンス例
{"ok":true}
POST/api/admin/tenant/:id/clientadmin
Add a client name to a tenant and return that client's portal dashboard URL.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
id | path | string | ○ | Tenant id |
client | body | string | ○ | Client name (80-char cap; 400 if empty) |
リクエスト
{"client":"新規クライアント"}レスポンス例
{"ok":true,"url":".../portal.html?c=%E6%96%B0%E8%A6%8F..."}
POST/api/admin/impersonate/:idadmin
Return an assist-mode ('admin_as') app URL for the given tenant (app shows a disclaimer banner).
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
id | path | string | ○ | Tenant id to impersonate |
レスポンス例
{"ok":true,"url":".../app?admin_as=%E6%9D%BF%E6%A9%8B..."}
GET/api/admin/subadminsadminlive 401
List all sub-admins (public-safe fields, no passwords) plus a compact {id,name} tenant list for assignment.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
token | query | string | | Admin token (alt to Bearer header) |
レスポンス例
{"ok":true,"subadmins":[{"id":"sa-demo","name":"サポート担当 山田","email":"yamada@ai-sns.io","tenants":["t-itabashi","t-nagoya"],"perms":{"canDelete":true},"active":true,"created":"2026-06-01"}],"tenants":[{"id":"t-itabashi","name":"板橋キッティングセンター"}]}
POST/api/admin/subadminadmin
Create a sub-admin; validates required name/email and unique email, auto-generates a password if none supplied.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
name | body | string | ○ | Sub-admin name (80-char cap) |
email | body | string | ○ | Unique email |
password | body | string | | Login password (random hex if omitted) |
tenants | body | array | | Assigned tenant ids (cap 200) |
canDelete | body | boolean | | Grant delete permission |
リクエスト
{"name":"新担当","email":"new@ai-sns.io","tenants":["t-osaka"],"canDelete":false}レスポンス例
{"ok":true,"subadmin":{...},"password":"<pass>"}
POST/api/admin/subadmin/:idadmin
Update a sub-admin's name, email, password, assigned tenants, canDelete perm, or active flag.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
id | path | string | ○ | Sub-admin id |
name | body | string | | New name |
email | body | string | | New email |
password | body | string | | New password |
tenants | body | array | | Reassign tenant ids |
canDelete | body | boolean | | Toggle delete perm |
active | body | boolean | | Enable/disable account |
リクエスト
{"active":false,"canDelete":true}レスポンス例
{"ok":true,"subadmin":{...updated...}}
POST/api/admin/subadmin/:id/deleteadmin
Delete a sub-admin and persist.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
id | path | string | ○ | Sub-admin id to delete |
レスポンス例
{"ok":true}
GET/api/admin/backupsadminlive 401
Return the global backup log (up to 120 newest snapshots across all tenants) plus daily-backup status.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
token | query | string | | Admin token (alt to Bearer header) |
レスポンス例
{"ok":true,"log":[{"tenantId":"t-itabashi","tenantName":"板橋キッティングセンター","id":"bk-...","ts":1699999999999,"by":"system","reason":"日次自動バックアップ","sites":1}],"daily":{"last":1699999999999,"tenants":5}}
GET/api/admin/activityadminlive 401
Return the audit/activity log (newest first, up to 200 entries).
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
token | query | string | | Admin token (alt to Bearer header) |
レスポンス例
{"ok":true,"activity":[{"ts":1699999999999,"by":"サポート担当 山田","role":"subadmin","action":"パスワードを変更","tenantId":"","tenantName":"","detail":""}]} サブ管理者 (Sub-Admin)
担当クライアント限定の運用(メモ・ファイル・削除)。要subadminトークン
POST/api/subadmin/login公開
Sub-admin login; matches email+password against the subadmins map and issues an 8h HMAC token.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
email | body | string | ○ | Sub-admin email, lowercased/trimmed before match (seed: yamada@ai-sns.io) |
password | body | string | ○ | Plaintext password; seed default 'kitting-sub' (or SUBADMIN_PASSWORD env) |
リクエスト
{"email":"yamada@ai-sns.io","password":"kitting-sub"}レスポンス例
{"ok":true,"token":"<b64>.<sig>","sub":{"id":"sa-demo","name":"サポート担当 山田","email":"yamada@ai-sns.io","tenants":["t-itabashi","t-nagoya"],"perms":{"canDelete":true},"active":true,"created":"2026-06-01"}}
GET/api/subadmin/mesubadminlive 401
Returns the authenticated sub-admin profile, their in-scope tenants, and aggregate stats.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
token | query | string | | Alternative to Authorization: Bearer header |
レスポンス例
{"ok":true,"sub":{...},"tenants":[{"id":"t-itabashi",...}],"stats":{"tenants":2,"devices":1414,"clients":5,"sites":1},"origin":"https://aisnsio-kitting.hf.space"}
GET/api/subadmin/tenant/:idsubadminlive 401
Scoped read of one tenant plus derived dashboards, published sites, backups, and the sub-admin's perms.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
id | path | string | ○ | Tenant id, must be in sub-admin scope (seed: t-itabashi, t-nagoya) |
token | query | string | | Alternative to Bearer header |
レスポンス例
{"ok":true,"tenant":{"id":"t-itabashi","clients":["北斗商事",...],"sites":["itabashi-kitting"]},"dashboards":[{"client":"北斗商事","url":".../portal.html?c=..."}],"published":[{"slug":"itabashi-kitting","url":".../site/itabashi-kitting","live":true}],"backups":[],"perms":{"canDelete":true},"origin":"..."}
POST/api/subadmin/tenant/:idsubadmin
Scoped non-core tenant edit; only the contact email can be changed, main settings are blocked.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
id | path | string | ○ | Tenant id, must be in scope |
email | body | string | | New contact email (max 120 chars) |
plan/seats/mrr/status/features | body | any | | If any present -> 403; sub-admins may not change core settings |
リクエスト
{"email":"new@example.co.jp"}レスポンス例
{"ok":true,"tenant":{"id":"t-itabashi","email":"new@example.co.jp",...}}
POST/api/subadmin/tenant/:id/clientsubadmin
Adds a client name to a scoped tenant and returns its portal URL.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
id | path | string | ○ | Tenant id, must be in scope |
client | body | string | ○ | Client name (max 80 chars); 400 if empty |
リクエスト
{"client":"新規クライアント"}レスポンス例
{"ok":true,"url":"https://aisnsio-kitting.hf.space/portal.html?c=%E6%96%B0%E8%A6%8F..."}
POST/api/subadmin/impersonate/:idsubadmin
Generates an assisted-login URL into the client app for a scoped tenant (support impersonation).
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
id | path | string | ○ | Tenant id, must be in scope |
レスポンス例
{"ok":true,"url":"https://aisnsio-kitting.hf.space/app?admin_as=%E6%9D%BF%E6%A9%8B...&by=subadmin"}
POST/api/subadmin/delete-requestsubadmin
Requests deletion of a client/site/tenant; generates a 6-digit access code (10-min expiry) gated by canDelete perm.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
tenantId | body | string | ○ | Tenant id, must be in scope |
targetType | body | string | | 'client'|'site'|'tenant', defaults to 'client' |
targetId | body | string | | Id/name of the thing to delete (max 120) |
リクエスト
{"tenantId":"t-itabashi","targetType":"client","targetId":"北斗商事"}レスポンス例
{"ok":true,"requestId":"dr-<hex>","sentTo":["itabashi@example.co.jp","マスター管理者"],"expiresInMin":10,"demoCode":"123456"}
POST/api/subadmin/delete-confirmsubadmin
Confirms a delete request with the emailed access code and performs the scoped delete after auto-backup.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
requestId | body | string | ○ | Id from delete-request; must belong to this sub-admin |
code | body | string | ○ | 6-digit access code |
リクエスト
{"requestId":"dr-<hex>","code":"123456"}レスポンス例
{"ok":true,"targetType":"client"}
GET/api/subadmin/activitysubadminlive 401
Returns up to 150 recent activity-log entries filtered to the sub-admin's own actions or in-scope tenants.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
token | query | string | | Alternative to Bearer header |
レスポンス例
{"ok":true,"activity":[{"ts":1700000000000,"by":"サポート担当 山田","role":"subadmin","action":"サポートメモを追加","tenantId":"t-itabashi","tenantName":"板橋キッティングセンター","detail":"..."}]}
GET/api/subadmin/backups-allsubadminlive 401
Aggregated backup log across all of the sub-admin's tenants, newest first, capped at 120 rows.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
token | query | string | | Alternative to Bearer header |
レスポンス例
{"ok":true,"log":[{"tenantId":"t-itabashi","tenantName":"板橋キッティングセンター","id":"bk-...","ts":1700000000000,"reason":"...","by":"..."}]}
POST/api/subadmin/passwordsubadmin
Self-service password change for the authenticated sub-admin.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
current | body | string | ○ | Current password; 401 if wrong (plaintext compare) |
next | body | string | ○ | New password, min 6 chars else 400 |
リクエスト
{"current":"kitting-sub","next":"newpass123"}レスポンス例
{"ok":true}
GET/api/notes/:tenantIdsubadminlive 401
Lists support notes for a tenant (admin any tenant, sub-admin scoped).
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
tenantId | path | string | ○ | Tenant id; sub-admin must have it in scope (seed: t-itabashi) |
token | query | string | | Alternative to Bearer header |
レスポンス例
{"ok":true,"notes":[{"id":"nt-...","ts":1700000000000,"by":"サポート担当 山田","text":"...","done":false}]}
POST/api/notes/:tenantIdsubadmin
Adds a support note (max 600 chars) to a tenant's note list.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
tenantId | path | string | ○ | Tenant id, scoped for sub-admin |
text | body | string | ○ | Note text, trimmed, max 600; 400 if empty |
リクエスト
{"text":"クライアントへ連絡済み"}レスポンス例
{"ok":true,"note":{"id":"nt-...","ts":1700000000000,"by":"サポート担当 山田","text":"...","done":false}}
POST/api/notes/:tenantId/:noteIdsubadmin
Updates (text/done) or deletes a specific support note.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
tenantId | path | string | ○ | Tenant id, scoped |
noteId | path | string | ○ | Note id (nt-...) |
del | body | boolean | | If truthy, delete the note and return {ok:true} |
done | body | boolean | | Toggle done flag |
text | body | string | | New text (max 600) |
リクエスト
{"done":true}レスポンス例
{"ok":true,"note":{"id":"nt-...","done":true,"text":"..."}}
GET/api/files/:tenantIdsubadminlive 401
Lists uploaded file metadata (no data blob) for a tenant.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
tenantId | path | string | ○ | Tenant id, scoped (seed: t-itabashi) |
token | query | string | | Alternative to Bearer header |
レスポンス例
{"ok":true,"files":[{"id":"fl-...","ts":1700000000000,"by":"サポート担当 山田","name":"手順書.pdf","type":"application/pdf","size":10240}]}
POST/api/files/:tenantIdsubadmin
Uploads a base64 file/document (up to ~2MB) attached to a tenant.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
tenantId | path | string | ○ | Tenant id, scoped |
name | body | string | | File name (max 160), defaults 'file' |
type | body | string | | MIME type (max 80) |
data | body | string | ○ | Base64/data payload; 400 if empty, 413 if >2,800,000 chars |
size | body | number | | Reported size; defaults to data.length |
リクエスト
{"name":"doc.pdf","type":"application/pdf","data":"<base64>"}レスポンス例
{"ok":true,"file":{"id":"fl-...","ts":1700000000000,"by":"...","name":"doc.pdf","type":"application/pdf","size":12345}}
GET/api/files/:tenantId/:fileId/downloadsubadminlive 401
Returns a single file's full base64 data for download.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
tenantId | path | string | ○ | Tenant id, scoped |
fileId | path | string | ○ | File id (fl-...); 404 if not found |
token | query | string | | Alternative to Bearer header |
レスポンス例
{"ok":true,"name":"doc.pdf","type":"application/pdf","data":"<base64>"}
POST/api/files/:tenantId/:fileId/deletesubadmin
Deletes an uploaded file from a tenant's file list.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
tenantId | path | string | ○ | Tenant id, scoped |
fileId | path | string | ○ | File id to remove |
レスポンス例
{"ok":true} バックアップ (Backup/Export)
日次バックアップ・状態エクスポート。要BACKUP_TOKEN
GET/api/admin/backupsadminlive 401
Master-admin global backup log (last 120 snapshot rows across all tenants) plus daily auto-backup status.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
token | query | string | | Admin JWT; alternatively sent as Authorization: Bearer <token>. Required. |
レスポンス例
{"ok":true,"log":[{"tenantId":"t-itabashi","tenantName":"板橋キッティングセンター","id":"bk-...","ts":1784600000000,"by":"system","reason":"日次自動バックアップ","sites":1}],"daily":{"last":1784600000000,"tenants":5}}
GET/api/backups/:tenantIdadminlive 401
List backup snapshot metadata for one tenant (newest first), for admin or the scoped sub-admin.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
tenantId | path | string | ○ | Tenant id, e.g. t-itabashi (seed tenants: t-itabashi, t-osaka, t-nagoya, t-fukuoka, t-sapporo). |
token | query | string | | Admin or sub-admin JWT; also accepted as Authorization: Bearer. Required. |
レスポンス例
{"ok":true,"backups":[{"id":"bk-lz...","ts":1784600000000,"by":"system","reason":"日次自動バックアップ","sites":1}]}
GET/api/subadmin/backups-allsubadminlive 401
Scope-wide backup log for the logged-in sub-admin: last 120 snapshot rows across only their assigned tenants.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
token | query | string | | Sub-admin JWT (role==='subadmin'); also accepted as Authorization: Bearer. Required. |
レスポンス例
{"ok":true,"log":[{"tenantId":"t-nagoya","tenantName":"名古屋モバイル管理","id":"bk-...","ts":1784600000000,"by":"system","reason":"日次自動バックアップ","sites":0}]}
GET/api/export/statetokenlive 200
Full runtime-data dump (all tenants/sites/subadmins/backups/leads/signs/bookings/etc. + counts) for automated off-site backups.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
token | query | string | | Backup token; must equal env BACKUP_TOKEN (default 'kitting-backup-token'). Alternatively header x-backup-token. Required (one of the two). |
レスポンス例
{"ok":true,"exportedAt":1784675572317,"space":"Aisnsio/kitting","tenants":{"t-itabashi":{...}},"sites":{...},"backups":{...},"counts":{"tenants":5,"backups":5,...}}
POST/api/backup/:tenantIdadmin
Create an on-demand snapshot of one tenant (deep-copies tenant record + its sites) with an optional reason label.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
tenantId | path | string | ○ | Tenant id to snapshot, e.g. t-itabashi. |
token | query | string | | Admin or scoped sub-admin JWT (or Authorization: Bearer). Required. |
reason | body | string | | Backup reason/label, sliced to 120 chars; defaults to '手動バックアップ'. |
リクエスト
{"reason":"設定変更前の手動バックアップ"}レスポンス例
{"ok":true,"backup":{"id":"bk-lz9x...","ts":1784675000000,"by":"マスター管理者","reason":"手動バックアップ","sites":1}}
POST/api/restore/:tenantId/:backupIdadmin
Rollback: restore a tenant (and its sites) from a stored snapshot; auto-snapshots current state first for recoverability.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
tenantId | path | string | ○ | Tenant id to roll back, e.g. t-itabashi. |
backupId | path | string | ○ | Snapshot id to restore, e.g. bk-lz9x2a (obtained from GET /api/backups/:tenantId). |
token | query | string | | Admin or scoped sub-admin JWT (or Authorization: Bearer). Required. |
レスポンス例
{"ok":true,"tenant":{"id":"t-itabashi","name":"板橋キッティングセンター","plan":"Business","sites":["itabashi-kitting"],...}} 公開フォーム・OAuth・その他 (Misc)
申込/パートナー/予約/署名/CRM・OAuth連携。
POST/api/synthia公開
Synthia AI chat proxy: forwards message+history to Anthropic Claude if ANTHROPIC_API_KEY is set, else returns a fallback flag so the client uses its built-in mock.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
message | body | string | ○ | User message (sliced to 4000 chars) |
history | body | array | | Prior turns [{role:'user'|'assistant',content}], last 8 used |
リクエスト
{"message":"string","history":[{"role":"user","content":"..."}]}レスポンス例
{"ok":false,"fallback":true,"reason":"no_key"} | {"ok":true,"text":"...","model":"claude-opus-4-8"}
GET/api/marketprice公開live 200
Live used-device market-price lookup for trade-in/buyback via SerpAPI / Yahoo Shopping / Google CSE; returns reference note if no key configured.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
model | query | string | ○ | Device model keyword (<=80 chars); 400 if missing |
cond | query | string | | Condition keyword (<=24 chars) |
レスポンス例
{"ok":true,"live":false,"model":"iPhone 13","note":"ライブ相場APIキーが未設定です…"}
GET/api/connect/status公開live 200
Lists all 13 integration providers (MDM/Apple/shipping/accounting/chat) with connected state, configured flag, redirectUri and go-live guide.
レスポンス例
{"ok":true,"origin":"https://aisnsio-kitting.hf.space","providers":[{"key":"intune","name":"Microsoft Intune","group":"MDM","authType":"oauth","connected":false,"configured":false,"guide":{...}}]}
GET/api/connect/:provider公開live 200
Starts OAuth: redirects (302) to the provider authorize URL for oauth providers, or returns an HTML popup for credential providers / unset creds.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
provider | path | string | ○ | Provider key e.g. intune, freee, moneyforward, lineworks |
レスポンス例
HTTP 200 text/html popup, OR 302 redirect to authorize URL, OR 404 text 'unknown provider'
GET/api/connect/:provider/callback公開live 200
OAuth redirect callback: validates state, exchanges the code for tokens against the provider, stores them, and returns an HTML popup that postMessages the opener.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
provider | path | string | ○ | Provider key |
code | query | string | | OAuth authorization code |
state | query | string | | CSRF state from the authorize step |
error | query | string | | Provider error code |
レスポンス例
HTTP 200 text/html popup ('接続に失敗しました' on state mismatch / '接続が完了しました' on success)
POST/api/connect/:provider/credentials公開
Saves API-key/token/webhook credentials for a credential-type provider; for webhook providers sends a real test POST to validate.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
provider | path | string | ○ | Credential provider key e.g. jamf, teams, yamato |
fields | body | object | ○ | Map of field key->value; all provider fields required |
リクエスト
{"fields":{"webhook":"https://..."}}レスポンス例
{"ok":true,"tested":true} | {"ok":false,"error":"...が未入力です"}
POST/api/connect/:provider/disconnect公開
Removes stored tokens/credentials for a provider.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
provider | path | string | ○ | Provider key |
レスポンス例
{"ok":true}
POST/api/site/publish公開
Publishes a white-label tenant marketing site (slug+HTML) served at /site/<slug>.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
slug | body | string | ○ | a-z0-9- slug (<=40); 400 if empty after sanitize |
html | body | string | ○ | Site HTML (<=800000 chars) |
name | body | string | | Display name (<=120) |
リクエスト
{"slug":"acme","html":"<html>..","name":"Acme"}レスポンス例
{"ok":true,"slug":"acme","url":"https://.../site/acme"}
GET/api/site/list公開live 200
Lists all published white-label sites with slug, name, updated timestamp and public URL.
レスポンス例
{"ok":true,"sites":[{"slug":"acme","name":"Acme","updated":1780000000000,"url":"https://.../site/acme"}]}
POST/api/site/:slug/unpublish公開
Deletes a published site by slug.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
slug | path | string | ○ | Site slug to remove |
レスポンス例
{"ok":true}
GET/site/:slug公開
Serves the published tenant site's raw HTML (not an /api path); 404 HTML page if slug unknown.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
slug | path | string | ○ | Published site slug |
レスポンス例
<!doctype html>...stored site HTML... (or 404 HTML)
POST/api/lead公開
Public lead capture: stores a CRM lead from site widgets/forms.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
name | body | string | | Contact name (<=120) |
email | body | string | | Email (<=160) |
company | body | string | | Company (<=160); at least one of name/email/company required |
phone | body | string | | Phone (<=40) |
message | body | string | | Message (<=1500) |
source | body | string | | Source tag (<=60), default 'web' |
tenant | body | string | | Owning tenant (<=80) |
リクエスト
{"name":"..","email":"..","company":"..","message":".."}レスポンス例
{"ok":true,"id":"L-xxxx"}
GET/api/leads公開live 200
Returns all CRM leads (newest first).
レスポンス例
{"ok":true,"leads":[{"id":"L-..","name":"QA Test","email":"qa@example.com","source":"signup","status":"new","created":1784675609773}]}
POST/api/lead/:id公開
Updates a lead's status/notes/contact fields.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
id | path | string | ○ | Lead id |
status | body | string | | Lead status |
notes | body | string | | Notes (<=3000) |
name/company/email/phone | body | string | | Contact fields (<=200) |
リクエスト
{"status":"contacted","notes":".."}レスポンス例
{"ok":true,"lead":{...}} | 404 {"ok":false}
POST/api/lead/:id/delete公開
Deletes a lead by id.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
id | path | string | ○ | Lead id |
レスポンス例
{"ok":true}
POST/api/sign/create公開
Creates a signable e-signature document (quote/contract) and returns its signing URL.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
title | body | string | | Doc title (<=160), default '御見積書' |
client | body | string | | Client name (<=120) |
email | body | string | | Signer email (<=160) |
amount | body | string | | Amount label (<=40) |
bodyHtml | body | string | | Document body HTML (<=200000) |
リクエスト
{"title":"..","client":"..","amount":"..","bodyHtml":".."}レスポンス例
{"ok":true,"id":"SG-xxxx","url":"https://.../sign.html?id=SG-xxxx"}
GET/api/sign/:id公開live 404
Fetches a signable document (public signing page reads this).
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
id | path | string | ○ | Document id SG-xxxx |
レスポンス例
{"ok":true,"doc":{"id":"SG-..","title":"..","status":"pending",...}} | 404 {"ok":false,"error":"not found"}
POST/api/sign/:id/submit公開
Signs a document: records signer name/signature/timestamp/IP and marks status 'signed'.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
id | path | string | ○ | Document id |
name | body | string | ○ | Signer name (<=120) |
agreed | body | boolean | ○ | Consent flag; 400 if false/missing |
signature | body | string | | Signature image data (<=200000) |
リクエスト
{"name":"..","agreed":true,"signature":"data:.."}レスポンス例
{"ok":true,"status":"signed","signedAt":1780000000000}
GET/api/sign/:id/status公開live 404
Returns just the signing status of a document.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
id | path | string | ○ | Document id |
レスポンス例
{"ok":true,"status":"pending","signedName":"","signedAt":0} | 404 {"ok":false}
GET/api/signs公開live 200
Lists all e-signature documents (metadata, newest first).
レスポンス例
{"ok":true,"signs":[{"id":"SG-..","title":"..","client":"..","status":"pending","created":..}]}
POST/api/booking公開
Public consultation booking; also creates a linked CRM lead with status 'meeting'.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
name | body | string | | Name (<=120) |
email | body | string | | Email (<=160); at least one of name/email required |
company | body | string | | Company (<=160) |
phone | body | string | | Phone (<=40) |
when | body | string | | Requested time (<=60) |
topic | body | string | | Topic (<=400) |
リクエスト
{"name":"..","email":"..","when":"..","topic":".."}レスポンス例
{"ok":true,"id":"B-xxxx"}
GET/api/bookings公開live 200
Lists all consultation bookings (newest first).
レスポンス例
{"ok":true,"bookings":[{"id":"B-..","name":"..","email":"..","status":"requested","created":..}]}
POST/api/booking/:id公開
Updates a booking's status.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
id | path | string | ○ | Booking id |
status | body | string | | New status (<=30) |
リクエスト
{"status":"confirmed"}レスポンス例
{"ok":true,"booking":{...}} | 404 {"ok":false}
POST/api/referral公開
Creates or updates a referral code for a referrer and returns the shareable ?ref= URL.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
referrer | body | string | | Referrer name (<=120), default '紹介者' |
code | body | string | | Desired code (<=24); auto-generated if omitted |
リクエスト
{"referrer":"..","code":".."}レスポンス例
{"ok":true,"code":"abc12","url":"https://.../?ref=abc12"}
GET/api/referrals公開live 200
Lists all referral codes with click/lead counts.
レスポンス例
{"ok":true,"referrals":[{"code":"abc12","referrer":"..","clicks":0,"leads":0,"created":..}]}
POST/api/referral/:code/track公開
Increments the click counter for a referral code.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
code | path | string | ○ | Referral code (case-insensitive) |
レスポンス例
{"ok":true}
POST/api/signup公開
Self-service trial signup: creates a trial (Starter) tenant and a linked CRM lead, returns the prospect app URL.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
email | body | string | ○ | Email (<=160); 400 if empty |
company | body | string | | Company (<=80), used as tenant name |
name | body | string | | Contact name (<=80) |
plan | body | string | | Requested plan label (stored in lead message) |
リクエスト
{"email":"..","company":"..","name":".."}レスポンス例
{"ok":true,"tenant":{"id":"t-..","name":".."},"url":"https://.../app?prospect=.."}
POST/api/partner公開
Partner/agency program application; creates a partner record + referral code + linked lead.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
company | body | string | ○ | Company (<=120); 400 if empty |
email | body | string | ○ | Email (<=160); 400 if empty |
contact | body | string | | Contact name (<=120) |
region | body | string | | Region (<=60) |
note | body | string | | Note (<=800) |
リクエスト
{"company":"..","email":"..","contact":"..","region":".."}レスポンス例
{"ok":true,"id":"P-xxxx","code":"acme12","referralUrl":"https://.../?ref=acme12"}
GET/api/partners公開live 200
Lists all partner applications (newest first).
レスポンス例
{"ok":true,"partners":[{"id":"P-..","company":"..","email":"..","tier":"Silver","status":"applied","code":".."}]}
POST/api/partner/:id公開
Updates a partner's status/tier/deals/revenue/note.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
id | path | string | ○ | Partner id |
status/tier/note | body | string | | Text fields (<=800) |
deals/revenue | body | number | | Numeric metrics (coerced with +) |
リクエスト
{"status":"active","tier":"Gold","deals":3,"revenue":500000}レスポンス例
{"ok":true,"partner":{...}} | 404 {"ok":false}
POST/api/review公開
Public review/NPS submission (stored unapproved pending moderation).
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
comment | body | string | ○ | Review text (<=800); 400 if empty |
rating | body | number | | 1-5 (clamped) |
name | body | string | | Name (<=80), default '匿名' |
company | body | string | | Company (<=120) |
nps | body | number | | 0-10 (clamped), default rating*2 |
リクエスト
{"rating":5,"comment":"..","name":"..","nps":9}レスポンス例
{"ok":true}
GET/api/reviews公開live 200
Lists approved reviews with computed average rating, count and NPS score.
レスポンス例
{"ok":true,"reviews":[{"id":"RV-965da4","name":"情シス部長","company":"北斗商事","rating":5,"nps":9,...}],"avg":4.7,"count":3,"nps":..}
GET/api/events公開live 200
Returns the static list of 3 upcoming webinars/events.
レスポンス例
{"ok":true,"events":[{"id":"ev-mdm","title":"30分でわかる:Intune × キッティング自動化","date":"2026-08-05 15:00","seats":100}]}
POST/api/event/:id/register公開
Registers for a webinar; creates a linked CRM lead (source 'webinar').
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
id | path | string | ○ | Event id (ev-mdm|ev-lcm|ev-ai) |
email | body | string | ○ | Email (<=160); 400 if empty |
name | body | string | | Name (<=120) |
company | body | string | | Company (<=160) |
リクエスト
{"email":"..","name":"..","company":".."}レスポンス例
{"ok":true} | 404 {"ok":false} for unknown event
POST/api/ab公開
Records an A/B landing test event (view or convert) for variant a or b.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
variant | body | string | | 'a' or 'b' (default 'a') |
event | body | string | | 'view' or 'convert' (default 'view') |
リクエスト
{"variant":"b","event":"convert"}レスポンス例
{"ok":true}
GET/api/ab公開live 200
Returns current A/B test counters for variants a and b.
レスポンス例
{"ok":true,"stats":{"a":{"view":0,"convert":0},"b":{"view":1,"convert":0}}}
GET/api/export/statetokenlive 401
Full runtime-data dump (all in-memory collections + counts) for automated backups; requires the backup token.
| パラメータ | 位置 | 型 | 必須 | 説明 |
|---|
token | query | string | ○ | Backup token; alternatively X-Backup-Token header. Must equal BACKUP_TOKEN |
レスポンス例
{"ok":false,"error":"unauthorized"} (no token) | {"ok":true,"exportedAt":..,"tenants":{..},"leads":{..},"counts":{..}}
GET/healthz公開live 200
Health check.
レスポンス例
{"status":"ok"}