Admin API
Admin API
Admin API는 조직의 구성원, 워크스페이스, 초대, API 키를 Claude Console에서 수동으로 관리하는 대신 프로그래밍 방식으로 관리할 수 있게 해 주는 API예요. Admin API 키, org:admin 범위의 OAuth 토큰, 또는 특정 워크스페이스에 바인딩되지 않은 개인 키나 서비스 계정 키로 호출할 수 있어요.
Admin API는 개별 계정에서는 사용할 수 없어요. 팀원과의 협업과 구성원 추가는 Console → Settings → Organization에서 조직을 설정해야 돼요.
출처: 문서
본문
Admin API는 특별한 접근 권한이 필요해요
Admin API는 세 가지 자격 증명을 허용해요:
x-api-key헤더로 보내는 Admin API 키(sk-ant-admin...로 시작). admin 역할을 가진 조직 구성원만 발급할 수 있어요. Admin API 키 만들기 참고.authorization헤더로 보내는org:admin범위의 OAuth 베어러 토큰. admin, owner, primary owner 역할을 가진 구성원만 얻을 수 있어요. OAuth 베어러 토큰 얻기 참고.- 특정 워크스페이스에 바인딩되지 않은 개인 키 또는 서비스 계정 키를
x-api-key헤더로 전달. 키는 연결된 계정과 동일한 권한을 가져요. 키 유형 참고.
Claude Enterprise: Claude Enterprise(claude.ai) 조직은 claude.ai에서 만든 범위 지정 API 키로 Admin API를 호출해요. 이 페이지에서 구성원·초대 엔드포인트만 적용돼요. 또한 Enterprise 전용 엔드포인트(그룹·커스텀 역할 읽기, 지출 한도)를 제공받아요. User management 참고.
AWS의 Claude Platform: 워크스페이스 엔드포인트(
/v1/organizations/workspaces의 create·get·list·update·archive)와 외부 키 엔드포인트(/v1/organizations/external_keys의 register·get·list·update·delete, CMEK용 — 키는 워크스페이스에 연결할 때 검증되므로 validate 엔드포인트는 없음)만 AWS의 Claude Platform에서 사용할 수 있어요. 조직 구성원, 워크스페이스 구성원, 초대, API 키, 사용량·비용·요금 한도 보고서는 사용할 수 없어요. Claude Platform on AWS 참고.
인증 (Authentication)
세 가지 자격 증명 중 하나로 인증하세요. Admin API 키는 대부분의 엔드포인트를 다뤄요. 서비스 계정, 페더레이션 발급자, 페더레이션 규칙 엔드포인트는 org:admin OAuth 토큰만 허용해요. 개인 키나 서비스 계정 키는 Admin API 키처럼 x-api-key 헤더로 보내면 돼요. 아래 예시는 조직 정보 엔드포인트를 OAuth 토큰과 Admin API 키로 호출해요.
Python, TypeScript, C#, Go, Java, PHP, Ruby SDK는 client.beta.organization 아래에 Admin API를 노출하고, ant CLI는 ant beta:organization으로 노출해요. 이 페이지의 예시는 ANTHROPIC_API_KEY에서 Admin API 키를, ANTHROPIC_AUTH_TOKEN에서 OAuth 베어러 토큰을 읽는 기본 클라이언트를 사용해요. Python·TypeScript·C#·Go·Java의 SDK 목록 메서드는 필요할 때 더 많은 페이지를 가져오는 반복자(iterator)를 반환하므로 limit은 총합이 아니라 페이지 크기를 설정해요. PHP, Ruby, curl 예시는 한 페이지를 반환해요. CLI에서 --limit은 구성원·초대·워크스페이스·워크스페이스 구성원·API 키 목록의 결과를 제한해요. 각 엔드포인트의 매개변수와 응답은 Admin API 참조를 참고하세요.
OAuth 베어러 토큰
org:admin 범위로 전용 프로필 아래 ant CLI에 로그인한 뒤(Admin access 참고), 베어러 토큰을 내보내세요. --profile admin은 org:admin 자격 증명을 자체 프로필 아래에 저장하고 이를 CLI의 활성 프로필로 만들어요. 내보낸 변수는 해당 셸의 모든 SDK·CLI 호출에 적용돼요. 관리를 위해 예약해 둔 셸을 사용하고, 작업이 끝나면 변수를 해제하며, ant profile activate default로 CLI를 다시 전환하세요:
ant auth login --profile admin --scope "org:admin"
export ANTHROPIC_AUTH_TOKEN=$(ant auth print-credentials --profile admin --access-token)
대화형 토큰은 수명이 짧아요. 요청이 401을 반환하기 시작하면 export 명령을 다시 실행해 토큰을 갱신하세요.
SDK와 ant CLI는 ANTHROPIC_AUTH_TOKEN을 자동으로 읽어요. 같은 셸에서 ANTHROPIC_API_KEY를 설정하지 않은 채 두면 베어러 토큰을 보내요. 자동화 워크로드는 로그인을 건너뛰어요. 워크로드 ID 페더레이션(WIF)으로 인증하고 SDK·CLI가 페더레이션 환경 변수에서 토큰 교환을 수행해요. WIF 관리용 워크로드 부트스트랩 참고.
내보낸 토큰으로 Admin API를 호출하세요:
ant beta:organization retrieve
client = anthropic.Anthropic()
organization = client.beta.organization.retrieve()
print(f"id: {organization.id}")
print(f"name: {organization.name}")
const client = new Anthropic();
const organization = await client.beta.organization.retrieve();
console.log(`id: ${organization.id}`);
console.log(`name: ${organization.name}`);
AnthropicClient client = new();
var organization = await client.Beta.Organization.Retrieve();
Console.WriteLine($"id: {organization.ID}");
Console.WriteLine($"name: {organization.Name}");
client := anthropic.NewClient()
organization, err := client.Beta.Organization.Get(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Printf("id: %s\n", organization.ID)
fmt.Printf("name: %s\n", organization.Name)
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
var organization = client.beta().organization().retrieve();
IO.println("id: " + organization.id());
IO.println("name: " + organization.name());
$client = new Client();
$organization = $client->beta->organization->retrieve();
echo "id: {$organization->id}\n";
echo "name: {$organization->name}\n";
client = Anthropic::Client.new
organization = client.beta.organization.retrieve
puts "id: #{organization.id}"
puts "name: #{organization.name}"
org:admin 토큰은 기본 프로필이나 페더레이션 규칙이 바인딩된 워크스페이스와 무관하게 전체 조직에 대한 접근 권한을 부여해요.
CI 및 기타 비대화형 워크로드의 경우 대화형 로그인 대신 Workload Identity Federation으로 토큰을 발급하세요. Admin API로 WIF 관리 참고.
Admin API 키
조직 유형에 맞는 Admin API 키를 만들려면 Admin API 키 만들기를 참고하세요.
ant beta:organization retrieve
client = anthropic.Anthropic()
organization = client.beta.organization.retrieve()
print(f"id: {organization.id}")
print(f"name: {organization.name}")
const client = new Anthropic();
const organization = await client.beta.organization.retrieve();
console.log(`id: ${organization.id}`);
console.log(`name: ${organization.name}`);
AnthropicClient client = new();
var organization = await client.Beta.Organization.Retrieve();
Console.WriteLine($"id: {organization.ID}");
Console.WriteLine($"name: {organization.Name}");
client := anthropic.NewClient()
organization, err := client.Beta.Organization.Get(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Printf("id: %s\n", organization.ID)
fmt.Printf("name: %s\n", organization.Name)
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
var organization = client.beta().organization().retrieve();
IO.println("id: " + organization.id());
IO.println("name: " + organization.name());
$client = new Client();
$organization = $client->beta->organization->retrieve();
echo "id: {$organization->id}\n";
echo "name: {$organization->name}\n";
client = Anthropic::Client.new
organization = client.beta.organization.retrieve
puts "id: #{organization.id}"
puts "name: #{organization.name}"
Admin API는 어떻게 작동하나요?
인증의 어떤 자격 증명으로든 인증한 뒤 다음 리소스를 관리할 수 있어요:
- 조직 구성원과 그 역할
- 조직 초대
- 워크스페이스와 그 구성원
- API 키
- 서비스 계정, 페더레이션 발급자, 페더레이션 규칙(
org:adminOAuth 토큰 전용)
일반적인 용도로는 온보딩·오프보딩 자동화, 워크스페이스 접근 관리, API 키 감사가 있어요.
조직 역할과 권한
조직 수준 역할은 다섯 가지예요. 자세한 내용은 API Console 역할과 권한을 참고하세요.
| 역할 | 권한 |
|---|---|
| user | 플레이그라운드 사용 |
| claude_code_user | 플레이그라운드와 Claude Code 사용 |
| developer | 플레이그라운드 사용과 API 키 관리 |
| billing | 플레이그라운드 사용과 청구 정보 관리 |
| admin | 위의 모든 것 + 사용자 관리 |
조직 owner와 primary owner는 모든 admin 권한을 가지며 admin도 관리할 수 있어요. 이 페이지에서 admin 역할을 언급하는 모든 내용은 owner와 primary owner에도 적용돼요.
핵심 개념
조직 구성원
조직 구성원을 목록화하고, 역할을 업데이트하고, 제거하세요.
조직의 구성원을 목록화하세요:
ant beta:organization:users list --limit 10
client = anthropic.Anthropic()
users = client.beta.organization.users.list(limit=10)
# Automatically fetches more pages as needed.
for user in users:
print(f"{user.id}: {user.email} ({user.role})")
const client = new Anthropic();
const users = await client.beta.organization.users.list({ limit: 10 });
for await (const user of users) {
console.log(`${user.id}: ${user.email} (${user.role})`);
}
AnthropicClient client = new();
var page = await client.Beta.Organization.Users.List(new() { Limit = 10 });
await foreach (var user in page.Paginate())
{
Console.WriteLine($"{user.ID}: {user.Email} ({user.Role.Raw()})");
}
client := anthropic.NewClient()
users := client.Beta.Organization.Users.ListAutoPaging(context.Background(), anthropic.BetaOrganizationUserListParams{
Limit: anthropic.Int(10),
})
for users.Next() {
user := users.Current()
fmt.Printf("%s: %s (%s)\n", user.ID, user.Email, user.Role)
}
if err := users.Err(); err != nil {
log.Fatal(err)
}
import com.anthropic.models.beta.organization.users.UserListParams;
void main() {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
var params = UserListParams.builder()
.limit(10)
.build();
var users = client.beta().organization().users().list(params);
for (var user : users.autoPager()) {
IO.println(user.id() + ": " + user.email() + " (" + user.role().asString() + ")");
}
}
$client = new Client();
$users = $client->beta->organization->users->list(limit: 10);
foreach ($users->getItems() as $user) {
echo "{$user->id}: {$user->email} ({$user->role})\n";
}
client = Anthropic::Client.new
users = client.beta.organization.users.list(limit: 10)
users.data.each do |user|
puts "#{user.id}: #{user.email} (#{user.role})"
end
구성원의 역할을 업데이트하세요:
ant beta:organization:users update \
--user-id user_01XyDMpzjS89pFZXqSFUBDr6 \
--role developer
client = anthropic.Anthropic()
user = client.beta.organization.users.update(
"user_01XyDMpzjS89pFZXqSFUBDr6", role="developer"
)
print(f"id: {user.id}")
print(f"role: {user.role}")
const client = new Anthropic();
const user = await client.beta.organization.users.update("user_01XyDMpzjS89pFZXqSFUBDr6", {
role: "developer"
});
console.log(`id: ${user.id}`);
console.log(`role: ${user.role}`);
using Anthropic.Models.Beta.Organization.Users;
// ...
AnthropicClient client = new();
var user = await client.Beta.Organization.Users.Update(
"user_01XyDMpzjS89pFZXqSFUBDr6",
new() { Role = Role.Developer }
);
Console.WriteLine($"id: {user.ID}");
Console.WriteLine($"role: {user.Role.Raw()}");
client := anthropic.NewClient()
user, err := client.Beta.Organization.Users.Update(
context.Background(),
"user_01XyDMpzjS89pFZXqSFUBDr6",
anthropic.BetaOrganizationUserUpdateParams{
Role: anthropic.BetaOrganizationUserUpdateParamsRoleDeveloper,
},
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("id: %s\n", user.ID)
fmt.Printf("role: %s\n", user.Role)
import com.anthropic.models.beta.organization.users.UserUpdateParams;
void main() {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
var params = UserUpdateParams.builder()
.role(UserUpdateParams.Role.DEVELOPER)
.build();
var user = client.beta().organization().users()
.update("user_01XyDMpzjS89pFZXqSFUBDr6", params);
IO.println("id: " + user.id());
IO.println("role: " + user.role().asString());
}
use Anthropic\Beta\Organization\Users\UserUpdateParams\Role;
// ...
$client = new Client();
$user = $client->beta->organization->users->update(
userID: 'user_01XyDMpzjS89pFZXqSFUBDr6',
role: Role::DEVELOPER,
);
echo "id: {$user->id}\n";
echo "role: {$user->role}\n";
client = Anthropic::Client.new
user_id = "user_01XyDMpzjS89pFZXqSFUBDr6"
user = client.beta.organization.users.update(user_id, role: :developer)
puts "id: #{user.id}"
puts "role: #{user.role}"
조직에서 구성원을 제거하세요:
ant beta:organization:users remove --user-id user_01XyDMpzjS89pFZXqSFUBDr6
client = anthropic.Anthropic()
removed_user = client.beta.organization.users.remove("user_01XyDMpzjS89pFZXqSFUBDr6")
print(f"id: {removed_user.id}")
const client = new Anthropic();
const removedUser = await client.beta.organization.users.remove(
"user_01XyDMpzjS89pFZXqSFUBDr6"
);
console.log(`id: ${removedUser.id}`);
AnthropicClient client = new();
var removedUser = await client.Beta.Organization.Users.Remove("user_01XyDMpzjS89pFZXqSFUBDr6");
Console.WriteLine($"id: {removedUser.ID}");
client := anthropic.NewClient()
removedUser, err := client.Beta.Organization.Users.Remove(context.Background(), "user_01XyDMpzjS89pFZXqSFUBDr6")
if err != nil {
log.Fatal(err)
}
fmt.Printf("id: %s\n", removedUser.ID)
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
var removedUser = client.beta().organization().users()
.remove("user_01XyDMpzjS89pFZXqSFUBDr6");
IO.println("id: " + removedUser.id());
$client = new Client();
$removedUser = $client->beta->organization->users->remove(
userID: 'user_01XyDMpzjS89pFZXqSFUBDr6',
);
echo "id: {$removedUser->id}\n";
client = Anthropic::Client.new
user_id = "user_01XyDMpzjS89pFZXqSFUBDr6"
removed_user = client.beta.organization.users.remove(user_id)
puts "id: #{removed_user.id}"
조직 초대
조직에 사용자를 초대하고 보류 중인 초대를 관리하세요.
조직에 사용자를 초대하세요:
ant beta:organization:invites create --email [email protected] --role developer
client = anthropic.Anthropic()
invite = client.beta.organization.invites.create(
email="[email protected]", role="developer"
)
print(f"id: {invite.id}")
print(f"email: {invite.email}")
print(f"status: {invite.status}")
print(f"expires_at: {invite.expires_at}")
const client = new Anthropic();
const invite = await client.beta.organization.invites.create({
email: "[email protected]",
role: "developer"
});
console.log(`id: ${invite.id}`);
console.log(`email: ${invite.email}`);
console.log(`status: ${invite.status}`);
console.log(`expires_at: ${invite.expires_at}`);
using Anthropic.Models.Beta.Organization.Invites;
// ...
AnthropicClient client = new();
var invite = await client.Beta.Organization.Invites.Create(new()
{
Email = "[email protected]",
Role = Role.Developer
});
Console.WriteLine($"id: {invite.ID}");
Console.WriteLine($"email: {invite.Email}");
Console.WriteLine($"status: {invite.Status.Raw()}");
Console.WriteLine($"expires_at: {invite.ExpiresAt:O}");
client := anthropic.NewClient()
invite, err := client.Beta.Organization.Invites.New(context.Background(), anthropic.BetaOrganizationInviteNewParams{
Email: "[email protected]",
Role: anthropic.BetaOrganizationInviteNewParamsRoleDeveloper,
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("id: %s\n", invite.ID)
fmt.Printf("email: %s\n", invite.Email)
fmt.Printf("status: %s\n", invite.Status)
fmt.Printf("expires_at: %s\n", invite.ExpiresAt.Format(time.RFC3339))
import com.anthropic.models.beta.organization.invites.InviteCreateParams;
void main() {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
var params = InviteCreateParams.builder()
.email("[email protected]")
.role(InviteCreateParams.Role.DEVELOPER)
.build();
var invite = client.beta().organization().invites().create(params);
IO.println("id: " + invite.id());
IO.println("email: " + invite.email());
IO.println("status: " + invite.status().asString());
IO.println("expires_at: " + invite.expiresAt());
}
use Anthropic\Beta\Organization\Invites\InviteCreateParams\Role;
// ...
$client = new Client();
$invite = $client->beta->organization->invites->create(
email: '[email protected]',
role: Role::DEVELOPER,
);
echo "id: {$invite->id}\n";
echo "email: {$invite->email}\n";
echo "status: {$invite->status}\n";
echo "expires_at: {$invite->expiresAt->format(DATE_ATOM)}\n";
client = Anthropic::Client.new
invite = client.beta.organization.invites.create(email: "[email protected]", role: :developer)
puts "id: #{invite.id}"
puts "email: #{invite.email}"
puts "status: #{invite.status}"
puts "expires_at: #{invite.expires_at.iso8601}"
보류 중인 초대를 목록화하세요:
ant beta:organization:invites list --limit 10
client = anthropic.Anthropic()
invites = client.beta.organization.invites.list(limit=10)
# Automatically fetches more pages as needed.
for invite in invites:
print(f"{invite.id}: {invite.email} ({invite.status})")
const client = new Anthropic();
const invites = await client.beta.organization.invites.list({ limit: 10 });
for await (const invite of invites) {
console.log(`${invite.id}: ${invite.email} (${invite.status})`);
}
AnthropicClient client = new();
var page = await client.Beta.Organization.Invites.List(new() { Limit = 10 });
await foreach (var invite in page.Paginate())
{
Console.WriteLine($"{invite.ID}: {invite.Email} ({invite.Status.Raw()})");
}
client := anthropic.NewClient()
invites := client.Beta.Organization.Invites.ListAutoPaging(context.Background(), anthropic.BetaOrganizationInviteListParams{
Limit: anthropic.Int(10),
})
for invites.Next() {
invite := invites.Current()
fmt.Printf("%s: %s (%s)\n", invite.ID, invite.Email, invite.Status)
}
if err := invites.Err(); err != nil {
log.Fatal(err)
}
import com.anthropic.models.beta.organization.invites.InviteListParams;
void main() {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
var params = InviteListParams.builder()
.limit(10)
.build();
var invites = client.beta().organization().invites().list(params);
for (var invite : invites.autoPager()) {
IO.println(invite.id() + ": " + invite.email() + " (" + invite.status().asString() + ")");
}
}
$client = new Client();
$invites = $client->beta->organization->invites->list(limit: 10);
foreach ($invites->getItems() as $invite) {
echo "{$invite->id}: {$invite->email} ({$invite->status})\n";
}
client = Anthropic::Client.new
invites = client.beta.organization.invites.list(limit: 10)
invites.data.each do |invite|
puts "#{invite.id}: #{invite.email} (#{invite.status})"
end
초대를 삭제하세요:
ant beta:organization:invites delete --invite-id invite_015gWxHNr6h6TdRPZTmuCGnn
client = anthropic.Anthropic()
deleted_invite = client.beta.organization.invites.delete(
"invite_015gWxHNr6h6TdRPZTmuCGnn"
)
print(f"id: {deleted_invite.id}")
const client = new Anthropic();
const deletedInvite = await client.beta.organization.invites.delete(
"invite_015gWxHNr6h6TdRPZTmuCGnn"
);
console.log(`id: ${deletedInvite.id}`);
AnthropicClient client = new();
var deletedInvite = await client.Beta.Organization.Invites.Delete(
"invite_015gWxHNr6h6TdRPZTmuCGnn"
);
Console.WriteLine($"id: {deletedInvite.ID}");
client := anthropic.NewClient()
deletedInvite, err := client.Beta.Organization.Invites.Delete(context.Background(), "invite_015gWxHNr6h6TdRPZTmuCGnn")
if err != nil {
log.Fatal(err)
}
fmt.Printf("id: %s\n", deletedInvite.ID)
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
var deletedInvite = client.beta().organization().invites()
.delete("invite_015gWxHNr6h6TdRPZTmuCGnn");
IO.println("id: " + deletedInvite.id());
$client = new Client();
$deletedInvite = $client->beta->organization->invites->delete(
inviteID: 'invite_015gWxHNr6h6TdRPZTmuCGnn',
);
echo "id: {$deletedInvite->id}\n";
client = Anthropic::Client.new
invite_id = "invite_015gWxHNr6h6TdRPZTmuCGnn"
deleted_invite = client.beta.organization.invites.delete(invite_id)
puts "id: #{deleted_invite.id}"
워크스페이스
Console과 API 예시는 Workspaces를 참고하세요.
워크스페이스 구성원
특정 워크스페이스에 대한 사용자 접근을 관리하세요:
워크스페이스에 구성원을 추가하세요:
ant beta:organization:workspaces:members add \
--workspace-id wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ \
--user-id user_01XyDMpzjS89pFZXqSFUBDr6 \
--workspace-role workspace_developer
client = anthropic.Anthropic()
member = client.beta.organization.workspaces.members.add(
"wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ",
user_id="user_01XyDMpzjS89pFZXqSFUBDr6",
workspace_role="workspace_developer",
)
print(f"user_id: {member.user_id}")
print(f"workspace_role: {member.workspace_role}")
const client = new Anthropic();
const member = await client.beta.organization.workspaces.members.add(
"wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ",
{
user_id: "user_01XyDMpzjS89pFZXqSFUBDr6",
workspace_role: "workspace_developer"
}
);
console.log(`user_id: ${member.user_id}`);
console.log(`workspace_role: ${member.workspace_role}`);
using Anthropic.Models.Beta.Organization.Workspaces;
AnthropicClient client = new();
var member = await client.Beta.Organization.Workspaces.Members.Add(
"wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ",
new()
{
UserID = "user_01XyDMpzjS89pFZXqSFUBDr6",
WorkspaceRole = BetaNoBillingWorkspaceRole.WorkspaceDeveloper
}
);
Console.WriteLine($"user_id: {member.UserID}");
Console.WriteLine($"workspace_role: {member.WorkspaceRole.Raw()}");
client := anthropic.NewClient()
member, err := client.Beta.Organization.Workspaces.Members.Add(
context.Background(),
"wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ",
anthropic.BetaOrganizationWorkspaceMemberAddParams{
UserID: "user_01XyDMpzjS89pFZXqSFUBDr6",
WorkspaceRole: anthropic.BetaNoBillingWorkspaceRoleWorkspaceDeveloper,
},
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("user_id: %s\n", member.UserID)
fmt.Printf("workspace_role: %s\n", member.WorkspaceRole)
import com.anthropic.models.beta.organization.workspaces.BetaNoBillingWorkspaceRole;
import com.anthropic.models.beta.organization.workspaces.members.MemberAddParams;
void main() {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
var params = MemberAddParams.builder()
.userId("user_01XyDMpzjS89pFZXqSFUBDr6")
.workspaceRole(BetaNoBillingWorkspaceRole.WORKSPACE_DEVELOPER)
.build();
var member = client.beta().organization().workspaces().members()
.add("wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ", params);
IO.println("user_id: " + member.userId());
IO.println("workspace_role: " + member.workspaceRole().asString());
}
use Anthropic\Beta\Organization\Workspaces\NoBillingWorkspaceRole;
// ...
$client = new Client();
$member = $client->beta->organization->workspaces->members->add(
workspaceID: 'wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ',
userID: 'user_01XyDMpzjS89pFZXqSFUBDr6',
workspaceRole: NoBillingWorkspaceRole::WORKSPACE_DEVELOPER,
);
echo "user_id: {$member->userID}\n";
echo "workspace_role: {$member->workspaceRole}\n";
client = Anthropic::Client.new
workspace_id = "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ"
member = client.beta.organization.workspaces.members.add(
workspace_id,
user_id: "user_01XyDMpzjS89pFZXqSFUBDr6",
workspace_role: :workspace_developer
)
puts "user_id: #{member.user_id}"
puts "workspace_role: #{member.workspace_role}"
워크스페이스의 구성원을 목록화하세요:
ant beta:organization:workspaces:members list \
--workspace-id wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ \
--limit 10
client = anthropic.Anthropic()
members = client.beta.organization.workspaces.members.list(
"wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ", limit=10
)
# Automatically fetches more pages as needed.
for member in members:
print(f"{member.user_id}: {member.workspace_role}")
const client = new Anthropic();
const members = await client.beta.organization.workspaces.members.list(
"wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ",
{ limit: 10 }
);
for await (const member of members) {
console.log(`${member.user_id}: ${member.workspace_role}`);
}
AnthropicClient client = new();
var page = await client.Beta.Organization.Workspaces.Members.List(
"wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ",
new() { Limit = 10 }
);
await foreach (var member in page.Paginate())
{
Console.WriteLine($"{member.UserID}: {member.WorkspaceRole.Raw()}");
}
client := anthropic.NewClient()
members := client.Beta.Organization.Workspaces.Members.ListAutoPaging(
context.Background(),
"wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ",
anthropic.BetaOrganizationWorkspaceMemberListParams{
Limit: anthropic.Int(10),
},
)
for members.Next() {
member := members.Current()
fmt.Printf("%s: %s\n", member.UserID, member.WorkspaceRole)
}
if err := members.Err(); err != nil {
log.Fatal(err)
}
import com.anthropic.models.beta.organization.workspaces.members.MemberListParams;
void main() {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
var params = MemberListParams.builder()
.limit(10)
.build();
var members = client.beta().organization().workspaces().members()
.list("wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ", params);
for (var member : members.autoPager()) {
IO.println(member.userId() + ": " + member.workspaceRole().asString());
}
}
$client = new Client();
$members = $client->beta->organization->workspaces->members->list(
workspaceID: 'wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ',
limit: 10,
);
foreach ($members->getItems() as $member) {
echo "{$member->userID}: {$member->workspaceRole}\n";
}
client = Anthropic::Client.new
workspace_id = "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ"
members = client.beta.organization.workspaces.members.list(workspace_id, limit: 10)
members.data.each do |member|
puts "#{member.user_id}: #{member.workspace_role}"
end
워크스페이스 구성원의 역할을 업데이트하세요:
ant beta:organization:workspaces:members update \
--user-id user_01XyDMpzjS89pFZXqSFUBDr6 \
--workspace-id wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ \
--workspace-role workspace_admin
client = anthropic.Anthropic()
member = client.beta.organization.workspaces.members.update(
"user_01XyDMpzjS89pFZXqSFUBDr6",
workspace_id="wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ",
workspace_role="workspace_admin",
)
print(f"user_id: {member.user_id}")
print(f"workspace_role: {member.workspace_role}")
const client = new Anthropic();
const member = await client.beta.organization.workspaces.members.update(
"user_01XyDMpzjS89pFZXqSFUBDr6",
{
workspace_id: "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ",
workspace_role: "workspace_admin"
}
);
console.log(`user_id: ${member.user_id}`);
console.log(`workspace_role: ${member.workspace_role}`);
using Anthropic.Models.Beta.Organization.Workspaces;
AnthropicClient client = new();
var member = await client.Beta.Organization.Workspaces.Members.Update(
"user_01XyDMpzjS89pFZXqSFUBDr6",
new()
{
WorkspaceID = "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ",
WorkspaceRole = BetaWorkspaceRole.WorkspaceAdmin
}
);
Console.WriteLine($"user_id: {member.UserID}");
Console.WriteLine($"workspace_role: {member.WorkspaceRole.Raw()}");
client := anthropic.NewClient()
member, err := client.Beta.Organization.Workspaces.Members.Update(
context.Background(),
"user_01XyDMpzjS89pFZXqSFUBDr6",
anthropic.BetaOrganizationWorkspaceMemberUpdateParams{
WorkspaceID: "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ",
WorkspaceRole: anthropic.BetaWorkspaceRoleWorkspaceAdmin,
},
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("user_id: %s\n", member.UserID)
fmt.Printf("workspace_role: %s\n", member.WorkspaceRole)
import com.anthropic.models.beta.organization.workspaces.BetaWorkspaceRole;
import com.anthropic.models.beta.organization.workspaces.members.MemberUpdateParams;
void main() {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
var params = MemberUpdateParams.builder()
.workspaceId("wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ")
.workspaceRole(BetaWorkspaceRole.WORKSPACE_ADMIN)
.build();
var member = client.beta().organization().workspaces().members()
.update("user_01XyDMpzjS89pFZXqSFUBDr6", params);
IO.println("user_id: " + member.userId());
IO.println("workspace_role: " + member.workspaceRole().asString());
}
use Anthropic\Beta\Organization\Workspaces\WorkspaceRole;
// ...
$client = new Client();
$member = $client->beta->organization->workspaces->members->update(
userID: 'user_01XyDMpzjS89pFZXqSFUBDr6',
workspaceID: 'wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ',
workspaceRole: WorkspaceRole::WORKSPACE_ADMIN,
);
echo "user_id: {$member->userID}\n";
echo "workspace_role: {$member->workspaceRole}\n";
client = Anthropic::Client.new
user_id = "user_01XyDMpzjS89pFZXqSFUBDr6"
member = client.beta.organization.workspaces.members.update(
user_id,
workspace_id: "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ",
workspace_role: :workspace_admin
)
puts "user_id: #{member.user_id}"
puts "workspace_role: #{member.workspace_role}"
워크스페이스에서 구성원을 제거하세요:
ant beta:organization:workspaces:members remove \
--user-id user_01XyDMpzjS89pFZXqSFUBDr6 \
--workspace-id wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ
client = anthropic.Anthropic()
removed_member = client.beta.organization.workspaces.members.remove(
"user_01XyDMpzjS89pFZXqSFUBDr6", workspace_id="wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ"
)
print(f"user_id: {removed_member.user_id}")
const client = new Anthropic();
const removedMember = await client.beta.organization.workspaces.members.remove(
"user_01XyDMpzjS89pFZXqSFUBDr6",
{ workspace_id: "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ" }
);
console.log(`user_id: ${removedMember.user_id}`);
AnthropicClient client = new();
var removedMember = await client.Beta.Organization.Workspaces.Members.Remove(
"user_01XyDMpzjS89pFZXqSFUBDr6",
new() { WorkspaceID = "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ" }
);
Console.WriteLine($"user_id: {removedMember.UserID}");
client := anthropic.NewClient()
removedMember, err := client.Beta.Organization.Workspaces.Members.Remove(
context.Background(),
"user_01XyDMpzjS89pFZXqSFUBDr6",
anthropic.BetaOrganizationWorkspaceMemberRemoveParams{
WorkspaceID: "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ",
},
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("user_id: %s\n", removedMember.UserID)
import com.anthropic.models.beta.organization.workspaces.members.MemberRemoveParams;
void main() {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
var params = MemberRemoveParams.builder()
.workspaceId("wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ")
.build();
var removedMember = client.beta().organization().workspaces().members()
.remove("user_01XyDMpzjS89pFZXqSFUBDr6", params);
IO.println("user_id: " + removedMember.userId());
}
$client = new Client();
$removedMember = $client->beta->organization->workspaces->members->remove(
userID: 'user_01XyDMpzjS89pFZXqSFUBDr6',
workspaceID: 'wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ',
);
echo "user_id: {$removedMember->userID}\n";
client = Anthropic::Client.new
user_id = "user_01XyDMpzjS89pFZXqSFUBDr6"
removed_member = client.beta.organization.workspaces.members.remove(
user_id,
workspace_id: "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ"
)
puts "user_id: #{removed_member.user_id}"
API 키
API 키를 모니터링하고 관리하세요. 응답의 각 키에는 expires_at 타임스탬프(만료가 없는 키는 null)와 키가 동작하는 신원인 principal이 포함돼요(키 유형 참고). 개인 키의 principal은 {"type": "user_actor", "user_id": "user_..."}이고, 서비스 계정 키는 {"type": "service_account_actor", "service_account_id": "svac_..."}, 워크스페이스 키는 null이에요. 각 키에는 scope 객체도 있어요: 한 워크스페이스에 바인딩된 키는 {"type": "workspace", "workspace_id": "wrkspc_..."}이고, 계정이 접근할 수 있는 모든 워크스페이스에서 작동하는 키는 {"type": "organization"}이에요. 최상위 workspace_id 필드는 더 이상 사용되지 않으며, Default Workspace에 바인딩된 키와 워크스페이스 범위가 없는 키 모두 null이에요. 둘을 구분하려면 scope를 사용하세요. Default Workspace의 ID로 workspace_id 필터를 사용한 목록은 Default Workspace에 바인딩된 키만 반환해요. 워크스페이스 범위가 없는 키는 어떤 workspace_id 필터에서도 반환되지 않아요.
워크스페이스의 활성 API 키를 목록화하세요:
ant beta:organization:api-keys list \
--limit 10 \
--status active \
--workspace-id wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ
client = anthropic.Anthropic()
api_keys = client.beta.organization.api_keys.list(
limit=10, status="active", workspace_id="wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ"
)
# Automatically fetches more pages as needed.
for api_key in api_keys:
print(f"{api_key.id}: {api_key.name} ({api_key.status})")
const client = new Anthropic();
const apiKeys = await client.beta.organization.apiKeys.list({
limit: 10,
status: "active",
workspace_id: "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ"
});
for await (const apiKey of apiKeys) {
console.log(`${apiKey.id}: ${apiKey.name} (${apiKey.status})`);
}
using Anthropic.Models.Beta.Organization.ApiKeys;
AnthropicClient client = new();
var page = await client.Beta.Organization.ApiKeys.List(new()
{
Limit = 10,
Status = ApiKeyListParamsStatus.Active,
WorkspaceID = "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ"
});
await foreach (var apiKey in page.Paginate())
{
Console.WriteLine($"{apiKey.ID}: {apiKey.Name} ({apiKey.Status.Raw()})");
}
client := anthropic.NewClient()
apiKeys := client.Beta.Organization.APIKeys.ListAutoPaging(context.Background(), anthropic.BetaOrganizationAPIKeyListParams{
Limit: anthropic.Int(10),
Status: anthropic.BetaOrganizationAPIKeyListParamsStatusActive,
WorkspaceID: anthropic.String("wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ"),
})
for apiKeys.Next() {
apiKey := apiKeys.Current()
fmt.Printf("%s: %s (%s)\n", apiKey.ID, apiKey.Name, apiKey.Status)
}
if err := apiKeys.Err(); err != nil {
log.Fatal(err)
}
import com.anthropic.models.beta.organization.apikeys.ApiKeyListParams;
void main() {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
var params = ApiKeyListParams.builder()
.limit(10)
.status(ApiKeyListParams.Status.ACTIVE)
.workspaceId("wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ")
.build();
var apiKeys = client.beta().organization().apiKeys().list(params);
for (var apiKey : apiKeys.autoPager()) {
IO.println(apiKey.id() + ": " + apiKey.name() + " (" + apiKey.status().asString() + ")");
}
}
use Anthropic\Beta\Organization\APIKeys\APIKeyListParams\Status;
// ...
$client = new Client();
$apiKeys = $client->beta->organization->apiKeys->list(
limit: 10,
status: Status::ACTIVE,
workspaceID: 'wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ',
);
foreach ($apiKeys->getItems() as $apiKey) {
echo "{$apiKey->id}: {$apiKey->name} ({$apiKey->status})\n";
}
client = Anthropic::Client.new
api_keys = client.beta.organization.api_keys.list(
limit: 10,
status: :active,
workspace_id: "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ"
)
api_keys.data.each do |api_key|
puts "#{api_key.id}: #{api_key.name} (#{api_key.status})"
end
API 키 이름을 바꾸거나 비활성화하세요:
ant beta:organization:api-keys update \
--api-key-id apikey_01Rj2N8SVvo6BePZj99NhmiT \
--status inactive \
--name "New Key Name"
client = anthropic.Anthropic()
api_key = client.beta.organization.api_keys.update(
"apikey_01Rj2N8SVvo6BePZj99NhmiT", status="inactive", name="New Key Name"
)
print(f"id: {api_key.id}")
print(f"name: {api_key.name}")
print(f"status: {api_key.status}")
const client = new Anthropic();
const apiKey = await client.beta.organization.apiKeys.update(
"apikey_01Rj2N8SVvo6BePZj99NhmiT",
{
status: "inactive",
name: "New Key Name"
}
);
console.log(`id: ${apiKey.id}`);
console.log(`name: ${apiKey.name}`);
console.log(`status: ${apiKey.status}`);
using Anthropic.Models.Beta.Organization.ApiKeys;
AnthropicClient client = new();
var apiKey = await client.Beta.Organization.ApiKeys.Update(
"apikey_01Rj2N8SVvo6BePZj99NhmiT",
new()
{
Status = Status.Inactive,
Name = "New Key Name"
}
);
Console.WriteLine($"id: {apiKey.ID}");
Console.WriteLine($"name: {apiKey.Name}");
Console.WriteLine($"status: {apiKey.Status.Raw()}");
client := anthropic.NewClient()
apiKey, err := client.Beta.Organization.APIKeys.Update(
context.Background(),
"apikey_01Rj2N8SVvo6BePZj99NhmiT",
anthropic.BetaOrganizationAPIKeyUpdateParams{
Status: anthropic.BetaOrganizationAPIKeyUpdateParamsStatusInactive,
Name: anthropic.String("New Key Name"),
},
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("id: %s\n", apiKey.ID)
fmt.Printf("name: %s\n", apiKey.Name)
fmt.Printf("status: %s\n", apiKey.Status)
import com.anthropic.models.beta.organization.apikeys.ApiKeyUpdateParams;
void main() {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
var params = ApiKeyUpdateParams.builder()
.status(ApiKeyUpdateParams.Status.INACTIVE)
.name("New Key Name")
.build();
var apiKey = client.beta().organization().apiKeys()
.update("apikey_01Rj2N8SVvo6BePZj99NhmiT", params);
IO.println("id: " + apiKey.id());
IO.println("name: " + apiKey.name());
IO.println("status: " + apiKey.status().asString());
}
use Anthropic\Beta\Organization\APIKeys\APIKeyUpdateParams\Status;
// ...
$client = new Client();
$apiKey = $client->beta->organization->apiKeys->update(
apiKeyID: 'apikey_01Rj2N8SVvo6BePZj99NhmiT',
status: Status::INACTIVE,
name: 'New Key Name',
);
echo "id: {$apiKey->id}\n";
echo "name: {$apiKey->name}\n";
echo "status: {$apiKey->status}\n";
client = Anthropic::Client.new
api_key_id = "apikey_01Rj2N8SVvo6BePZj99NhmiT"
api_key = client.beta.organization.api_keys.update(
api_key_id,
status: :inactive,
name: "New Key Name"
)
puts "id: #{api_key.id}"
puts "name: #{api_key.name}"
puts "status: #{api_key.status}"
서비스 계정
서비스 계정 키와 Workload Identity Federation 토큰이 동작하는 비인간 신원인 서비스 계정(svac_...)을 만들고 관리하세요. 이 엔드포인트들은 페더레이션 발급자·페더레이션 규칙 엔드포인트처럼 org:admin OAuth 토큰이 필요해요. Admin API로 WIF 관리 참고.
페더레이션 발급자
조직의 워크로드 신원을 주장할 수 있는 토큰을 발급하는 OIDC ID 제공자(fdis_...)를 등록하세요. Admin API로 WIF 관리 참고.
페더레이션 규칙
발급자 토큰을 서비스 계정과 범위에 매핑하는 규칙(fdrl_...)을 관리하세요. Admin API로 WIF 관리 참고.
조직 정보 접근하기
/v1/organizations/me 엔드포인트는 자격 증명이 속한 조직을 반환해요:
ant beta:organization retrieve
client = anthropic.Anthropic()
organization = client.beta.organization.retrieve()
print(f"id: {organization.id}")
print(f"name: {organization.name}")
const client = new Anthropic();
const organization = await client.beta.organization.retrieve();
console.log(`id: ${organization.id}`);
console.log(`name: ${organization.name}`);
AnthropicClient client = new();
var organization = await client.Beta.Organization.Retrieve();
Console.WriteLine($"id: {organization.ID}");
Console.WriteLine($"name: {organization.Name}");
client := anthropic.NewClient()
organization, err := client.Beta.Organization.Get(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Printf("id: %s\n", organization.ID)
fmt.Printf("name: %s\n", organization.Name)
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
var organization = client.beta().organization().retrieve();
IO.println("id: " + organization.id());
IO.println("name: " + organization.name());
$client = new Client();
$organization = $client->beta->organization->retrieve();
echo "id: {$organization->id}\n";
echo "name: {$organization->name}\n";
client = Anthropic::Client.new
organization = client.beta.organization.retrieve
puts "id: #{organization.id}"
puts "name: #{organization.name}"
{
"id": "12345678-1234-5678-1234-567812345678",
"type": "organization",
"name": "Organization Name"
}
매개변수 상세와 응답 스키마는 조직 정보 API 참조를 참고하세요.
사용량 및 비용 보고서
Usage and Cost API로 조직의 사용량과 비용을 추적하세요.
Claude Code 분석
Claude Code Analytics API로 개발자 생산성과 Claude Code 도입을 모니터링하세요.
요금 한도(Rate limits)
Rate Limits API로 조직과 워크스페이스에 구성된 요금 한도를 읽으세요.
Compliance API
Compliance API로 조직의 감사·활동 데이터를 조회하세요. Admin API 키는 Activity Feed만 읽을 수 있어요. 전체 접근을 위해서는 Compliance API 설정을 참고하세요.
모범 사례
- 워크스페이스와 API 키에 의미 있는 이름과 설명을 사용하세요
- 실패한 작업의 오류를 처리하세요
- 구성원 역할과 권한을 정기적으로 감사하세요
- 사용하지 않는 워크스페이스와 만료된 초대를 정리하세요
- API 키 사용량을 모니터링하고 각 키의
expires_at을 감사하며 주기적으로 키를 교체하세요
FAQ
Admin API를 사용하는 데 필요한 권한은 무엇인가요?
Admin API는 Admin API 키(sk-ant-admin로 시작), org:admin 범위의 OAuth 베어러 토큰, 또는 특정 워크스페이스에 바인딩되지 않은 개인 키나 서비스 계정 키를 허용해요. admin 역할을 가진 조직 구성원만 Admin API 키를 발급할 수 있고, admin·owner·primary owner 역할을 가진 구성원만 org:admin 토큰을 얻을 수 있어요. 개인 키나 서비스 계정 키는 연결된 계정과 동일한 권한을 가져요. 인증 참고.
Admin API로 새 API 키를 만들 수 있나요? 아니요. API 키는 Claude Console에서 만들어요. Admin API는 기존 키를 읽고, 이름을 바꾸고, 상태를 변경만 할 수 있어요.
사용자를 제거하면 API 키는 어떻게 되나요? 동작은 키 유형에 따라 달라져요.
개인 키는 해당 사용자가 조직에서 제거되면 작동을 멈춰요. 서비스 계정 키는 서비스 계정이 보관 처리되면 작동을 멈추지만, 만든 사용자가 제거되어도 계속 작동해요. 워크스페이스 API 키는 계속 작동해요. Claude Code 워크스페이스에서 각 키는 만든 구성원에게 바인딩되며 해당 구성원이 제거되면 작동을 멈춰요.
API로 조직 admin을 제거할 수 있나요? 아니요. API는 admin 역할을 가진 구성원을 제거할 수 없어요.
조직 초대는 얼마나 오래 유지되나요? 초대는 21일 후 만료돼요. 만료 기간은 구성할 수 없어요.
워크스페이스 관련 질문은 Workspaces FAQ를 참고하세요.