Skip to main content

claude_api/admin/
mod.rs

1//! Anthropic Admin API.
2//!
3//! Workspace-, user-, key-, and usage-management endpoints under
4//! `/v1/organizations`. **Requires an admin API key** (distinct from
5//! the regular API key used for Messages/Models/etc.) -- pass it via
6//! [`Client::builder().api_key(...)`](crate::ClientBuilder::api_key)
7//! exactly like a normal key. The wire-level `x-api-key` header is the
8//! same; only the key's permissions differ.
9//!
10//! Gated on the `admin` feature.
11//!
12//! # Layout
13//!
14//! - [`organization`] -- the authenticated organization (`me`).
15//! - [`invites`] -- create / retrieve / list / delete user invites.
16//! - [`users`] -- retrieve / list / update / delete users.
17//! - [`workspaces`] -- workspace CRUD plus archive.
18//! - [`workspace_members`] -- per-workspace membership.
19
20#![cfg(feature = "admin")]
21#![cfg_attr(docsrs, doc(cfg(feature = "admin")))]
22
23use serde::{Deserialize, Serialize};
24
25use crate::client::Client;
26
27pub mod api_keys;
28pub mod cost_report;
29pub mod invites;
30pub mod organization;
31pub mod rate_limits;
32pub mod usage_report;
33pub mod users;
34pub mod workspace_members;
35pub mod workspaces;
36
37/// Top-level namespace handle for the Admin API.
38///
39/// Obtained via [`Client::admin`].
40pub struct Admin<'a> {
41    client: &'a Client,
42}
43
44impl<'a> Admin<'a> {
45    pub(crate) fn new(client: &'a Client) -> Self {
46        Self { client }
47    }
48
49    /// Sub-namespace for the authenticated organization
50    /// (`/v1/organizations/me`).
51    #[must_use]
52    pub fn organization(&self) -> organization::Organization<'a> {
53        organization::Organization::new(self.client)
54    }
55
56    /// Sub-namespace for invites.
57    #[must_use]
58    pub fn invites(&self) -> invites::Invites<'a> {
59        invites::Invites::new(self.client)
60    }
61
62    /// Sub-namespace for organization users.
63    #[must_use]
64    pub fn users(&self) -> users::Users<'a> {
65        users::Users::new(self.client)
66    }
67
68    /// Sub-namespace for workspaces.
69    #[must_use]
70    pub fn workspaces(&self) -> workspaces::Workspaces<'a> {
71        workspaces::Workspaces::new(self.client)
72    }
73
74    /// Sub-namespace for workspace members. Scoped to a single
75    /// workspace at call time.
76    #[must_use]
77    pub fn workspace_members(
78        &self,
79        workspace_id: impl Into<String>,
80    ) -> workspace_members::WorkspaceMembers<'a> {
81        workspace_members::WorkspaceMembers::new(self.client, workspace_id.into())
82    }
83
84    /// Sub-namespace for API keys.
85    #[must_use]
86    pub fn api_keys(&self) -> api_keys::ApiKeys<'a> {
87        api_keys::ApiKeys::new(self.client)
88    }
89
90    /// Sub-namespace for the usage reports.
91    #[must_use]
92    pub fn usage_report(&self) -> usage_report::UsageReport<'a> {
93        usage_report::UsageReport::new(self.client)
94    }
95
96    /// Sub-namespace for the cost report.
97    #[must_use]
98    pub fn cost(&self) -> cost_report::Cost<'a> {
99        cost_report::Cost::new(self.client)
100    }
101
102    /// Sub-namespace for rate-limit listings (org + workspace).
103    #[must_use]
104    pub fn rate_limits(&self) -> rate_limits::RateLimits<'a> {
105        rate_limits::RateLimits::new(self.client)
106    }
107}
108
109// =====================================================================
110// Shared role + status enums
111// =====================================================================
112
113/// Organization-level user role. Forward-compatible: unknown roles
114/// fall through to [`Self::Other`].
115///
116/// Note that `admin` is read-only on responses; you cannot invite a
117/// user as `admin` or update an existing user's role to `admin`.
118#[derive(Debug, Clone, PartialEq, Eq)]
119pub enum OrganizationRole {
120    /// Standard end-user.
121    User,
122    /// Developer with API access.
123    Developer,
124    /// Billing-only access.
125    Billing,
126    /// Organization administrator (read-only on responses).
127    Admin,
128    /// Claude Code user role.
129    ClaudeCodeUser,
130    /// Unknown role; raw string preserved.
131    Other(String),
132}
133
134impl Serialize for OrganizationRole {
135    fn serialize<S: serde::Serializer>(&self, s: S) -> std::result::Result<S::Ok, S::Error> {
136        s.serialize_str(match self {
137            Self::User => "user",
138            Self::Developer => "developer",
139            Self::Billing => "billing",
140            Self::Admin => "admin",
141            Self::ClaudeCodeUser => "claude_code_user",
142            Self::Other(v) => v,
143        })
144    }
145}
146
147impl<'de> Deserialize<'de> for OrganizationRole {
148    fn deserialize<D: serde::Deserializer<'de>>(d: D) -> std::result::Result<Self, D::Error> {
149        let s = String::deserialize(d)?;
150        Ok(match s.as_str() {
151            "user" => Self::User,
152            "developer" => Self::Developer,
153            "billing" => Self::Billing,
154            "admin" => Self::Admin,
155            "claude_code_user" => Self::ClaudeCodeUser,
156            _ => Self::Other(s),
157        })
158    }
159}
160
161/// Subset of [`OrganizationRole`] valid as a write value (no `admin`).
162#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
163#[serde(rename_all = "snake_case")]
164#[non_exhaustive]
165pub enum WriteOrganizationRole {
166    /// Standard end-user.
167    User,
168    /// Developer with API access.
169    Developer,
170    /// Billing-only access.
171    Billing,
172    /// Claude Code user role.
173    ClaudeCodeUser,
174}
175
176/// Status of a pending invite.
177#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
178#[serde(rename_all = "snake_case")]
179#[non_exhaustive]
180pub enum InviteStatus {
181    /// User has accepted the invite.
182    Accepted,
183    /// Invite expired without being accepted.
184    Expired,
185    /// Invite was deleted by an admin.
186    Deleted,
187    /// Invite is outstanding.
188    Pending,
189}
190
191/// Workspace-level role.
192///
193/// `workspace_billing` is read-only on responses; you cannot create or
194/// update a member to that role.
195#[derive(Debug, Clone, PartialEq, Eq)]
196pub enum WorkspaceRole {
197    /// Standard workspace user.
198    User,
199    /// Developer with API access in this workspace.
200    Developer,
201    /// Restricted developer (subset of developer).
202    RestrictedDeveloper,
203    /// Workspace administrator.
204    Admin,
205    /// Billing-only role (read-only on responses).
206    Billing,
207    /// Unknown role; raw string preserved.
208    Other(String),
209}
210
211impl Serialize for WorkspaceRole {
212    fn serialize<S: serde::Serializer>(&self, s: S) -> std::result::Result<S::Ok, S::Error> {
213        s.serialize_str(match self {
214            Self::User => "workspace_user",
215            Self::Developer => "workspace_developer",
216            Self::RestrictedDeveloper => "workspace_restricted_developer",
217            Self::Admin => "workspace_admin",
218            Self::Billing => "workspace_billing",
219            Self::Other(v) => v,
220        })
221    }
222}
223
224impl<'de> Deserialize<'de> for WorkspaceRole {
225    fn deserialize<D: serde::Deserializer<'de>>(d: D) -> std::result::Result<Self, D::Error> {
226        let s = String::deserialize(d)?;
227        Ok(match s.as_str() {
228            "workspace_user" => Self::User,
229            "workspace_developer" => Self::Developer,
230            "workspace_restricted_developer" => Self::RestrictedDeveloper,
231            "workspace_admin" => Self::Admin,
232            "workspace_billing" => Self::Billing,
233            _ => Self::Other(s),
234        })
235    }
236}
237
238/// Subset of [`WorkspaceRole`] valid as a write value (no
239/// `workspace_billing`).
240#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
241#[serde(rename_all = "snake_case")]
242#[non_exhaustive]
243pub enum WriteWorkspaceRole {
244    /// Standard workspace user.
245    WorkspaceUser,
246    /// Developer with API access in this workspace.
247    WorkspaceDeveloper,
248    /// Restricted developer.
249    WorkspaceRestrictedDeveloper,
250    /// Workspace administrator.
251    WorkspaceAdmin,
252}
253
254/// Common pagination params for `after_id` / `before_id` / `limit`
255/// list endpoints (invites / users / workspaces / members / api keys).
256#[derive(Debug, Clone, Default)]
257#[non_exhaustive]
258pub struct ListParams {
259    /// Cursor: results immediately after this ID.
260    pub after_id: Option<String>,
261    /// Cursor: results immediately before this ID.
262    pub before_id: Option<String>,
263    /// Page size. Default 20, max 1000.
264    pub limit: Option<u32>,
265}
266
267impl ListParams {
268    pub(crate) fn to_query(&self) -> Vec<(&'static str, String)> {
269        let mut q = Vec::new();
270        if let Some(a) = &self.after_id {
271            q.push(("after_id", a.clone()));
272        }
273        if let Some(b) = &self.before_id {
274            q.push(("before_id", b.clone()));
275        }
276        if let Some(l) = self.limit {
277            q.push(("limit", l.to_string()));
278        }
279        q
280    }
281}