멤버
`members->list`, `listAll`, `iterate`, `get`, `add`, `update`, `remove`, `grantAddress`, `revokeAddress`, `grantDomain`, `revokeDomain`, 그리고 옆의 초대 메서드.
모든 메서드
$supportRoleId = 'role_8b1f4c2e9a7d3b60e5f1a2c4';$viewerRoleId = 'role_2c7e9a1f4b8d3e60c5a7f1b9'; $invitation = $client->members->add([ 'email' => '[email protected]', 'roleId' => $supportRoleId, 'addressIds' => ['2b81de07-9c3f-4a61-b8e2-5d07f4c19a36'], 'access' => 'member',]);echo $invitation['id'], ' ', $invitation['expiresAt'], PHP_EOL; foreach ($client->members->listAll() as $person) { echo $person['email'], ' ', $person['userId'], PHP_EOL;} $samId = 'q7Vd3kX9mT2pLw8RzN4bYc6HfJ1sGa5E';$member = $client->members->get($samId);echo $member['role']['name'], $member['implied'] ? ' (implied)' : '', PHP_EOL; $client->members->update($samId, ['roleId' => $viewerRoleId]); $addressId = 'c40a95f2-1e7b-4d38-a6c9-82f05b3d7e14';$client->members->grantAddress($samId, ['addressId' => $addressId, 'access' => 'viewer']);$client->members->revokeAddress($samId, $addressId); $removed = $client->members->remove($samId);echo $removed['addressesRevoked'], PHP_EOL;한 사람에게는 두 가지 권한이 주어지며, 이 둘을 하나로 합쳐서는 안 됩니다. role은 무엇을 해도 되는지이고, addresses와 domains는 그것을 어떤 대상에 할 수 있는지입니다. 둘 다 허용해야 합니다: emails:send를 가진 역할을 갖고 있으면서 invoices@에 대해서는 access가 viewer로 설정된 사람은, 메일을 보낼 수는 있지만 그 주소에서는 보낼 수 없는 사람입니다. 예외는 addresses:all을 가진 역할로, addresses에 무엇이 나열되든 모든 주소에 닿는데, 그 배열에는 직접 받은 부여만 들어 있기 때문입니다. 그러므로 addresses를 그 사람이 닿는 범위 전체로 읽기 전에 permissions를 확인하세요.
한 사람에 관한 모든 호출은 이메일이 아니라 그 사람의 userId를 첫 번째 인자로 받으므로, 예제처럼 list나 listAll에서 읽어 오세요. 유일한 예외는 add로, 주소를 초대하기 때문입니다: 그 사람은 초대를 수락한 뒤에야 userId를 가지며, 그때까지는 listInvitations로 초대를 추적합니다. add, update, grantAddress, grantDomain의 본문은 API의 camelCase 이름(roleId, addressIds, addressId)을 키로 하는 배열 하나입니다.
list는 OpenEmail\Result\Page 하나를 반환하고, listAll은 모든 멤버를 하나의 배열로 반환하며, iterate는 멤버를 하나씩 yield하는 Generator를 반환합니다. 멤버는 camelCase 키를 가진 배열로 돌아오고 role은 그 안의 배열이므로, $member['role']['name']으로 역할의 이름을 읽습니다.
implied가 true이면 아무도 역할을 고르지 않았다는 뜻입니다. 주소나 도메인 권한만 있고 역할 행은 없어서, 가진 권한 중 가장 넓은 것에서 역할을 추론한 것입니다. “아직 정해지지 않음”으로 취급하세요. 추론을 결정으로 바꾸는 것은 update입니다. 그전까지는 주소 접근 권한을 넓히면 그 사람이 할 수 있는 일도 조용히 함께 넓어집니다.
워크스페이스 소유자는 isOwner가 true인 첫 번째 행이지만, add, update, remove는 여전히 member_is_owner로 소유자를 거부합니다. 이는 ValidationException으로 던져지는 422입니다. 공유되지 않은 워크스페이스도 멤버가 없다고 보고하지 않고 한 명으로 보고하므로, 좌석 수를 셀 때는 isOwner를 제외하세요: count(array_filter($client->members->listAll(), fn(array $member): bool => !$member['isOwner'])).
remove는 두 축을 모두 가져갑니다: 역할과 이 워크스페이스의 모든 주소 및 도메인 권한을 함께 회수하고, 회수한 권한의 수를 도메인을 포함해 addressesRevoked로 보고합니다. revokeAddress는 좁은 쪽으로, 회사를 떠난 사람이 아니라 팀을 옮긴 사람을 위한 호출이며, revokeDomain은 도메인 전체에 대해 같은 일을 합니다.
add, update, remove와 네 가지 부여 및 회수 호출은 OAuth 액세스 토큰에는 인증 코드를 요구하지만, API 키에는 절대 요구하지 않습니다. 토큰이 코드를 얻기 전까지 이 호출들은 isStepUpRequired()가 true인 PermissionException을 던집니다. add와 grantDomain은 팀이 포함된 요금제도 필요하며, 그렇지 않은 요금제에서는 errorCode가 plan_required로 설정된 PermissionException을 던집니다.
매개변수
emailstring필수- 초대할 대상이며, 앞뒤 공백을 제거하고 소문자로 변환합니다. 아직 계정이 없어도 됩니다. 누구든 초대할 수 있고, 역할과 권한은 초대를 수락할 때 적용됩니다. 이미 워크스페이스에 있는 사람은 `member_is_owner`(422)입니다. 자체 비밀번호로 로그인하는 주소는 초대할 수 없으며 `mailbox_login`(403)으로 돌아오므로, 대신 그 사람 본인의 이메일을 초대하세요.
roleIdstring필수- 그 사람이 가질 역할이며 1자에서 128자이고, 이 워크스페이스에 존재하는 역할이어야 합니다: 알 수 없는 id는 `NotFoundException`으로 던져지는 `role_not_found`(404)입니다. 소유자 역할은 넘겨줄 수 없어 `role_immutable`(409)로 돌아옵니다. 누군가를 소유자로 만드는 것은 워크스페이스 양도이고, 여기에는 그런 호출이 없기 때문입니다.
addressIdsarray- 초대에 담기는 주소이며, 각각 1자에서 128자인 id를 최대 64개까지 지정할 수 있고, 초대가 수락될 때 부여됩니다. 무엇이든 기록되기 전에 모든 id를 검사하므로, 이 워크스페이스의 주소가 아닌 id가 하나라도 있으면 호출 전체가 422 `member_not_found`로 거부되고 아무것도 발송되지 않습니다. 같은 주소를 10분 안에 다시 초대하면 409 `invitation_too_soon`입니다.
domainIdsarray- 초대에 담기는 도메인 전체로, 최대 64개의 id이며 초대가 수락될 때 부여됩니다. 도메인 부여는 나중에 만든 주소를 포함해 그 도메인의 모든 주소에 닿습니다. 이 워크스페이스의 도메인이 아닌 id는 주소와 마찬가지로 422 `member_not_found`입니다.
accessstring- `addressIds`와 `domainIds`에 담긴 모든 id에 대해 무엇을 할 수 있는지입니다: `member`는 주소를 읽고 그 주소로 보낼 수 있으며, `viewer`는 읽기만 합니다. 기본값은 `member`로, 콘솔과 기존 공유 경로가 늘 사용해 온 수준입니다. 덕분에 스크립트에서든 화면에서든 같은 호출이 같은 의미를 갖습니다. 서로 다른 수준을 섞으려면 예외로 둘 주소에 대해 나중에 `grantAddress`를 호출하세요.
응답
objectstring- 항상 `member`입니다. 삭제 호출도 같은 값과 함께 해당 사용자의 `userId`, true로 설정된 `deleted`, `addressesRevoked`만 돌려주고, 아래의 다른 필드는 돌려주지 않습니다.
userIdstring- 그 사람의 계정 id이며, 다른 모든 멤버 호출이 첫 번째 인자로 받는 핸들입니다: `get`, `update`, `remove`와 네 가지 부여 및 회수 호출이 모두 이 값을 씁니다. 사람을 추가하는 호출만 대신 이메일로 동작하는데, 동료를 추가하는 사람은 상대의 주소는 알아도 id는 모르기 때문입니다.
emailstring- 그 사람 계정에 등록된 이메일이며, 해당 행에 저장된 그대로 돌려줍니다. 이 리소스는 이 값을 기록하지 않으며, `add`에서의 소문자 변환은 조회를 위해 보낸 주소에 적용될 뿐 돌아오는 값에 적용되는 것이 아닙니다. 멤버 목록은 소유자 다음부터 가입 시점이 아니라 이 값을 기준으로 정렬됩니다. 이 목록은 무엇이 바뀌었는지 보려고가 아니라 특정 한 사람을 찾으려고 읽기 때문입니다.
namestring or null- 그 사람 계정에서 가져온 표시 이름이며, 해당 컬럼에는 항상 값이 있습니다. 타입에 있는 null은 방어적인 것일 뿐 이 API에서 실제로 관측된 상태는 아닙니다. 이 값은 워크스페이스가 아니라 그 사람에게 속하므로, 이 리소스로는 아무것도 설정할 수 없습니다.
imagestring or null- 그 사람 계정에서 가져온 아바타이며, 설정하지 않았으면 null입니다.
role.idstring or null- 그 사람이 가진 역할의 id로, `$member['role']['id']`로 읽으며, 아무도 고르지 않았으면 null입니다. `implied`를 참고하세요. 여기가 null인 경우가, `role`이 누군가의 결정이 아니라 추론을 보고하는 유일한 경우입니다.
role.namestring- 역할의 이름입니다. 추론된 멤버의 경우 이 워크스페이스의 행이 아니라, 그 사람의 접근 권한이 대응하는 내장 템플릿의 이름입니다.
role.builtinstring or null- 이 역할이 어떤 내장 역할(`owner`, `admin`, `member`, `viewer`, `developer`, `billing`)인지이며, 사용자 정의 역할이면 null입니다. `owner`는 소유자 본인의 행에만 true인 `isOwner`와 함께 나타납니다. 그 역할을 누군가에게 부여하려 하면 `role_immutable`(409)로 거부됩니다.
isOwnerbool- 정확히 한 행에서만 true이며, 워크스페이스가 귀속된 계정입니다. 역할 행이 무엇이라고 하든 모든 권한을 가지며, 정렬 시 가장 앞에 오고, `add`, `update`, `remove`는 모두 `member_is_owner`로 거부합니다. 좌석 수를 셀 때는 제외하십시오.
impliedbool- 주소나 도메인 권한은 있는데 멤버 행이 없어 역할이 선택된 것이 아니라 추론된 경우 true입니다: `member` 권한이 하나라도 있으면 내장 Member로, 그렇지 않으면 Viewer가 됩니다. 소유자에게는 절대 true가 되지 않습니다. “접근 권한에서 추론됨”으로 표시하세요. `update`로 추론을 결정으로 바꾸기 전까지는, 주소 접근 권한을 넓히면 그 사람이 할 수 있는 일도 조용히 함께 넓어집니다.
permissionsarray- 역할의 권한을 멤버에 펼쳐 놓은 것으로, 역할을 따로 조회하지 않고도 한 번의 읽기로 “이 사람이 해도 되는가?”에 답할 수 있습니다. 추론된 멤버의 경우 이 워크스페이스의 역할 행이 아니라 내장 템플릿에서 가져오므로, 내장 Member 역할을 수정해도 추론된 멤버가 가진 권한은 달라지지 않습니다.
addressesarray- 그 사람에게 부여된 주소이며 주소 기준으로 정렬되고, 주소마다 자체 접근 수준을 담은 배열이 하나씩 있습니다. 역할만 있고 권한이 없는 사람은 비어 있습니다. 주소가 부여되기 전의 새 멤버가 바로 그 모습이며, 무엇을 보여 줄지 아직 정하는 중이라면 그것이 올바른 상태입니다.
addresses[].addressIdstring- 주소의 id이며, `grantAddress`와 `revokeAddress`가 받는 값입니다. 이 워크스페이스의 주소가 아닌 id는 두 호출 모두에서 거부되며, 일어나지도 않은 회수를 보고하는 일은 없습니다.
addresses[].addressstring- 로컬 파트와 도메인을 다시 조합한 전체 주소이며, 소문자로 표기됩니다.
addresses[].accessstring- 이 주소 하나에 대해 무엇을 할 수 있는지입니다: `member`는 읽고 그 주소로 보낼 수 있으며, `viewer`는 읽기만 합니다. 발송이 일어나려면 이 값과 역할이 모두 허용해야 하므로, `emails:send`를 가진 역할이라도 `viewer` 권한 위에서는 어떤 주소로도 보내지 못합니다. 저장된 컬럼 이름은 `role`이지만, 배열 하나가 서로 다른 어휘에서 온 `role` 키를 두 개 들고 있지 않도록 여기서는 이름을 바꿨습니다.
domainsarray- 그 사람에게 부여된 도메인 전체이며, 각각 `domainId`, `domain`, `access`를 가집니다. 도메인 부여는 나중에 만든 주소를 포함해 그 도메인의 모든 주소에 닿으므로, 누군가 어떤 주소에 닿지 못한다고 판단하기 전에 `addresses`와 함께 읽으세요. `grantDomain`과 `revokeDomain`은 `domainId`를 받습니다.
createdAtstring or null- 멤버 행이 기록된 시각이며 ISO 8601 문자열입니다. 멤버 행이 아예 없으면 null입니다. 이 null은 `implied`가 true인 경우와 같은 집단을 가리킵니다: 역할 제도가 생기기 전부터 권한을 갖고 있었고 그 뒤로 아무도 역할을 주지 않은 사람들입니다.
초대
$waiting = $client->members->listAllInvitations(); foreach ($waiting as $invitation) { if ($invitation['expired']) { $client->members->resendInvitation($invitation['id']); }} $client->members->revokeInvitation('winv_6bb640f5b99e47deb758f1f5');add는 초대로 답하며, 이어지는 호출은 다음과 같습니다. listInvitations는 아직 아무도 수락하지 않은 초대의 OpenEmail\Result\Page 하나를 반환하고, listAllInvitations는 전부를 하나의 배열로 반환하며, iterateInvitations는 초대를 하나씩 yield하는 Generator를 반환합니다. resendInvitation은 새 링크와 14일의 추가 기간으로 다시 보내고, revokeInvitation은 철회합니다. 대기 중인 초대는 수락될 때까지 아무것도 부여하지 않습니다.
초대는 id, email, role, addresses, domains, expiresAt, expired, lastSentAt, createdAt를 가진 배열입니다. delivered와 deliveryError는 마지막 초대 이메일이 어떻게 되었는지 알려 주므로, 스크립트는 기록만 된 초대와 실제로 누군가에게 도착한 초대를 구분할 수 있습니다.
resendInvitation은 같은 주소를 10분 안에 두 번째로 보내려 하면 409 invitation_too_soon으로 거부하고, revokeInvitation은 먼저 수락된 초대를 409 invitation_accepted로 거부합니다. 둘 다 ConflictException으로 던져지므로 isConflict()가 true이며, errorCode로 구분할 수 있습니다.