멤버 그룹 관리 API
인사 시스템(HRIS)·학사 시스템(SIS) 등 조직의 원본 시스템이 가진 조직도와 구성원 정보를 에 자동으로 반영하는 API입니다. 조직 동기화(Directory Sync) API라고도 부릅니다.
그룹 유형과 그룹 이름은 조직이 직접 정의합니다. 본부·국·부서, 단과대학·학과, 지사·팀 등 어떤 체계를 쓰든 그대로 반영되며, 아래 예시에 나오는 이름은 설명을 위한 예시일 뿐입니다.
조직도(그룹의 생성·이름 변경·계층 이동·삭제)와 구성원(그룹 소속, 활성 여부, 커스텀 필드 값)을 동기화합니다. 원본 시스템이 현재 상태 전체를 보내면 서버가 기존 데이터와 대조해 필요한 변경만 적용하므로, "무엇이 바뀌었는지"를 보내는 쪽에서 계산할 필요가 없습니다.
- Base Path:
/v1/directory-sync - Host:
https://factchat-cloud.mindlogic.ai(API Gateway와 동일한 호스트입니다. 조직 서비스 도메인*.factchat.bot이 아닙니다) - 인증: API Gateway에서 발급한 API 키 (
Authorization: Bearer YOUR_API_KEY) - 사용 전 기능 활성화 요청이 필요합니다 (아래 사전 준비 참고)
사전 준비
1. 기능 활성화 요청
이 API는 기본적으로 꺼져 있습니다. 관리자 화면에는 이 기능을 켜는 설정이 없으므로, 마인드로직 담당자에게 활성화를 요청해주세요. 활성화 전에 호출하면
403이 반환됩니다.2. API 키 발급
웹사이트 좌측 하단의 API Gateway 메뉴에서 API 키를 발급합니다. 발급 절차는 API Gateway 인증 문서와 동일합니다. 메뉴가 보이지 않는다면 조직에서 API Gateway 기능이 꺼져 있는 것이므로, 마인드로직 담당자에게 함께 요청해주세요.
키는 관리자 권한이 있는 활성 계정으로 발급해야 합니다. 일반 구성원이나 그룹 관리자의 키로
호출하면
403이 반환됩니다. 모델 호출용으로 이미 발급한 키가 있더라도, 그 키의 소유자가
관리자가 아니면 이 API에는 사용할 수 없습니다.동기화 대상 조직은 호스트가 아니라 API 키로 결정됩니다. 키 하나로 조직 전체의 그룹과 구성원을
변경할 수 있으므로 비밀번호와 동일하게 취급해주세요. 이 API 호출에는 크레딧이 차감되지 않습니다.
스키마 조회
GET
/v1/directory-sync/schema/동기화 요청은 이름이 아니라 서버가 발급한 id로 대상을 지정합니다. 조직의 그룹 유형·그룹·커스텀 필드와 각각의 id를 반환합니다.
요청 헤더
응답 예시
여기서 받은
id 값을 동기화 요청에서 그대로 사용합니다. 새로 만든 그룹의 id는 다음 스키마 조회에서 확인할 수 있습니다.quota는 그룹에 설정된 크레딧 한도입니다. 한도가 없으면 null로 나갑니다. 동기화 요청의 quota와 모양이 같으므로, 받은 값을 그대로 되돌려 보내면 한도가 그대로 유지됩니다. → 그룹 크레딧 한도이 API는 그룹 유형과 커스텀 필드의 정의 자체는 만들지 않습니다. 관리자 화면의
그룹 관리에서 먼저 만들어 두어야 동기화 요청에서
참조할 수 있습니다.
동기화 실행
POST
/v1/directory-sync/조직도와 구성원을 동기화합니다. 두 가지를 한 요청에 함께 담을 수 있습니다.
요청 헤더
모든 값은 **JSON 요청 본문(body)**에 담습니다. 쿼리 파라미터는 사용하지 않습니다.
경로 끝의 슬래시(
/)는 생략할 수 없습니다. /v1/directory-sync처럼 보내면 404입니다.파라미터
최상위
dry_run
기본 boolean
false. true면 실제로 반영하지 않고 결과만 계산해 돌려줍니다. 처음 연동할 때는 반드시 이 모드로 먼저 확인해주세요.groups
조직도 항목 배열. → 조직도array | null
members
구성원 항목 배열. → 구성원array | null
groups와 members는 둘 다 선택입니다. 보낸 쪽만 처리되고, 생략한 쪽은 손대지 않습니다.조직도 (groups[])
배열의 각 항목이 그룹 하나입니다.
id
그룹의 id. 넣으면 기존 그룹 수정, 생략하면 새 그룹 생성입니다.string | null
parent
상위 그룹의 id.string | null
키를 생략하면 신규 생성은 최상위 그룹이 되고, 기존 그룹 수정은 상위 그룹이 그대로 유지됩니다. 최상위로 옮기려면
"parent": null을 명시해주세요. 이름과 같은 규칙(보내지 않은 값은 유지)입니다.그룹 유형에 트리 구조가 켜져 있어야 사용할 수 있습니다. 그룹 관리 화면에서 그룹 유형을 열면 트리(조직도) 구조 사용 설정이 있습니다. 이 설정을 켜야 그 유형의 그룹들이 상·하위 관계를 가질 수 있고, 꺼져 있으면 모든 그룹이 최상위로만 존재합니다. 꺼진 유형에
parent를 보내면 해당 항목이 parent is only allowed for is_hierarchical=True group types 사유로 실패합니다. 스키마 응답에는 이 설정이 나오지 않으니 화면에서 확인해주세요.name_i18n
언어별 그룹명. 예: object | null
{ "ko": "전략기획부", "en": "Strategy and Planning" }.ko_name / en_name
string | null
name_i18n 대신 쓸 수 있는 간편 입력입니다.신규 생성 시 한쪽만 보내면 나머지 언어에도 같은 값이 채워집니다. 기존 그룹 수정 시에는 보낸 언어만 반영되고, 보내지 않은 언어의 이름은 그대로 유지됩니다. 이름 필드를 아예 보내지 않으면(
parent만 바꾸는 경우 등) 그룹명은 변경되지 않습니다.quota
그룹의 크레딧 한도. 생략하면 한도를 손대지 않습니다. → 그룹 크레딧 한도object | null
_delete
boolean
true면 해당 그룹을 삭제합니다. id가 함께 있어야 하며, 구성원이나 하위 그룹이 남아 있으면 실패합니다.구성원 (members[])
배열의 각 항목이 구성원 한 명입니다.
match
대상 구성원을 찾는 기준입니다. 현재 object
required
email만 지원합니다. 예: { "email": "hong@example.com" }.invite
이메일이 일치하는 계정이 없을 때 초대를 만들 경우 사용합니다. object | null
{ "name": "홍길동" }처럼 이름을 함께 보냅니다. → 신규 구성원 초대groups
그룹 유형별 소속을 object | null
{ 그룹 유형 id: 그룹 id } 형태로 지정합니다. 한 사람이 하나만 속할 수 있는 유형이면, 같은 유형의 다른 그룹에서 자동으로 빠집니다.트리(조직도) 구조를 쓰는 유형에서는 그 사람이 실제로 속한 말단 그룹 하나만 지정합니다. 상위 조직은 조직도를 따라 함께 인정되므로, 본부·국을 따로 보낼 필요가 없습니다.
소속이 바뀌면 크레딧 차감 기준도 옮겨간 그룹으로 이어집니다. 개인에게 직접 건 한도가 아니라 그룹 한도를 따르던 구성원은 이동 후 목적지 그룹의 한도를 적용받습니다.
custom_fields
커스텀 필드 값을 object | null
{ 커스텀 필드 id: 값 } 형태로 지정합니다. 값은 반드시 문자열이어야 합니다 — 사번·학번처럼 숫자로 보이는 값도 "20240101"처럼 따옴표로 감싸주세요. 숫자를 그대로 보내면 요청 전체가 422로 거부됩니다.is_active
계정 활성 여부입니다.boolean | null
_delete
boolean
true면 해당 구성원을 탈퇴 처리합니다.전체 동기화
full_sync를 true로 보내면 요청에 담긴 명단이 곧 전체 명단이 됩니다. 원본 시스템에서 삭제된 항목을 자동으로 정리할 때 사용합니다.| 대상 | full_sync 동작 |
|---|---|
| 그룹 | 요청이 참조한 그룹 유형 범위 안에서, 요청에 등장하지 않은 그룹을 삭제 대상으로 처리 |
| 구성원 | 요청에 없는 활성 구성원을 비활성 처리 (삭제 아님) |
빈 배열을 보내지 마세요.
{"full_sync": true, "members": []}처럼 빈 배열을 보내면
"전원이 명단에서 빠졌다"는 뜻으로 해석되어, 조직의 활성 구성원이 모두 비활성 처리됩니다.
원본 시스템 조회가 실패했을 때 빈 배열을 그대로 전달하는 연동에서 특히 위험합니다.전송 전에 명단이 비어 있지 않은지 반드시 확인하고, 비어 있으면 요청 자체를 보내지 마세요.
dry_run으로 먼저 확인하면 deleted 건수로 영향 범위를 미리 볼 수 있습니다.full_sync는 요청에 실제로 담긴 도메인에만 적용됩니다. groups만 보내면 구성원은 손대지 않습니다.
groups·members 키를 둘 다 생략한 full_sync 요청은 400으로 거부됩니다. (키를 넣고 값만
빈 배열로 보내는 경우는 거부되지 않습니다 — 위 경고 참고.)관리자 계정은 비활성 대상에서 제외됩니다. 원본 명단이 잘못돼도 관리자가 로그인하지 못하는 상황은
생기지 않습니다.
그룹 크레딧 한도
그룹에 걸린 크레딧 한도를 조회하고 변경할 수 있습니다. 조회는 스키마 조회 응답의
groups[].quota, 변경은 동기화 요청의 그룹 항목에 넣는 quota이며 두 쪽 모양이 같습니다.group_credit_quota— 그룹 전체가 쓸 수 있는 크레딧 상한member_credit_quota— 그 그룹에 속한 구성원 1인의 상한
보낸 값에 따라 동작이 세 가지로 갈립니다.
| 보낸 값 | 동작 |
|---|---|
quota 키 생략 또는 "quota": null | 한도를 손대지 않음 |
{ "group_credit_quota": 500000 } | 보낸 값만 변경, 보내지 않은 값은 기존 그대로 |
{ "group_credit_quota": null, "member_credit_quota": null } | 한도 해제(무제한) |
판정 기준은 "요청에 두 값을 다 담았는지"가 아니라 "적용한 뒤의 상태"입니다. 두 값은 둘 다
설정돼 있거나 둘 다 해제돼 있어야 하고, 적용 결과 한쪽만 남으면 그 항목이
member_quota_required 또는 group_quota_required 사유로 실패합니다.- 두 값이 이미 설정된 그룹에 한쪽만 보내면 성공합니다. 보내지 않은 값은 그대로 유지됩니다.
- 한쪽만
null로 보내면 실패합니다. - 한도가 없던 그룹(신규 생성 포함)에 한쪽만 보내면 실패합니다. 처음 설정할 때는 두 값을 함께 보내야 합니다.
두 값을 모두
null로 보내면 그 그룹의 한도가 통째로 풀립니다. 한도가 없는 그룹이 스키마 응답에서
빈 객체가 아니라 null로 나가는 것도 이 때문입니다 — 받은 값을 그대로 되돌려 보내도 한도가
실수로 해제되지 않습니다.신규 그룹 생성과 한도 설정을 한 요청에 담을 수 있습니다.
id 없이 이름과 quota를 함께 보내면 그룹이 만들어진 직후 같은 요청 안에서 한도가 적용됩니다. 그룹을 먼저 만들고 화면에서 한도를 하나씩 넣을 필요가 없습니다.크레딧 한도는 기관 크레딧 요금제에서만 유효합니다. 팀·개인 요금제 조직에서 한도를 설정하려 하면
한도를 담은 항목이 모두
not_enterprise 사유로 실패합니다. 내부적으로는 무제한으로 바뀌기 때문에,
성공으로 보고하면 한도를 건 것으로 오해하게 됩니다.요금제 자체가 크레딧 한도 변경을 허용하지 않는 조직에서는 요청 전체가
403입니다.한도 적용이 실패해도 그룹의 생성·이름·계층 변경은 그대로 반영됩니다. 이때 같은 그룹이
created(또는 updated)와 failed에 함께 잡힙니다.한도 변경은 관리자 화면에서 바꾸는 것과 같은 경로를 지납니다. 변경 이력이 감사 로그에 남고, 유효 한도가 달라진 구성원에게는 알림이 갑니다.
신규 구성원 초대
구성원 항목에
invite를 넣으면, 이메일이 일치하는 계정이 없을 때 초대를 만들고 초대 메일을 보냅니다.- 계정을 바로 만들지 않고 초대로 가는 이유는 요청에 비밀번호가 없기 때문입니다. 받는 사람이 초대 메일에서 가입을 마치면 계정이 생깁니다.
groups·custom_fields는 기존 구성원과 같은 키를 씁니다. 초대에 함께 저장됐다가 수락 시점에 계정으로 넘어갑니다.- 그룹 유형 규칙(한 유형에 하나만 속할 수 있는지, 필수 유형인지)은 기존 구성원 배정과 같은 기준으로 검사합니다.
- 가입 폼의 필수 커스텀 필드는 초대에도 채워야 합니다. 빠지면 그 항목이 실패합니다.
- 새로 만든 초대는
created로 셉니다. - 이미 계정이 있거나 이미 대기 중인 초대가 있으면 실패가 아니라
skipped입니다. 같은 명단을 매일 보내도 리포트가 실패로 물들지 않습니다.
dry_run으로는 초대도 메일도 남지 않습니다. 실제 반영에서는 조직 변경이 저장된 뒤에 메일이 나갑니다.메일 발송이 실패해도 초대와 나머지 동기화 결과는 유지됩니다. 초대받은 사람이 메일을 받지 못했다면
관리자 화면의 멤버 초대에서 다시 보내주세요.
정원을 넘는 초대가 하나라도 있으면 요청 전체가
402로 거부됩니다. 같은 요청의 조직도 변경도
반영되지 않으므로, 명단을 고쳐 다시 보내주세요. 좌석은 이번에 실제로 새로 만들 초대만 셉니다
(이미 계정이 있거나 대기 중인 초대가 있는 이메일은 제외).SSO 전용 조직은 초대를 사용할 수 없어
403이 반환됩니다.요청·응답 예시
조직도 — 신설·이름 변경·폐지를 한 번에
항목 3개를 보냈는데
total이 2인 이유는, 조직도의 total이 요청 항목 중 삭제를 뺀 수이기 때문입니다. 삭제 항목은 deleted에만 반영됩니다. (구성원은 삭제 항목도 total에 포함됩니다.)구성원 — 소속 변경과 사번 갱신
전체 동기화 — 반영 전 영향 범위 확인
명단에 없는 활성 구성원 1명이 비활성 대상(
deleted)으로 잡혔음을 보여줍니다. dry_run이라 실제로는 반영되지 않았습니다.실행 결과 읽기
응답
data의 groups·members에 처리 건수가 담깁니다. 요청에서 생략한 도메인은 null입니다.| 필드 | 의미 |
|---|---|
total | 요청에 담긴 항목 수. 조직도는 삭제(_delete) 항목을 빼고 세고, 구성원은 포함해 셉니다 |
created | 새로 만든 수 |
updated | 실제로 값이 바뀐 수 |
deleted | 삭제·탈퇴·비활성 처리한 수 |
skipped | 바뀔 내용이 없거나 대상을 찾지 못해 건너뛴 수 |
failed | 실패한 수 |
failed_details | 실패한 항목과 사유 목록 |
total은 "요청에 담긴 항목 수"이지 "바뀐 항목 수"가 아닙니다. 나머지 필드의 합과 일치하지 않을 수 있습니다.요청에 없던 대상이
deleted로 잡히기 때문입니다 — 조직도의 삭제 항목과, full_sync로 비활성된
구성원이 그렇습니다. 예를 들어 명단에 있는 1명은 변경할 내용이 없고 명단에 없던 1명이 비활성되면
total: 1, skipped: 1, deleted: 1이 됩니다. 반대로 요청한 항목이 실패하면 total: 1, failed: 1처럼
created·updated가 모두 0일 수 있습니다.같은 내용을 다시 보내면
updated가 아니라 skipped입니다. 서버가 쓰기 전에 현재 값과 비교해
실제로 달라진 항목만 updated로 셉니다. 이름·상위 그룹이 그대로여도 한도만 바뀌었다면 updated입니다.한도 적용만 실패한 그룹은
created·updated와 failed에 함께 잡히므로, 카운터의 합이 total보다
클 수 있습니다.일부 항목이 실패해도 나머지는 그대로 반영됩니다. 요청 전체가 취소되지 않으므로,
failed_details를 확인해 해당 항목만 고쳐서 다시 보내면 됩니다.자주 나오는
reason 값은 다음과 같습니다.reason | 원인 |
|---|---|
unknown group_type: ... | group_type에 넣은 id가 이 조직에 없음 |
unknown group (public_hash_id) | id에 넣은 그룹 id가 이 조직에 없음 |
name is required for a new group | 신규 생성인데 이름을 하나도 보내지 않음 |
unknown group: ... | 구성원 소속에 지정한 그룹 id가 없거나, 지정한 그룹 유형에 속하지 않음 |
parent not found: ... | parent에 넣은 상위 그룹 id가 없음 |
parent is only allowed for is_hierarchical=True group types | 트리(조직도) 구조 사용이 꺼진 그룹 유형에 parent를 지정함 |
group has members — move members before delete | 구성원이 남아 있는 그룹을 삭제하려 함 |
group has child groups — delete leaves first | 하위 그룹이 남아 있는 그룹을 삭제하려 함 |
quota: not_enterprise — ... | 크레딧 한도를 쓸 수 없는 요금제에서 한도를 설정하려 함 |
quota: member_quota_required — ... | group_credit_quota만 설정하고 member_credit_quota를 해제 상태로 둠 |
quota: group_quota_required — ... | 위의 반대 (member_credit_quota만 설정) |
invite: code=3 (name) | 초대 이름이 비어 있음 (100자 초과는 요청 전체가 422로 거부됨) |
invite: code=7 | 가입에 필수인 커스텀 필드를 보내지 않음 |
invite: code=8 (...) | 가입 폼에 없는 커스텀 필드를 지정함 |
invite: code=14 (...) | 유니크 커스텀 필드의 값이 이미 사용 중 |
invite: <사유> (그룹명) | 초대에 지정한 소속이 그룹 유형 규칙에 어긋남 |
제약 사항
- 같은 요청에서 새로 만든 그룹을 상위 그룹으로 지정할 수 없습니다. 상위 그룹을 먼저 만들고, 그 id를 받은 뒤 하위 그룹을 보내는 두 번의 요청으로 나눠주세요.
- 그룹 유형과 커스텀 필드의 정의는 동기화되지 않습니다. 관리자 화면에서 먼저 만들어야 합니다.
- 그룹 관리자 지정과 모델·기능 권한은 이 API로 설정할 수 없습니다. (그룹 크레딧 한도는 그룹 크레딧 한도로 설정할 수 있습니다.) 관리자 화면의 그룹 관리와 그룹 관리자에서 처리해주세요. 어드민 화면이 쓰는
/v1/admin/*는 화면 구동을 위한 내부 경로이며 외부 연동용으로 제공되지 않습니다. - 처리 순서는 그룹 생성·수정 → 구성원 → 그룹 삭제입니다. 부서를 없애면서 인원을 옮기는 요청을 한 번에 보내도, 구성원이 먼저 이동한 뒤 빈 그룹이 삭제됩니다.
- 동기화 요청은 순차로 보내주세요. 같은 조직의 요청은 한 번에 하나만 처리되며, 앞선 요청이 진행 중이면 뒤 요청은 기다리지 않고 즉시
409로 실패합니다. 이전 요청의 응답을 받은 뒤 다음 요청을 보내세요.409를 받으면 잠시 후 같은 요청을 그대로 다시 보내면 됩니다. - 한 사람을 특정 그룹에서만 빼는 것은 불가능합니다.
groups는{ 그룹 유형: 그룹 }매핑이라 유형당 하나만 지정할 수 있습니다. 여러 그룹에 동시에 속할 수 있는 유형에서 일부 소속만 해제하려면 관리자 화면을 사용해주세요. - 요청 본문은 최대 50MB입니다.
코드 예제
Python
스키마를 받아 부서 명단을 동기화하는 최소 예제입니다.
dry_run으로 먼저 확인한 뒤 반영합니다.curl
에러 코드
| 코드 | 의미 |
|---|---|
400 | groups·members 키를 둘 다 생략한 full_sync 요청 |
401 | API 키가 없거나 유효하지 않음 |
402 | 초대가 조직의 정원을 초과 (대기 중인 초대도 좌석으로 셈) |
403 | 조직에 이 API가 활성화돼 있지 않거나, 키 소유자가 관리자가 아님(비활성 계정 포함). SSO 전용 조직에서 초대를 시도했거나, 크레딧 한도를 변경할 수 없는 요금제인 경우도 포함 |
404 | 경로 끝의 슬래시 누락 등 존재하지 않는 경로 |
405 | 허용되지 않는 메서드 (/는 POST, /schema/는 GET) |
409 | 같은 조직의 다른 동기화가 진행 중 (잠시 후 재시도) |
413 | 요청 본문이 50MB를 초과 |
422 | 요청 본문 형식 오류 (필수 필드 누락, 커스텀 필드 값에 문자열이 아닌 값 등) |
500 | 서버 오류 |
503 | 조직이 점검 중 |
개별 항목의 실패는 에러 코드가 아니라 응답의
failed_details로 전달됩니다.관리자 설정
이 API의 사용 여부는 조직 단위로 관리되며, 관리자 화면에는 설정 항목이 없습니다. 활성화·비활성화가 필요하면 마인드로직 담당자에게 요청해주세요.
활성화 이후에도 관리자 권한이 있는 활성 계정의 API 키만 이 API를 호출할 수 있습니다. 해당 계정의 관리자 권한을 회수하거나 계정을 비활성화하면 그 키의 호출도 즉시 차단되므로, 조직 내 담당자가 바뀌어도 키를 따로 폐기하지 않아도 됩니다. 다만 키 자체는 계정에 남아 있으니, 발급 계정과 보관 위치를 조직의 보안 정책에 맞춰 관리해주세요.
다음 단계
- API Gateway 인증 — API 키 발급 방법
- 그룹 관리 — 그룹 유형·커스텀 필드를 화면에서 만드는 방법
- 그룹 관리자 — 이 API로는 설정할 수 없는 그룹 관리자 지정
- 멤버 초대 — 신규 구성원 가입 경로
마지막 수정 날짜: Aug 20, 2026
