{"openapi":"3.1.0","info":{"title":"MUSUBICODE Public API","version":"1.0.0","description":"開発チャット、ツール同期、AIクルーを操作するREST API。"},"servers":[{"url":"https://app.musubicode.com/api/v1"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"MUSUBICODE API key"}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}},"Account":{"type":"object","required":["userId","email","displayName","workspaceId","workspaceName","createdAt"],"properties":{"userId":{"type":"string"},"email":{"type":"string","format":"email"},"displayName":{"type":"string"},"workspaceId":{"type":"string"},"workspaceName":{"type":"string"},"createdAt":{"type":"integer"}}},"Channel":{"type":"object","required":["id","name","description","createdAt"],"properties":{"id":{"type":"string"},"name":{"type":"string","minLength":1,"maxLength":40,"description":"日本語、英数字、空白、ハイフン、アンダースコアを利用できます。"},"description":{"type":"string"},"createdAt":{"type":"integer"},"unread":{"type":"integer","minimum":0,"maximum":99,"description":"チャンネル一覧取得時の未読メッセージ数。99件でクランプされます。"}}},"Invite":{"type":"object","required":["tokenHash","role","expiresAt","maxUses","usedCount","createdBy"],"properties":{"tokenHash":{"type":"string","pattern":"^[0-9a-f]{64}$"},"role":{"type":"string","enum":["member","admin"]},"expiresAt":{"type":"integer"},"maxUses":{"type":"integer","minimum":1,"maximum":100},"usedCount":{"type":"integer","minimum":0},"createdBy":{"type":"string"}}},"Member":{"type":"object","required":["userId","displayName","role","joinedAt"],"properties":{"userId":{"type":"string"},"displayName":{"type":"string"},"role":{"type":"string","enum":["owner","admin","member"]},"joinedAt":{"type":"integer"}}},"Message":{"type":"object","required":["id","channelId","authorId","authorName","body","createdAt"],"properties":{"id":{"type":"string"},"channelId":{"type":"string"},"authorId":{"type":"string"},"authorName":{"type":"string"},"authorType":{"type":"string","enum":["human","ai","integration"]},"body":{"type":"string"},"createdAt":{"type":"integer"}}},"ConversationTurn":{"type":"object","required":["agent","speaker","initials","phase","phaseLabel","content"],"properties":{"agent":{"type":"string","enum":["codex","claude","gemini"]},"speaker":{"type":"string","description":"チャットに表示する自然な日本語の担当名"},"initials":{"type":"string"},"phase":{"type":"string","enum":["plan","research","spec","implementation","review"]},"phaseLabel":{"type":"string"},"content":{"type":"string"},"citations":{"type":"array","items":{"type":"string","format":"uri"}},"demo":{"type":"boolean"}}},"ApprovalRequest":{"type":"object","required":["id","workspaceId","requestedBy","requestedVia","kind","title","detail","status","state","decidedBy","decidedAt","decisionNote","expiresAt","consumedAt","createdAt"],"properties":{"id":{"type":"string"},"workspaceId":{"type":"string"},"requestedBy":{"type":"string"},"requestedVia":{"type":"string","enum":["session","chatgpt","api-key"]},"kind":{"type":"string","pattern":"^[a-z][a-z0-9._-]{1,60}$"},"title":{"type":"string","minLength":1,"maxLength":200},"detail":{"type":"object","additionalProperties":true,"description":"Maximum serialized size: 8KB"},"status":{"type":"string","enum":["pending","approved","rejected"]},"state":{"type":"string","enum":["pending","approved","rejected","expired","consumed"]},"decidedBy":{"type":["string","null"]},"decidedAt":{"type":["integer","null"]},"decisionNote":{"type":["string","null"]},"expiresAt":{"type":"integer"},"consumedAt":{"type":["integer","null"]},"createdAt":{"type":"integer"}}}}},"paths":{"/account":{"get":{"summary":"自分のアカウント状態を確認","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Account status"},"401":{"description":"MUSUBICODE login required"}}},"post":{"summary":"自分専用のアカウントと作業場所を作成","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["workspaceName"],"properties":{"workspaceName":{"type":"string","minLength":2,"maxLength":60}}}}}},"responses":{"201":{"description":"Account created"},"403":{"description":"MUSUBICODE login required"}}}},"/health":{"get":{"summary":"稼働状態","responses":{"200":{"description":"Healthy"}}}},"/channels":{"get":{"summary":"チャンネル一覧","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"workspaceId","schema":{"type":"string"}}],"responses":{"200":{"description":"Channels","content":{"application/json":{"schema":{"type":"object","required":["channels"],"properties":{"channels":{"type":"array","items":{"$ref":"#/components/schemas/Channel"}}}}}}},"401":{"description":"Unauthorized"}}},"post":{"summary":"チャンネル作成","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"workspaceId":{"type":"string"},"name":{"type":"string","minLength":1,"maxLength":40,"description":"日本語、英数字、空白、ハイフン、アンダースコアを利用できます。"},"description":{"type":"string"}}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","required":["channel"],"properties":{"channel":{"$ref":"#/components/schemas/Channel"}}}}}},"409":{"description":"Channel already exists"}}},"delete":{"summary":"チャンネル削除（管理者以上）","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"workspaceId":{"type":"string"},"id":{"type":"string"}}}}}},"responses":{"200":{"description":"Deleted"},"400":{"description":"The last channel cannot be deleted"},"404":{"description":"Not found"}}}},"/channels/read":{"post":{"summary":"チャンネルを既読にする","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["channelId"],"properties":{"workspaceId":{"type":"string","default":"default"},"channelId":{"type":"string"}}}}}},"responses":{"204":{"description":"Read timestamp recorded"},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"404":{"description":"Workspace not found or insufficient role"}}}},"/messages":{"get":{"summary":"チャンネルのメッセージ一覧","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"channelId","schema":{"type":"string"}},{"in":"query","name":"limit","schema":{"type":"integer","maximum":100}}],"responses":{"200":{"description":"Messages"},"401":{"description":"Unauthorized"}}},"post":{"summary":"メッセージ送信","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["channelId","body"],"properties":{"channelId":{"type":"string"},"body":{"type":"string","maxLength":8000}}}}}},"responses":{"201":{"description":"Created"},"401":{"description":"Unauthorized"}}}},"/runs":{"get":{"summary":"AIクルー実行履歴","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Runs"}}},"post":{"summary":"3人のAIに相談","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["prompt"],"properties":{"prompt":{"type":"string","maxLength":12000},"channelId":{"type":"string"},"agents":{"type":"array","items":{"type":"string","enum":["codex","claude","gemini"]}},"approvalMode":{"type":"string","const":"manual"}}}}}},"responses":{"200":{"description":"各AIの発言を会話順に返します。未接続時はデモ会話です。","content":{"application/json":{"schema":{"type":"object","required":["conversation","demo"],"properties":{"conversation":{"type":"array","items":{"$ref":"#/components/schemas/ConversationTurn"}},"demo":{"type":"boolean"},"summary":{"type":"string"}}}}}},"401":{"description":"Unauthorized when providers are active"},"429":{"description":"Rate limited"}}}},"/approvals":{"get":{"summary":"Human Gate承認リクエスト一覧","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"workspaceId","schema":{"type":"string","default":"default"}},{"in":"query","name":"status","schema":{"type":"string","enum":["pending","all"],"default":"pending"}}],"responses":{"200":{"description":"Approval requests with a derived state","content":{"application/json":{"schema":{"type":"object","required":["workspaceId","approvals"],"properties":{"workspaceId":{"type":"string"},"approvals":{"type":"array","items":{"$ref":"#/components/schemas/ApprovalRequest"}}}}}}},"400":{"description":"Invalid status filter"},"401":{"description":"Authentication required"}}},"post":{"summary":"Human Gate承認リクエスト作成","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["kind","title"],"properties":{"workspaceId":{"type":"string","default":"default"},"kind":{"type":"string","pattern":"^[a-z][a-z0-9._-]{1,60}$"},"title":{"type":"string","minLength":1,"maxLength":200},"detail":{"type":"object","additionalProperties":true,"description":"Maximum serialized size: 8KB"},"expiresInHours":{"type":"integer","minimum":1,"maximum":168,"default":72}}}}}},"responses":{"201":{"description":"Approval request created","content":{"application/json":{"schema":{"type":"object","required":["approval"],"properties":{"approval":{"$ref":"#/components/schemas/ApprovalRequest"}}}}}},"400":{"description":"Invalid request"},"401":{"description":"Authentication required"},"413":{"description":"Detail exceeds 8KB"}}},"put":{"summary":"Human Gate承認または却下（管理者・人間経路のみ）","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","status"],"properties":{"workspaceId":{"type":"string","default":"default"},"id":{"type":"string"},"status":{"type":"string","enum":["approved","rejected"]},"decisionNote":{"type":"string"}}}}}},"responses":{"200":{"description":"Approval request decided","content":{"application/json":{"schema":{"type":"object","required":["approval"],"properties":{"approval":{"$ref":"#/components/schemas/ApprovalRequest"}}}}}},"400":{"description":"Invalid decision"},"403":{"description":"human_approval_only"},"404":{"description":"Not found or insufficient role"},"409":{"description":"Approval request is not pending"}}}},"/approvals/consume":{"post":{"summary":"承認済みリクエストを原子的に消費","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"workspaceId":{"type":"string","default":"default"},"id":{"type":"string"}}}}}},"responses":{"200":{"description":"Approval request consumed"},"401":{"description":"Authentication required"},"409":{"description":"Approval request is not consumable"}}}},"/integrations":{"get":{"summary":"ツール接続状態","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Integrations"}}},"post":{"summary":"接続状態を更新","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["provider","enabled"],"properties":{"provider":{"type":"string"},"enabled":{"type":"boolean"},"config":{"type":"object"}}}}}},"responses":{"200":{"description":"Updated"}}}},"/api-keys":{"get":{"summary":"APIキー一覧","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Keys"}}},"post":{"summary":"APIキー作成（値は一度だけ返却）","security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Created"}}},"delete":{"summary":"APIキー失効","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Revoked"}}}},"/billing/checkout":{"post":{"summary":"Stripe Checkout Sessionを作成","description":"サーバー側カタログのplanKeyだけを受け付け、金額やStripe Price IDはクライアントから受け取らない。","security":[{"bearerAuth":[]}],"parameters":[{"in":"header","name":"Idempotency-Key","required":true,"schema":{"type":"string","minLength":16,"maxLength":100,"pattern":"^[A-Za-z0-9_-]+$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["planKey"],"properties":{"workspaceId":{"type":"string","default":"default"},"planKey":{"type":"string","pattern":"^[a-z0-9][a-z0-9_-]{0,63}$"}}}}}},"responses":{"201":{"description":"Stripe-hosted Checkout URL created"},"400":{"description":"Invalid plan or idempotency key"},"401":{"description":"Authentication required"},"503":{"description":"Stripe configuration missing or invalid"}}}},"/billing/portal":{"post":{"summary":"Stripe Customer Portal Sessionを作成","security":[{"bearerAuth":[]}],"parameters":[{"in":"header","name":"Idempotency-Key","required":true,"schema":{"type":"string","minLength":16,"maxLength":100,"pattern":"^[A-Za-z0-9_-]+$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"workspaceId":{"type":"string","default":"default"}}}}}},"responses":{"201":{"description":"Customer Portal URL created"},"401":{"description":"Authentication required"},"409":{"description":"No mapped Stripe Customer"},"503":{"description":"Stripe configuration missing or invalid"}}}},"/invites":{"get":{"summary":"有効期限内の招待一覧（管理者以上）","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"workspaceId","schema":{"type":"string","default":"default"}}],"responses":{"200":{"description":"Invites","content":{"application/json":{"schema":{"type":"object","required":["workspaceId","invites"],"properties":{"workspaceId":{"type":"string"},"invites":{"type":"array","items":{"$ref":"#/components/schemas/Invite"}}}}}}},"404":{"description":"Workspace not found or insufficient role"}}},"post":{"summary":"招待作成（管理者以上・トークンは一度だけ返却）","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"workspaceId":{"type":"string","default":"default"},"role":{"type":"string","enum":["member","admin"],"default":"member"},"expiresInHours":{"type":"integer","minimum":1,"maximum":168,"default":72},"maxUses":{"type":"integer","minimum":1,"maximum":100,"default":10}}}}}},"responses":{"201":{"description":"Created; the plaintext token is returned only once"},"400":{"description":"Invalid invite options"},"404":{"description":"Workspace not found or insufficient role"}}},"delete":{"summary":"招待失効（管理者以上）","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["tokenHash"],"properties":{"workspaceId":{"type":"string","default":"default"},"tokenHash":{"type":"string","pattern":"^[0-9a-f]{64}$"}}}}}},"responses":{"200":{"description":"Revoked"},"404":{"description":"Invite not found"}}}},"/invites/accept":{"post":{"summary":"招待を受諾（MUSUBICODEログインのみ）","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["token"],"properties":{"token":{"type":"string"}}}}}},"responses":{"200":{"description":"Joined or already a member"},"401":{"description":"Authentication required"},"403":{"description":"API keys cannot accept invitations"},"404":{"description":"Invalid, expired, or exhausted invite"}}}},"/members":{"get":{"summary":"メンバー一覧","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"workspaceId","schema":{"type":"string","default":"default"}}],"responses":{"200":{"description":"Members","content":{"application/json":{"schema":{"type":"object","required":["workspaceId","members"],"properties":{"workspaceId":{"type":"string"},"members":{"type":"array","items":{"$ref":"#/components/schemas/Member"}}}}}}}}},"delete":{"summary":"メンバー削除（管理者以上）","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["userId"],"properties":{"workspaceId":{"type":"string","default":"default"},"userId":{"type":"string"}}}}}},"responses":{"200":{"description":"Removed"},"400":{"description":"Owner or current member cannot be removed"},"404":{"description":"Member not found"}}}},"/files":{"get":{"summary":"同期ファイル一覧または取得","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Files"}}},"put":{"summary":"ファイルを同期ストレージへ保存","security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Stored"}}},"delete":{"summary":"同期ファイルを削除","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Deleted"}}}},"/webhooks/github":{"post":{"summary":"署名付きGitHub Webhook","responses":{"202":{"description":"Accepted"},"401":{"description":"Invalid signature"}}}},"/webhooks/stripe":{"post":{"summary":"署名付きStripe Webhook","description":"raw bodyを検証し、設定したTest/Liveモードと一致するイベントだけをイベントID単位で冪等に処理する。","responses":{"200":{"description":"Verified and processed or already processed"},"400":{"description":"Missing/invalid signature or mode mismatch"},"413":{"description":"Payload too large"},"503":{"description":"Stripe webhook configuration missing"}}}}}}