Nodaro 문서
문서노드 레퍼런스모델템플릿AI 에이전트(MCP)개발자셀프 호스팅리서치비교
REST API

워크스페이스와 조직

X-Nodaro-Workspace로 Nodaro API 요청을 조직의 워크스페이스에서 실행하고, 토큰을 워크스페이스에 연결하고, 멤버, 초대, 공유, 사용량을 관리하세요.

Nodaro Cloud에서 사용할 수 있습니다

워크스페이스는 조직의 멤버가 함께 작업하는 곳으로, 학교의 반이나 회사의 팀이 해당됩니다. API 요청은 X-Nodaro-Workspace 헤더에 워크스페이스 ID를 보내면 그 워크스페이스에서 실행되며, 조직 엔드포인트는 그 주변의 모든 것을 관리합니다. 조직, 멤버, 초대, 참여 코드, 공유, 예산, 사용량이 여기에 해당합니다.

조직은 인스턴스별로 켜는 Nodaro Cloud 기능입니다. 조직이 켜져 있지 않은 곳에서는 아래 엔드포인트가 존재하지 않고 헤더도 무시됩니다. 셀프 호스팅 빌드에는 조직이 포함되지 않습니다. 개념은 워크스페이스에서 확인하세요.

워크스페이스에서 작업

X-Nodaro-Workspace: 6f1e6b4c-6a4e-4b7b-9d2a-2f0f0a1d9c34

이 헤더가 하는 일은 딱 두 가지입니다. 목록이 어느 워크스페이스를 반환할지와 새로 만든 것이 어디에 저장될지를 정합니다. 액세스 권한을 주지는 않습니다. ID로 지정한 대상을 읽고, 수정하고, 삭제하고, 실행하는 요청은 그 객체가 속한 워크스페이스를 따릅니다. 헤더를 빠뜨려도 내 작업이 가려지지 않으며, 헤더를 위조해도 다른 사람의 작업에 닿을 수 없습니다.

헤더가 없으면 조직이 없는 계정과 마찬가지로 개인 공간에서 작업합니다.

curl -s https://app.nodaro.ai/v1/workflows \
  -H "Authorization: Bearer $NODARO_API_KEY" \
  -H "X-Nodaro-Workspace: 6f1e6b4c-6a4e-4b7b-9d2a-2f0f0a1d9c34"
// Every request of this client acts in the workspace:
const classClient = createClient({
  baseUrl: 'https://app.nodaro.ai',
  auth: new StaticTokenAuth(process.env.NODARO_API_KEY!),
  workspaceId: '6f1e6b4c-6a4e-4b7b-9d2a-2f0f0a1d9c34',
})

// Or derive a second client from an existing one:
const classroom = client.withWorkspace(workspaceId)
await classroom.workflows.run(workflowId) // lands in the class
await client.workflows.run(workflowId)    // lands in the personal space
nodaro --workspace 6f1e6b4c-6a4e-4b7b-9d2a-2f0f0a1d9c34 workflows list   # this command only
export NODARO_WORKSPACE=6f1e6b4c-6a4e-4b7b-9d2a-2f0f0a1d9c34            # this shell or CI job
nodaro workspace use 6f1e6b4c-6a4e-4b7b-9d2a-2f0f0a1d9c34                # saved on the profile
nodaro workspace current                                                # which one applies, and why

client.withWorkspace는 기존 클라이언트를 바꾸지 않고 새 클라이언트를 반환합니다. 그래서 동시에 실행되는 두 작업이 어느 워크스페이스에 있는지를 두고 경합하는 일이 없습니다. 개인 공간에는 null을 넘기세요. CLI에서는 세 가지 방법 중 위에 있는 방법이 아래 방법보다 우선하며, nodaro workspace use는 저장하기 전에 워크스페이스를 확인합니다.

헤더는 내가 속한 워크스페이스에 대해서만 보내세요.

상태코드발생 시점
400validation_error값이 UUID가 아닙니다.
403not_a_member그 워크스페이스의 멤버가 아니거나, 워크스페이스가 없거나, 그 조직이 활성 상태가 아닙니다.
403member_suspended내 멤버십이 정지되었습니다.

다음 요청은 오래된 선택을 거부하지 않으므로, 이 때문에 접근이 막히는 일은 없습니다. GET /v1/me, GET /v1/workspaces, 초대 읽기와 수락, 그리고 코드로 워크스페이스에 참여하기입니다. 이런 요청에서는 더 이상 선택할 수 없는 워크스페이스를 헤더를 보내지 않은 것처럼 처리합니다. GET /v1/me와 GET /v1/workspaces는 선택할 수 있는 워크스페이스를 알려 주므로, 여기에 더 이상 나오지 않는 워크스페이스는 캐시한 선택에서 지우세요.

토큰을 워크스페이스에 연결

API 토큰은 워크스페이스 하나에 연결할 수 있습니다. 연결한 뒤에는 모든 요청에서 그 헤더를 보낸 것처럼 작동하며, 다른 워크스페이스를 명시한 헤더에는 400 token_workspace_mismatch가 반환됩니다.

# Bind
curl -X PATCH https://app.nodaro.ai/v1/api-tokens/$TOKEN_ID \
  -H "Authorization: Bearer $SESSION_JWT" \
  -H "Content-Type: application/json" \
  -d '{"workspaceId": "6f1e6b4c-6a4e-4b7b-9d2a-2f0f0a1d9c34"}'

# Unbind
curl -X PATCH https://app.nodaro.ai/v1/api-tokens/$TOKEN_ID \
  -H "Authorization: Bearer $SESSION_JWT" \
  -H "Content-Type: application/json" \
  -d '{"workspaceId": null}'

토큰을 관리하려면 로그인한 세션의 JWT가 필요합니다. API 토큰이나 OAuth 토큰으로는 403 forbidden이 반환됩니다. 토큰은 헤더로 선택할 수 있는 워크스페이스에만 연결할 수 있으며, 연결 해제는 언제든지 가능합니다. 토큰 목록에는 연결된 워크스페이스가 workspaceId로 나옵니다.

새로 만든 것이 저장되는 곳

  • 워크스페이스 안에서 만든 것은 그 워크스페이스에 저장되며, 개인 공간에 저장되지 않습니다. 프로젝트를 지정하지 않은 만들기는 워크스페이스의 프로젝트로 들어갑니다. 워크스페이스에 아직 프로젝트가 없으면 409 workspace_has_no_default_project가 반환되므로, 프로젝트를 지정하면 성공합니다.
  • 지정한 프로젝트는 작업 중인 워크스페이스에 속해야 합니다. 다른 워크스페이스나 개인 공간의 프로젝트를 지정하면 404 Project not found가 반환됩니다. 존재하지 않는 프로젝트와 같은 응답이므로, 헤더로 무엇이 존재하는지 알아낼 수 없습니다.
  • 프로젝트 만들기는 관리자로 제한될 수 있습니다. 이 경우 멤버에게는 403 project_create_not_allowed가 반환됩니다.
  • 조직은 개인 공간을 닫을 수 있습니다. 이 경우 멤버는 워크스페이스 안에서만 만들 수 있고, 헤더 없는 만들기에는 403 personal_space_disabled가 반환됩니다. 조직이 없는 계정은 영향을 받지 않습니다.

보관된 워크스페이스는 읽기 전용

워크스페이스를 보관하면 그 안의 모든 것은 계속 읽을 수 있지만, 새 작업은 추가할 수 없습니다. 목록은 이전과 같이 작동합니다. 프로젝트, 워크플로, 가져오기, 하위 워크플로 등 모든 만들기에는 409 workspace_archived가 반환되며, 작업을 워크스페이스 안으로 옮길 때도 마찬가지입니다. 작업을 밖으로 옮기는 것은 계속 허용됩니다. 보관된 워크스페이스를 여는 이유가 작업을 꺼내기 위해서이기 때문입니다. 워크플로 공유처럼 그 안에 쓰는 다른 요청에는 403 workspace_archived가 반환됩니다. 상태가 아니라 코드로 판단하세요.

내 정보: GET /v1/me

GET /v1/me는 내 프로필을 반환합니다. 조직이 있는 인스턴스에서는 organizations, workspaces, lastWorkspaceId도 담기며, 각 항목에는 내 역할과 상태가 있습니다. 조직 항목에는 그 조직이 워크스페이스를 부르는 단어 같은, 확정된 vocabulary가 포함되므로 클라이언트가 “반”이나 “팀”을 하드코딩할 필요가 없습니다. GET /v1/workspaces는 같은 워크스페이스 목록만 따로 반환합니다.

조직 필드의 세 가지 상태를 구분하세요.

보이는 것의미해야 할 일
필드가 없음이 인스턴스에는 조직이 없습니다.워크스페이스 전환 메뉴를 표시하지 마세요.
필드가 있지만 비어 있음이 계정은 어느 조직에도 속하지 않습니다.조직을 만들거나 참여하도록 안내하세요.
organizationsUnavailable: true조회에 실패했습니다.기존 선택을 유지하세요.

조직 엔드포인트

모든 엔드포인트에는 인증이 필요합니다. 본문은 JSON이고, 응답은 { "data": … }, 목록은 { "data": [ … ], "nextCursor": … }이며, ID는 UUID입니다.

조직

메서드경로권한본문 또는 쿼리
POST/v1/orgs로그인한 누구나{ name, kind, slug?, acceptTerms?, settings? }이며, kind는 school 또는 team입니다. 201을 반환합니다.
GET/v1/orgs누구나내 조직 목록을 내 role, memberStatus와 함께 반환합니다.
GET/v1/orgs/:id멤버
PATCH/v1/orgs/:id소유자, 관리자{ name?, settings? }. 설정은 키별로 병합되며, 알 수 없는 키는 버려집니다.
POST/v1/orgs/:id/transfer-ownership소유자{ userId }. 새 소유자는 활성 관리자여야 하며, 이전 소유자는 같은 단계에서 관리자가 됩니다.
DELETE/v1/orgs/:id소유자보관되지 않은 워크스페이스가 하나라도 있으면 409 has_active_workspaces로 거부됩니다. 조직은 소프트 삭제되고 슬러그는 해제됩니다.
POST/v1/orgs/:id/leave멤버소유자는 나갈 수 없으므로(409 owner_cannot_leave) 먼저 소유권을 이전하세요. 나가면 조직의 모든 워크스페이스에서도 제거됩니다.
  • 승인. 새 조직은 보통 pending으로 시작하고, 플랫폼이 승인하면 active가 됩니다. 기다리는 동안에는 소유자만 조직을 볼 수 있고 다른 사람은 볼 수 없으며, 그 안의 어떤 것도 바꿀 수 없습니다. 만든 사람에게 이 사실을 알려 주세요. 그렇지 않으면 대기 상태가 실패처럼 보입니다.
  • 학교는 약관 동의가 필요합니다. 학교를 만들려면 acceptTerms: true가 필요하며, 이로써 소유자는 학생을 등록할 권한이 있음을 확인합니다. 이 값이 없으면 400 terms_required가 반환됩니다.
  • 슬러그는 영문 소문자, 숫자, 하이픈으로 이루어진 1~50자입니다. 보내는 슬러그는 사용 중이 아니어야 합니다(409 name_taken). 보내지 않으면 이름에서 만들어집니다. “Sunrise School”은 sunrise-school이 되고, 그다음은 sunrise-school-2가 됩니다.
  • 조직 만들기는 사용자마다 시간당 몇 개로 제한됩니다.

멤버

메서드경로권한본문 또는 쿼리
GET/v1/orgs/:id/members소유자, 관리자?limit=50&cursor=…, 최대 200. 행: userId, role, status, joinedAt, email, displayName, avatarUrl.
PATCH/v1/orgs/:id/members/:userId소유자, 관리자{ role?, status? }: admin 또는 member, active 또는 suspended. 소유자의 행에는 쓸 수 없습니다.
DELETE/v1/orgs/:id/members/:userId소유자, 관리자소유자에게는 쓸 수 없습니다. 그 사람을 조직의 모든 워크스페이스에서도 제거합니다.

워크스페이스

메서드경로권한본문 또는 쿼리
POST/v1/orgs/:id/workspaces소유자, 관리자{ name, slug?, description?, settings? }. 201을 반환합니다. 슬러그는 조직 안에서 고유합니다.
GET/v1/orgs/:id/workspaces멤버멤버는 자신의 워크스페이스를, 소유자와 관리자는 모든 워크스페이스를 봅니다. ?includeArchived=true를 붙이면 보관된 워크스페이스도 포함됩니다.
GET/v1/workspaces누구나조직과 관계없이 내가 속한 모든 워크스페이스입니다.
GET/v1/workspaces/:id워크스페이스 멤버
PATCH/v1/workspaces/:id워크스페이스 관리자{ name?, description?, settings? }
POST/v1/workspaces/:id/archive소유자, 관리자보관합니다. 되돌릴 수 있으며 아무것도 삭제되지 않습니다.
POST/v1/workspaces/:id/unarchive소유자, 관리자보관을 해제합니다.

워크스페이스 멤버

메서드경로권한본문 또는 쿼리
GET/v1/workspaces/:id/members워크스페이스 멤버?limit&cursor. 멤버는 userId, role, displayName, avatarUrl, addedAt을 봅니다. 관리자는 status와 creditCap도 봅니다. 명단에 이메일 주소는 없습니다.
POST/v1/workspaces/:id/members워크스페이스 관리자{ userId, role }이며, role은 admin 또는 member입니다. 그 사람은 이미 조직의 활성 멤버여야 합니다(400 not_org_member). 새로운 사람을 들이려면 초대하세요.
PATCH/v1/workspaces/:id/members/:userId워크스페이스 관리자{ role?, status?, creditCap? }. creditCap은 멤버의 사용 한도이며, 한도가 없으면 null입니다.
DELETE/v1/workspaces/:id/members/:userId워크스페이스 관리자그 사람을 이 워크스페이스에서만 제거합니다. 조직에는 남습니다.

조직의 소유자와 관리자는 목록에 나오지 않아도 조직의 모든 워크스페이스에서 관리자입니다. 이들 중 한 명을 워크스페이스에 명시적으로 추가하면 대신 그 명시적인 역할이 적용됩니다. 이렇게 하면 조직 관리자가 어떤 반에서는 일반 멤버가 될 수 있습니다.

초대

초대 하나는 이메일 주소 하나를 대상으로 합니다. 초대 링크에는 이메일에만 있는 토큰이 담기며, 초대받은 사람은 로그인하기 전에 무엇에 초대되었는지 확인할 수 있습니다.

메서드경로권한본문 또는 쿼리
POST/v1/orgs/:id/invitations소유자, 관리자, 그리고 조직이 허용하면 자기 워크스페이스로 초대하는 워크스페이스 관리자{ emails, orgRole?, workspaceId?, workspaceRole? }. 주소는 최대 200개이며, 소문자로 바뀌고 중복은 제거됩니다. 주소마다 한 행씩 { email, status, link? }를 담아 201을 반환합니다.
GET/v1/orgs/:id/invitations위와 같은 사람?status=(open, accepted, revoked, expired), workspaceId, limit, cursor. 토큰은 반환하지 않습니다.
DELETE/v1/invitations/:id위와 같은 사람철회합니다. 링크가 더 이상 작동하지 않습니다. 수락된 초대에는 거부됩니다.
POST/v1/invitations/:id/resend위와 같은 사람새 토큰과 만료 시각을 발급하고 다시 보냅니다. 이전 링크는 더 이상 작동하지 않습니다.
GET/v1/invitations/by-token/:token공개초대받은 사람이 결정하는 데 필요한 정보입니다. orgName, kind, vocabulary, inviterName, workspaceName, 가려진 이메일 주소, expiresAt, state. IP 주소별로 제한됩니다.
POST/v1/invitations/:token/accept로그인한 초대 대상자계정의 이메일이 초대와 일치해야 합니다(400 email_mismatch). 두 번째 수락은 거부됩니다.
  • 주소마다 자체 행이 있습니다. status는 sent, link_only, failed 중 하나이며, 이메일을 보내지 못한 주소에는 항상 link가 있습니다. 메일 공급자가 없는 설치 환경은 모든 주소를 link_only로 반환합니다. 이 링크를 표시하세요. 어느 경우든 초대는 만들어져 있고, 링크가 없으면 아무도 초대에 들어갈 수 없습니다.
  • 초대는 14일 뒤에 만료되며, 조직은 하루에 500개까지 보낼 수 있습니다(429 bulk_invite_cap_exceeded).
  • 같은 주소를 다시 초대하면 두 번째 초대를 만드는 대신 열려 있는 초대를 새 토큰으로 바꿉니다.
  • 이미 멤버인 사람을 초대하면 초대는 사용 처리되지만, 그 사람의 역할이 바뀌거나 정지가 해제되지는 않습니다.

참여 코드

참여 코드는 8자로, 교실에서 소리 내어 읽기 좋은 길이입니다. 이 코드로는 워크스페이스 하나에 일반 멤버로만 참여할 수 있고, 정지는 해제되지 않으며, 조직이 허용한 이메일 도메인 제한이 적용됩니다.

메서드경로권한본문 또는 쿼리
GET/v1/workspaces/:id/join-code워크스페이스 관리자{ code, enabled, rotatedAt, rotatedBy }. 만든 코드가 없으면 null입니다.
POST/v1/workspaces/:id/join-code워크스페이스 관리자{ action }: rotate, enable, disable. 코드가 한 번도 없었던 워크스페이스를 켜면 코드가 만들어집니다. 재발급하면 코드가 바뀌고 이전 코드는 즉시 작동하지 않습니다.
POST/v1/workspaces/join로그인한 누구나{ code }. 소리 내어 읽은 형태도 받습니다. BCDF-GHJK, 소문자, 숫자 0 대신 쓴 O처럼 잘못 듣기 쉬운 글자도 됩니다. 계정마다 분당 10회, IP 주소마다 분당 30회로 제한됩니다.

워크플로 하나 공유

권한 부여는 한 사람에게 워크플로 하나에 대한 액세스를 줍니다. 액세스를 더할 수만 있고 뺄 수는 없습니다.

메서드경로권한본문 또는 쿼리
GET/v1/workflows/:id/collaborators워크플로를 볼 수 있는 누구나{ userId, name, avatarUrl, role, createdAt } 행이며, 이메일 주소는 없습니다.
POST/v1/workflows/:id/collaborators아래 참고{ userId } 또는 { email } 중 정확히 하나와 role: viewer 또는 editor. 201을 반환합니다. 분당 20명 추가로 제한됩니다.
PATCH/v1/workflows/:id/collaborators/:userIdPOST와 같음{ role }
DELETE/v1/workflows/:id/collaborators/:userIdPOST와 같음, 또는 본인누구나 자신의 액세스 권한을 제거할 수 있습니다.
GET/v1/workflows/shared-with-me로그인한 누구나내 워크스페이스 밖에서 내가 권한을 받은 워크플로이며, 각각 grantedRole이 붙습니다. 최신순, 최대 200개입니다.
GET/v1/workflows/:id/access워크플로를 볼 수 있는 누구나{ access, workspaceId, visibility, canChangeVisibility, canShare, canRun }. 그래프는 반환하지 않습니다.
  • 공유할 수 있는 사람: 만든 사람, 관리자가 멤버의 작업을 편집할 수 있는 워크스페이스의 워크스페이스 관리자, 그리고 공동 작업자가 초대할 수 있는 워크스페이스에서 그 워크플로를 편집할 수 있는 모든 사람입니다.
  • 이메일로 추가하면 조직과 관계없이 모든 계정의 주소와 대조합니다. 404는 계정이 없다는 뜻이며, 그 이상은 공개하지 않습니다.
  • 워크스페이스 밖의 사람은 편집 권한을 받아도 보기만 할 수 있습니다. 실행하려면 활성 멤버십이 필요하므로, 외부 공동 작업자는 워크스페이스의 크레딧을 쓸 수 없습니다.
  • 워크플로를 만든 사람이나 나 자신에게는 권한을 줄 수 없습니다(400). 권한 부여는 수락 단계 없이 바로 적용됩니다.
  • canChangeVisibility, canShare, canRun은 서로 별개의 규칙입니다. 하나로 다른 하나를 추측하지 마세요.

전혀 접근할 수 없는 워크플로에는 존재하지 않는 워크플로와 똑같이 404가 반환됩니다. 이미 볼 수 있는 워크플로에 더 많은 권한이 필요할 때만 403이 반환됩니다. 워크스페이스에 속한 워크플로를 실행하려면 편집 권한과 활성 멤버십이 필요합니다.

감사 로그

메서드경로권한본문 또는 쿼리
GET/v1/orgs/:id/audit소유자, 관리자?cursor&limit, 최신순. 각 항목: { id, workspaceId, action, targetType, targetId, details, createdAt, actor }. 시스템이 수행한 작업이면 actor는 null입니다.

감사 로그는 조직이 정지된 동안에도 읽을 수 있습니다. action은 제품과 함께 늘어나는 열린 목록입니다. 아는 작업은 표시하고, 나머지는 원래 값을 그대로 보여 주세요.

역할과 설정

범위역할할 수 있는 일
조직owner관리자가 할 수 있는 모든 일에 더해 소유권 이전과 조직 삭제. 정확히 한 명뿐입니다. 소유자는 정지, 제거, 강등될 수 없습니다.
조직admin설정, 소유자를 제외한 멤버, 워크스페이스 관리. 모든 워크스페이스의 관리자입니다.
조직member조직에 소속되어, 자신이 추가된 워크스페이스에서 작업.
워크스페이스admin워크스페이스의 설정과 멤버 관리.
워크스페이스member워크스페이스에서 작업.

설정은 계층으로 적용됩니다. 워크스페이스 설정이 조직 설정보다 우선하고, 조직 설정은 조직 종류의 기본값보다 우선합니다. 설정되지 않은 키는 다음 계층의 값을 따르며, false도 실제 값으로 취급됩니다.

키값제어 대상
admin_accessview 또는 edit관리자가 멤버의 워크플로로 할 수 있는 일.
default_workflow_visibilityprivate 또는 workspace새 워크플로의 공개 범위.
member_access_to_sharedview 또는 edit멤버가 워크스페이스에 공유된 워크플로로 할 수 있는 일.
members_can_create_projects불리언멤버가 프로젝트를 만들 수 있는지 여부.
member_caps_enabled불리언멤버별 크레딧 한도를 적용할지 여부.
personal_space_enabled불리언멤버가 개인 공간을 가질 수 있는지 여부.
workspace_admins_can_invite불리언워크스페이스 관리자가 새 사람을 조직에 초대할 수 있는지 여부.
collaborators_can_invite불리언편집 권한이 있는 공동 작업자가 다른 공동 작업자를 초대할 수 있는지 여부.

조직에만 있는 설정으로 ["school.example"] 같은 allowed_email_domains와 { "workspace": "Cohort" } 같은 vocabulary_overrides도 있습니다. 둘 다 수정하면 통째로 바뀝니다.

워크스페이스를 부르는 단어를 직접 정할 때, 그 단어가 문법상 남성형이면 vocabulary_overrides의 workspace_gender도 "m"으로 설정하세요. 예: { "workspace": "Grupo", "workspace_gender": "m" }. 그러면 워크스페이스를 언급하는 히브리어와 브라질 포르투갈어 문장이 그 단어에 맞게 일치합니다. "m"이 없으면 여성형으로 취급합니다. 이 설정은 API에만 있습니다.

학교의 초기 설정은 다음과 같습니다. 관리자는 편집 가능, 워크플로는 비공개, 멤버는 공유된 작업을 보기만 가능, 멤버는 프로젝트를 만들 수 없음, 한도 사용, 개인 공간 사용, 워크스페이스 관리자는 초대 가능, 공동 작업자는 초대 불가. 팀의 초기 설정은 다음과 같습니다. 관리자는 보기만 가능, 워크플로는 워크스페이스에 공개, 멤버는 공유된 작업을 편집 가능, 멤버는 프로젝트를 만들 수 있음, 한도 미사용, 개인 공간 사용, 두 초대 설정 모두 사용.

예산과 사용량

조직은 멤버의 작업 비용을 세 단계로 지불하며, 단계마다 범위가 좁아집니다.

  1. 풀. 조직은 자체 결제를 통해 조직 전체가 함께 쓰는 하나의 풀에 선불 크레딧 팩을 구매합니다.
  2. 할당. 소유자는 풀에서 워크스페이스의 예산으로 크레딧을 옮깁니다. 풀은 워크스페이스가 받은 만큼 정확히 줄어듭니다. 크레딧을 풀로 되돌릴 수도 있지만, 워크스페이스가 이미 예약했거나 사용한 양 아래로는 줄일 수 없습니다.
  3. 멤버 한도. 워크스페이스 안에서 관리자는 한 멤버가 쓸 수 있는 양에 한도를 정할 수 있습니다. 한도는 워크스페이스 설정에서 켠 경우에만 적용되며, 그 워크스페이스에서 작업하는 조직 관리자에게는 적용되지 않습니다.

워크스페이스 안에서 한 작업은 워크스페이스가 지불하며, 멤버 자신의 크레딧은 쓰이지 않습니다. 모든 단계의 여유분은 할당량에서 예약량과 사용량을 뺀 값이며, 이를 넘을 실행은 시작하기 전에 402 budget_exceeded 또는 402 member_cap_exceeded로 거부됩니다.

라우트권한기능
GET /v1/orgs/:id/credits소유자, 조직 관리자풀, 누적 구매액, 그리고 각 워크스페이스의 할당량과 예약·사용된 크레딧.
POST /v1/orgs/:id/credits/checkout소유자선불 팩 하나의 결제 URL. 본문 { packId }.
POST /v1/orgs/:id/workspaces/:wsId/allocate소유자풀과 워크스페이스 사이에서 크레딧을 옮깁니다. 본문 { delta }. 새 여유분을 반환합니다.
GET /v1/workspaces/:id/budget멤버내 사용량, 한도, 여유분. 관리자는 멤버별 행도 받습니다.
GET /v1/orgs/:id/usage소유자, 조직 관리자조직의 사용량 보고서.
GET /v1/workspaces/:id/usage멤버, 워크스페이스 관리자워크스페이스 하나의 같은 보고서.

환불과 결제 분쟁이 생기면 조직의 풀에서 비율에 맞춰 크레딧을 회수하며, 0 아래로는 내려가지 않습니다. 조직을 삭제하려면 먼저 모든 워크스페이스 할당량을 회수해야 합니다.

자동화는 워크스페이스의 크레딧을 씁니다. Webhook 트리거 URL은 Bearer 자격 증명입니다. URL을 가진 사람은 누구나 실행을 시작할 수 있고, 워크스페이스에 있는 워크플로의 실행은 그 워크스페이스가 지불합니다. Webhook, 일정, Telegram에서 시작된 모든 자동 실행은 먼저 트리거를 만든 사람이 여전히 그 워크플로를 실행할 수 있는지 확인합니다. 더 이상 실행할 수 없으면 자동화가 멈추고, 실행 기록에는 코드가 run_requires_authenticated_member인 실패 항목 하나가 표시됩니다.

사용량 보고서

두 사용량 라우트는 기간 동안 누가 무엇에 얼마를 썼는지 알려 줍니다.

쿼리의미
from, to양 끝을 포함하는 날짜, YYYY-MM-DD. 기간은 최대 366일이며, 기본값은 최근 30일입니다.
tz일별 집계에 쓰는 IANA 시간대. 기본값은 UTC입니다.
groupByworkspace(조직 전용), member, model, day, 또는 개별 실행을 최신순으로 cursor로 페이지를 나눠 보여 주는 none.
workspaceId, userId보고서 범위를 좁힙니다.
formatcsv를 보내면 보고서를 CSV로 반환합니다.
  • 각 행에는 크레딧 수치가 세 개 있습니다. credits는 지금까지 실행에 든 비용으로, 끝난 실행은 확정된 금액, 진행 중인 실행은 잡혀 있는 예약분입니다. settledCredits와 inFlightCredits는 그 합계를 나눈 값입니다.
  • 워크스페이스에 남은 양보다 비용이 더 든 종량제 실행은 여유분까지만 청구되고, 나머지는 플랫폼이 부담합니다. 합계에는 이것이 platformAbsorbedCredits로 보고되며, settledCredits에서 platformAbsorbedCredits를 뺀 값이 예산에 실제로 반영된 양입니다. 예산으로 충당하지 못한 승인된 앱의 추가 요금도 플랫폼이 부담하며, appMarkupAbsorbedCredits로 따로 보고됩니다.
  • 그룹이 5,000개를 넘는 보고서는 truncated: true를 반환합니다. 잘리는 것은 그룹별 행뿐이며, 합계는 전체 기간을 포함합니다.
  • 일반 멤버는 자신의 실행만 볼 수 있고, 멤버별 그룹화는 거부됩니다. 워크스페이스 관리자는 모든 사람을 보고 userId로 거를 수 있습니다. 조직 보고서는 소유자와 조직 관리자용입니다.
  • CSV 내보내기는 UTF-8, RFC 4180 형식이며, 줄 끝은 CRLF이고 바이트 순서 표시는 없습니다. =, +, -, @로 시작하는 셀은 스프레드시트가 실행하지 못하도록 앞에 아포스트로피를 붙여 감쌉니다. 내보내기는 사용자마다 분당 10회로 제한되며 감사 로그에 기록됩니다.
  • 멤버가 계정을 삭제하면 그 사람의 실행 기록도 함께 사라지고, 보고서에는 빈 구간이 생깁니다. 그 사람의 워크플로와 프로젝트는 워크스페이스에 남습니다.

사용량 보고서가 없는 인스턴스는 404를 반환하고, 보고 기능을 아직 쓸 수 없는 동안에는 503 billing_unavailable을 반환합니다.

오류

상태코드발생 시점
400validation_error필드가 잘못되었거나, 커서 형식이 잘못되었거나, 그 행에 허용되지 않는 변경이거나, 사용량 보고서의 날짜, 시간대, 기간, 그룹화가 잘못되었습니다.
400terms_requiredacceptTerms: true 없이 학교를 만들었습니다.
400not_org_member조직의 활성 멤버가 아닌 사람을 워크스페이스에 추가하려 했습니다.
400token_workspace_mismatch한 워크스페이스에 연결된 토큰에 다른 워크스페이스를 지정한 헤더가 붙었습니다.
400join_code_invalid그런 코드가 없거나, 코드가 꺼져 있거나, 그 워크스페이스가 보관되었습니다. 세 경우 모두 같은 응답입니다.
400invitation_expired, invitation_revoked, invitation_accepted초대가 14일을 넘겼거나, 철회되었거나, 이미 수락되었습니다.
400email_mismatch로그인한 계정의 이메일이 초대받은 이메일이 아닙니다.
401unauthorized유효한 자격 증명이 없습니다.
403insufficient_role멤버이지만 그 작업을 하기에는 역할이 낮습니다.
403member_suspended내 멤버십이 정지되었습니다.
403org_not_active조직이 대기 중이거나 정지되었는데, 작업이 무언가를 변경하려 합니다.
403workspace_archived보관된 워크스페이스에 쓰려고 했습니다.
403not_a_member헤더가 내가 선택할 수 없는 워크스페이스를 지정합니다.
403domain_not_allowed조직이 목록에 있는 이메일 도메인만 받습니다.
404not_found그런 조직, 워크스페이스, 멤버가 없거나, 내가 멤버가 아닌 곳입니다.
404invitation_not_found그 토큰에 해당하는 초대가 없습니다. 조직이 활성 상태가 아닌 경우도 포함됩니다.
409name_taken보낸 슬러그가 사용 중입니다.
409already_a_member그 사람은 이미 워크스페이스에 있습니다.
409owner_cannot_leave나가기 전에 소유권을 이전하세요.
409has_active_workspaces조직을 삭제하기 전에 모든 워크스페이스를 보관하세요.
429rate_limit_exceeded조직 만들기, 참여 시도, CSV 내보내기가 너무 많습니다.
429bulk_invite_cap_exceeded조직이 하루 초대 한도에 도달했습니다.
503billing_unavailable이 인스턴스에서는 아직 사용량 보고를 쓸 수 없습니다.
503audit_unavailableCSV 내보내기를 감사 로그에 기록하지 못해 거부되었습니다. 다시 시도하세요.

SDK, CLI, MCP에서 사용

  • SDK: client.organizations와 client.workspaces가 이 엔드포인트를 다루며, 보고서용 usage, usageRows, usageCsv도 포함합니다. client.me()에는 조직 필드가 담깁니다.
  • CLI: nodaro org와 nodaro workspace입니다. 예를 들어 nodaro org invite <orgId> --email ada@school.example --workspace <id>, nodaro org usage <orgId> --from 2026-09-01 --to 2026-09-30 --group-by member --csv > september.csv가 있습니다. 초대 명령은 주소마다 한 줄씩 출력하며, 이메일을 보내지 못한 주소에는 링크도 함께 출력합니다.
  • MCP: list_workspaces와 select_workspace 도구입니다. 선택은 세션이 바뀌어도 기억되며, 세션마다 다시 확인합니다. 이 도구를 쓰는 OAuth 앱에는 workspaces:read와 workspaces:write 스코프가 필요합니다.

전체 명령과 메서드 목록은 CLI와 SDK에서 확인하세요.

자주 묻는 질문

Nodaro API 요청을 워크스페이스에서 실행되게 하려면 어떻게 하나요?

X-Nodaro-Workspace 헤더에 워크스페이스 ID를 보내세요. 이 헤더가 목록이 어느 워크스페이스를 읽을지, 새로 만든 것이 어디에 저장될지를 정합니다. SDK에서는 createClient({ workspaceId }) 또는 client.withWorkspace(id)를, CLI에서는 --workspace를 사용하세요.

워크스페이스 헤더를 잘못 보내면 내 작업이 가려지거나 다른 사람의 작업에 닿을 수 있나요?

아니요. 헤더는 범위를 정할 뿐 액세스 권한을 정하지 않습니다. ID로 무언가를 읽고, 바꾸고, 삭제하고, 실행하는 요청은 그 객체가 속한 워크스페이스를 따르며, 내가 속하지 않은 워크스페이스에는 403 not_a_member가 반환됩니다.

API 토큰을 워크스페이스 하나에 묶을 수 있나요?

네. 로그인한 세션에서 PATCH /v1/api-tokens/:id에 workspaceId를 보내 연결하세요. 그러면 토큰은 모든 요청에서 그 헤더를 보낸 것처럼 작동하고, 다른 워크스페이스를 지정한 헤더에는 400 token_workspace_mismatch가 반환됩니다.

만들기 요청에 403 personal_space_disabled가 반환되는 이유는 무엇인가요?

조직이 멤버에게 워크스페이스 안에서만 작업을 만들도록 요구하기 때문입니다. 내 워크스페이스 중 하나를 지정한 X-Nodaro-Workspace 헤더를 보내면 같은 호출이 성공합니다.

셀프 호스팅 설치에서도 조직을 사용할 수 있나요?

아니요. 조직은 인스턴스별로 켜는 Nodaro Cloud 기능입니다. 셀프 호스팅 빌드에는 조직이 포함되지 않으며, 워크스페이스 헤더도 무시됩니다.

초대가 이메일로 발송되지 않고 링크로 돌아온 이유는 무엇인가요?

설치 환경에 메일 공급자가 없거나 발송이 실패했기 때문입니다. 어느 경우든 초대는 만들어져 있으므로, 반환된 링크를 직접 그 사람에게 보내세요.

최종 업데이트

목차