조직
조직 카테고리의 API 작업 14개를 다룹니다.
| 메서드 | 경로 | 설명 |
|---|---|---|
| GET | /v1/orgs | — |
| POST | /v1/orgs | org 생성 |
| PATCH | /v1/orgs/{orgSlug} | org의 표시 이름 변경 (runlot org rename) |
| DELETE | /v1/orgs/{orgSlug} | org 삭제 (runlot org delete) |
| GET | /v1/orgs/{orgSlug}/notifications | 최근 알림 |
| GET | /v1/orgs/{orgSlug}/members | 조직 멤버 목록 조회 (runlot org members) |
| POST | /v1/orgs/{orgSlug}/members | 기존 사용자를 멤버로 추가(운영 및 자동화용) |
| GET | /v1/orgs/{orgSlug}/invites | 대기 중인 초대(runlot member invites) |
| POST | /v1/orgs/{orgSlug}/invites | 이메일로 초대(runlot member invite) |
| DELETE | /v1/orgs/{orgSlug}/invites/{inviteId} | 초대 취소(runlot member uninvite) |
| GET | /v1/invites/{token} | 초대 미리보기(인증 없음) |
| POST | /v1/invites/{token}/accept | 초대 수락 |
| PUT | /v1/orgs/{orgSlug}/members/{userId} | 역할 변경(runlot org set-role) |
| DELETE | /v1/orgs/{orgSlug}/members/{userId} | 멤버 제거 또는 자진 탈퇴(runlot member rm, runlot member leave) |
GET /v1/orgs
operationId listOrgs
| 상태 코드 | 설명 | 응답 본문 |
|---|---|---|
| 200 | 소속 조직 | object |
| 401 | — | — |
POST /v1/orgs
생성자가 admin이 됩니다. 개인 계정은 단순히 1인 조직이므로 별도의 경로가 없습니다.
operationId createOrg
요청 본문: application/json · object
| 상태 코드 | 설명 | 응답 본문 |
|---|---|---|
| 201 | 생성된 조직 | Org |
| 401 | — | — |
| 409 | — | — |
PATCH /v1/orgs/{orgSlug}
admin 이상의 권한이 필요합니다. org.rename으로 감사 기록됩니다.
여기서는 표시 이름만 변경할 수 있습니다. 슬러그는 주소의 일부입니다 — <project>.<slug>.runlot.app, 인증서 SAN, 클론 URL, 그리고 저장소에 커밋된 runlot.json의 "org" 필드 — 이므로 이름을 변경할 수 없습니다.
operationId updateOrg
요청 본문: application/json · object
| 상태 코드 | 설명 | 응답 본문 |
|---|---|---|
| 200 | 수정된 조직 | OrgMembership |
| 400 | — | — |
| 403 | — | — |
| 404 | — | — |
DELETE /v1/orgs/{orgSlug}
admin 이상의 권한이 필요합니다. 이 작업은 되돌릴 수 없습니다.
confirm 필드에는 정확한 조직 슬러그를 입력해야 합니다(앞뒤 공백은 제거됩니다).
삭제는 두 단계로 이루어지며, 대기하는 것은 첫 번째 단계뿐입니다. 응답은 조직을 삭제됨으로 표시합니다: 조직 목록에서 사라지고, 조직 범위의 모든 경로가 404를 반환하며, 대기 중인 초대는 더 이상 작동하지 않고, 슬러그는 즉시 재사용할 수 있게 됩니다. 데이터는 보존 기간이 지난 후 삭제되며, 기본값은 한 달입니다. 응답의 purgeAfter가 바로 그 시점입니다 — 보존 기간이 변경될 수 있으므로 직접 계산하지 말고 응답에서 읽으세요.
삭제는 조직이 비어 있을 때만 성공합니다. 프로젝트, 도메인, 저장소, 또는 DNS 존이 남아 있으면 응답은 409 org_not_empty이며, 엔벨로프의 details.holdings에 종류별 개수와 몇 가지 이름이 나열됩니다. 이미 삭제한 프로젝트는 집계되지 않습니다 — 이러한 프로젝트는 조직보다 먼저, 자체 보존 기간에 따라 사라집니다.
그 외 거부되는 경우가 두 가지 더 있습니다: 개인 조직은 personal_org를 반환하며(최초 로그인 시 생성된 조직으로 삭제할 수 없음), 유료 구독이 활성 상태이면 active_subscription을 반환합니다 — 먼저 구독을 취소하세요.
org.delete 감사 이벤트는 조직보다 오래 남으며, target에 슬러그를 유지합니다.
operationId deleteOrg
요청 본문: application/json · object
| 상태 코드 | 설명 | 응답 본문 |
|---|---|---|
| 202 | 삭제됨으로 표시 — 이제 모든 화면에서 사라졌으며, 데이터는 purgeAfter 이후 삭제됩니다 | OrgDeleted |
| 400 | — | — |
| 403 | — | — |
| 404 | — | — |
| 409 | 비어 있지 않음 (org_not_empty) · 개인 org (personal_org) · 활성 구독 (active_subscription) | Error |
GET /v1/orgs/{orgSlug}/notifications
조직의 제한, 백업, 복원 이벤트를 최신순으로 표시합니다.
sentAt이 설정되어 있으면 이메일도 함께 발송된 것입니다. 이 값이 없는 행은 아직 대기 중이거나 보낼 주소가 없는 경우입니다 — 비공개 GitHub 이메일로 로그인한 계정은 등록된 이메일이 없으며, 이 목록이 유일한 알림 경로입니다.
viewer 이상이 필요합니다.
operationId listNotifications
| 매개변수 | 위치 | 필수 | 타입 | 설명 |
|---|---|---|---|---|
limit | query | 아니오 | 정수 | — |
| 상태 코드 | 설명 | 응답 본문 |
|---|---|---|
| 200 | 알림 목록 조회 | object |
| 403 | — | — |
| 404 | — | — |
GET /v1/orgs/{orgSlug}/members
member 이상의 권한이 필요합니다.
operationId listMembers
| 상태 코드 | 설명 | 응답 본문 |
|---|---|---|
| 200 | 멤버 목록 | object |
| 403 | — | — |
| 404 | — | — |
POST /v1/orgs/{orgSlug}/members
이것은 초대가 아닙니다. 사용자는 이미 최소 한 번 로그인한 상태여야 하며, provider + subject로 식별됩니다. 해당 사용자가 없으면 404 user_not_found를 반환합니다. 이미 멤버인 경우 409 already_member를 반환합니다 — 역할을 변경하려면 PUT을 사용하세요.
이메일로 누군가를 초대하려면 대신 POST …/invites를 사용하세요. 이 엔드포인트는 제공자의 subject id를 이미 알고 있는 자동화를 위한 것입니다.
admin 이상의 권한이 필요합니다. 감사 로그에 member.add로 기록됩니다.
operationId addMember
요청 본문: application/json · object
| 상태 코드 | 설명 | 응답 본문 |
|---|---|---|
| 201 | 멤버가 추가되었습니다 | Member |
| 400 | — | — |
| 403 | — | — |
| 404 | 조직이 존재하지 않거나 사용자가 존재하지 않습니다(user_not_found) | Error |
| 409 | 이미 멤버입니다(already_member) | Error |
GET /v1/orgs/{orgSlug}/invites
admin 이상의 권한이 필요합니다. 초대 목록에는 아직 조직에 속하지 않은 사람들의 이메일 주소가 담겨 있으므로, 멤버 목록보다 더 높은 역할이 필요합니다.
수락되었거나 취소된 초대는 표시되지 않습니다 — 해당 이력은 감사 로그에 남아 있습니다. 만료된 초대는 표시되므로 관리자가 다시 보낼 수 있습니다.
operationId listInvites
| 상태 코드 | 설명 | 응답 본문 |
|---|---|---|
| 200 | 초대 목록 | object |
| 403 | — | — |
| 404 | — | — |
POST /v1/orgs/{orgSlug}/invites
admin 이상의 권한이 필요합니다. 이메일은 즉시 발송되지 않고 대기열에 추가됩니다 — sentAt이 비어 있으면 아직 발송되지 않은 것입니다.
동일한 주소로 다시 호출하면 초대가 재전송됩니다: 기존 초대가 새 토큰과 만료 시간으로 업데이트되며(역할이 변경될 수도 있음), 이 경우 200을 반환합니다. 완전히 새로운 초대는 201을 반환합니다.
이미 멤버인 주소는 409 already_member를 반환합니다. 대기 중인 초대가 너무 많으면 409 too_many_invites를 반환합니다.
초대는 7일간 유효하며, 1회용이고, 언제든지 취소할 수 있습니다. 감사 로그에 member.invite로 기록됩니다.
operationId createInvite
요청 본문: application/json · object
| 상태 코드 | 설명 | 응답 본문 |
|---|---|---|
| 200 | 기존 초대 재전송 | Invite |
| 201 | 새 초대 | Invite |
| 400 | — | — |
| 403 | — | — |
| 404 | — | — |
| 409 | 이미 멤버임(already_member) 또는 대기 중인 초대가 너무 많음(too_many_invites) | Error |
DELETE /v1/orgs/{orgSlug}/invites/{inviteId}
admin 이상의 권한이 필요합니다. 아직 발송되지 않은 이메일은 발송되지 않습니다 — 취소하면 발송 대기열에서도 제거됩니다. 이미 수락되었거나 취소된 초대는 404를 반환합니다. 감사 로그에 member.uninvite로 기록됩니다.
operationId revokeInvite
| 상태 코드 | 설명 | 응답 본문 |
|---|---|---|
| 204 | 취소됨 | — |
| 403 | — | — |
| 404 | — | — |
GET /v1/invites/{token}
인증이 필요하지 않습니다. 초대 링크를 받은 사람은 아직 로그인하지 않은 상태이며 초대의 목적을 확인할 수 있어야 합니다. 토큰은 32바이트 무작위 값이므로 추측할 수 없으며, 열어봐도 조직 이름만 표시됩니다.
초대 상태는 오류가 아니라 값입니다(state). 따라서 클라이언트는 만료된 링크와 잘못된 링크를 구분할 수 있습니다.
알 수 없는 토큰은 404를 반환합니다 — 오래전에 취소된 토큰과 같은 응답입니다.
operationId getInvite
| 상태 코드 | 설명 | 응답 본문 |
|---|---|---|
| 200 | 초대 | InviteView |
| 404 | — | — |
POST /v1/invites/{token}/accept
로그인이 필요합니다. 로그인한 계정의 이메일이 초대받은 주소와 일치할 필요는 없습니다 — 비공개 GitHub 이메일로 로그인한 계정은 등록된 이메일이 전혀 없을 수 있습니다. 대신 초대는 7일간 유효하며, 1회용이고, 언제든지 취소할 수 있으며, 감사 기록에는 초대받은 주소와 수락한 계정이 모두 남습니다.
해당 사용자가 이미 멤버인 경우 역할은 변경되지 않습니다(alreadyMember: true).
감사 로그에 member.accept로 기록됩니다.
operationId acceptInvite
| 상태 코드 | 설명 | 응답 본문 |
|---|---|---|
| 200 | 수락됨 | object |
| 401 | — | — |
| 404 | — | — |
| 409 | 이미 수락됨(invite_used), 취소됨(invite_revoked), 또는 만료됨(invite_expired) | Error |
PUT /v1/orgs/{orgSlug}/members/{userId}
admin 이상의 권한이 필요합니다. 마지막 admin은 강등할 수 없습니다(409 last_admin), 본인도 예외가 아닙니다 — 조직에는 항상 관리할 수 있는 사람이 있어야 합니다. 감사 로그에 member.role로 기록됩니다.
operationId setMemberRole
요청 본문: application/json · object
| 상태 코드 | 설명 | 응답 본문 |
|---|---|---|
| 200 | 변경된 멤버 | Member |
| 400 | — | — |
| 403 | — | — |
| 404 | — | — |
| 409 | 마지막 admin입니다(last_admin) | Error |
DELETE /v1/orgs/{orgSlug}/members/{userId}
다른 사람을 제거하려면 admin 이상의 권한이 필요하지만, 본인을 제거하는 것은 누구나 할 수 있습니다 — userId가 본인의 것이면 이는 조직을 나가는 것입니다.
마지막 admin은 제거될 수 없으며 나갈 수도 없습니다(409 last_admin). 감사 로그는 제거를 member.remove로, 나가기를 member.leave로 기록합니다.
operationId removeMember
| 상태 코드 | 설명 | 응답 본문 |
|---|---|---|
| 204 | 제거됨 | — |
| 403 | — | — |
| 404 | — | — |
| 409 | 마지막 admin입니다(last_admin) | Error |