온투코웍스

개발자

API·프로토콜·규칙

온투코웍스의 백엔드는 REST + WebSocket 하나의 API 위에 있습니다. 콘솔이 쓰는 것과 같은 API입니다.

기본 주소 — https://app.ontocoworks.com/api · 인증은 세션 쿠키(cs_sid, HttpOnly) · 실시간은 wss://app.ontocoworks.com/ws · 모든 응답은 JSON, 오류는 { "error": "code", "message": "…" }
목차

1. 인증

메서드·경로본문설명
POST /auth/signupname, email, password(8자+숫자), ref?, agreeTerms, agreePrivacy201. 개인 조직·'나의 방'·비서 자동 생성, 웰컴 캐시. 속도제한 20/시
POST /auth/login · /logoutemail, password세션 쿠키 발급·폐기. 로그인 10/5분(IP+이메일)
GET /auth/me사용자·소속 조직(역할·캐시 잔액)·추천 코드
POST /auth/password/forgot · /resetemail / token, password30분 토큰, 재설정 메일 발송
POST /auth/verify-email · /verify-email/resendcode(6자리)가입 이메일 인증(10분·5회·재발송 30초). GET /auth/me의 user.emailVerified
GET /auth/google구글 OAuth(설정 전 503)

1-1. API 토큰 · MCP 연결

외부 도구(AI 어시스턴트, 자동화, 스크립트)가 내 계정으로서 온투코웍스를 쓰게 하는 열쇠입니다. 콘솔 오른쪽 위 프로필 › API·MCP 연결에서 발급하며, 원문은 발급 순간 한 번만 보입니다. 토큰은 내가 볼 수 있는 조직·방·파일만, 내 역할 그대로 움직입니다. 결제·삭제·비밀번호·토큰 관리는 토큰으로 할 수 없습니다.

메서드·경로본문설명
GET /me/tokens내 토큰 목록(원문 없음). 로그인 세션에서만
POST /me/tokensname, scopes?(["read"] 또는 ["read","write"]), expiresDays?201. token 원문 1회 반환. 최대 20개
DELETE /me/tokens/:id폐기(즉시 끊김)
모든 API헤더 Authorization: Bearer oc_pat_…쿠키 대신 토큰. 읽기 전용 토큰은 GET 만(쓰기는 403)

MCP 서버

주소 https://app.ontocoworks.com/api/mcp (Streamable HTTP, JSON-RPC 2.0, POST). 같은 토큰을 Authorization: Bearer 헤더로 보냅니다. 서버→클라이언트 알림 스트림은 지원하지 않습니다(도구 호출만).

# Claude Code
claude mcp add --transport http ontocoworks https://app.ontocoworks.com/api/mcp --header "Authorization: Bearer oc_pat_…"

# 직접 호출
curl -X POST https://app.ontocoworks.com/api/mcp -H "Authorization: Bearer oc_pat_…" -H "content-type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"list_orgs","arguments":{}}}'
도구입력하는 일
list_orgs내 조직(id·이름·역할)
list_rooms · create_room · list_membersorgId / orgId,name,visibility?,invitePolicy? / roomId방 목록·만들기·멤버
read_messages · send_message · search_messagesroomId,limit?,before? / roomId,body / orgId,q대화 읽기·보내기(내 이름으로, @이름 으로 AI 팀원 호출)·검색
list_agentsorgIdAI 팀원 목록
list_files · read_fileorgId / fileId파일함 목록·텍스트 읽기(10만 자)
list_apps · install_apporgId / orgId,appId스토어 앱 목록·설치(조직 관리자)

앱을 코드로 만들어 올리는(직접 만들기 API) 도구는 아직 없습니다 — 스토어 설치까지 지원하며, 사용자 정의 앱 배포 API는 다음 단계입니다.

2. 조직·멤버·초대·캐시

메서드·경로권한설명
POST /orgs · GET /orgs · GET /orgs/:id로그인팀 조직 생성 시 스페이스 '일반'·방 '전체' 자동
GET /orgs/:id/members · PATCH|DELETE /orgs/:id/members/:userIdmember / admin+역할 owner > admin > member > guest. admin 부여는 owner만
POST|GET /orgs/:id/invites · GET /invites/:code · POST /invites/:code/acceptadmin+ / 공개 / 로그인1회용·다회·이메일 지정·만료. 이메일 지정 시 초대 메일 발송, 응답 mailed
GET /orgs/:id/cash · POST /orgs/:id/cash/topup-requests · POST …/:rid/decidemember / admin+ / owner잔액·원장 / 충전 요청 / 승인·집행(집행 시에만 원장 charge)
GET /orgs/:id/audit · GET /orgs/:id/usageadmin+통합 행동 로그 / 에이전트·모델·일별 사용량

3. 방·메시지·실시간

메서드·경로설명
GET|POST /orgs/:id/rooms스페이스·내 방(안 읽음 수) / 방 생성(channel·dm·group, 초기 멤버)
GET /rooms/:rid · POST /rooms/:rid/members · DELETE /rooms/:rid/members/:type/:id멤버는 사람·에이전트 한 표. 에이전트는 replyPolicy mention|always|never
GET /rooms/:rid/messages?after=|before=&limit= · POST /rooms/:rid/messages · POST /rooms/:rid/read방별 seq 커서. 본문 최대 20,000자

WebSocket /ws

// 연결: 같은 쿠키(cs_sid). 무인증·변조 시 401
← {"t":"hello","user":{"id":"…","name":"…"}}
→ {"t":"sub","room":"<roomId>"}        // 멤버만. 아니면 {"t":"error","code":"not_room_member"}
← {"t":"subbed","room":"…"}
← {"t":"msg","room":"…","message":{seq, author_type:"user|agent|system", body, meta, …}}
→ {"t":"unsub","room":"…"}  ·  → {"t":"ping"} ← {"t":"pong"}
// 서버가 25초마다 ping 프레임을 보냅니다(프록시 유휴 타임아웃 방지). 끊기면 재접속 후 after=seq 로 갭을 채웁니다.

4. 에이전트

메서드·경로설명
GET|POST /orgs/:id/agents · PATCH|DELETE /orgs/:id/agents/:aidname, handle(영소문자·숫자·_), persona, model, permLevel 1~3, maxTokens, status. 삭제=휴지통
PUT|GET /orgs/:id/secrets · DELETE /orgs/:id/secrets/:name금고(openrouter|anthropic|openai). 쓰기 전용, 목록은 힌트만, 삭제는 owner
GET /orgs/:id/approvals · POST …/:apid/decide승인 게이트 목록·결정

발화 규칙 v1

  1. @handle 또는 @이름 지목 → 지목된 에이전트 전원 응답
  2. 방 멤버십 replyPolicy=always → 1명 응답
  3. 1:1 방(사람 1 + 에이전트 1) → 지목 없이 응답
  4. 그 외 침묵. never·정지·삭제된 에이전트는 어떤 경우에도 침묵

컨텍스트는 방 최근 20건을 정본에서 매번 읽습니다(뇌에 원문 복사 없음). 답글 meta: {trigger, model, provider, key_source, input_tokens, output_tokens, cost_krw, latency_ms}.

5. 캐시 정산 공식

cost_krw = ceil( usage.cost_usd × USD_KRW(1,400) × MODEL_MARGIN(1.3) )
key_source = 'org'      → cost_krw = 0 (조직 자체 키, BYOK)
key_source = 'platform' → cash_ledger 에 debit(-cost_krw, ref_type='model_usage')
잔액 ≤ 0 → 응답 대신 시스템 안내(정지). 충전: requested → approved(owner) → executed(owner, 원장 charge)

6. 앱 매니페스트(개요)

앱은 iframe 표면 + 매니페스트 + postMessage로 붙습니다. 매니페스트는 이름·아이콘·진입 URL·provides/consumes 액션·필요 권한·설정 페이지를 선언하고, 방에서 /명령과 #참조로 호출됩니다. 앱 간 연동은 액션 버스를 통해 이루어집니다. 상세 표준(SDK·서명·심사)은 공개 출시와 함께 게시합니다.

외부 연동 — 메일(SMTP)

커넥트 › 앱 › 메일(SMTP)에서 회사 메일 계정을 연결합니다(서버·포트·계정·비밀번호 또는 앱 비밀번호·보내는 주소). 비밀번호는 조직 금고에만 저장되고 응답·로그에 나오지 않습니다. 연결 테스트는 실제 로그인을 확인합니다.

메서드·경로본문설명
POST /orgs/:id/apps/mail/connectkind:"basic", label?, username, secret, config:{host, port(465·587), from?, from_name?}201. 관리자. 사설 호스트·허용 외 포트 400
POST /connections/:id/mail/sendto, subject, text사람이 직접 발송(관리자). 분당 30
AI 도구 send_mailto, subject, text, connection?, reason?L2. 발송 요청 카드만 올리고, 관리자가 카드에서 [승인]해야 실제 발송(자동 발송 없음)

7. 측정 방법

  • 응답 지연 2.3초: 2026-09-02, 실서버, 개인 조직 '나의 방'에서 비서에게 "한 문장으로 자기소개" — 사용자 메시지 201 응답부터 에이전트 답글 WebSocket 수신까지. 모델 anthropic/claude-sonnet-5, 327+48 토큰, 차감 ₩3.
  • 적대적 검수 105/105: 같은 날, 실서버, 스크립트 test/adversarial.ts. 범위는 §8.
  • 자동 재기동 5초: api·agent-runtime 프로세스 kill -9 후 systemd 재기동 → /health 200까지.

8. 검수 범위(2026-09-02)

  • 입력 검증·가입·세션 변조·쿠키 플래그·로그인 열거 방지·속도제한(429)
  • 권한 경계: 비멤버 404(존재 비노출), member/admin/owner 계층, 개인 조직·소유자 보호, IDOR(타 조직 방·에이전트·충전)
  • 초대(1회용·이메일 지정·경로 조작), 캐시 무결성(최소·음수·소수·승인 순서·이중 집행·원장 합계)
  • 메시지(빈/2만자/SQL 메타·동시 8건 seq 고유), 에이전트(핸들·중복·타 조직·프롬프트 주입=키 미노출·집행 거절)
  • WebSocket(무인증·변조·비멤버·깨진 프레임·비UUID·미지 op), 금고(값 미노출·owner만 삭제), 프록시(XFF 위조 무효·26MB 413), 정적 8표면
  • 복원력: 메시지 버스 정지 중 쓰기 201·health 200, 재개 후 팬아웃·에이전트 디스패치 복구, kill -9 자동 재기동