anthropic_api/admin/api_keys.rs
1//! # API Keys Admin API
2//!
3//! This module provides a Rust interface to Anthropic's Admin API for managing API keys, which allows you to
4//! list, get, and update API keys.
5//!
6//! ## Key Features
7//!
8//! - List all API keys with pagination and filtering support
9//! - Get detailed information about a specific API key
10//! - Update API key properties like name and status
11//!
12//! ## Basic Usage
13//!
14//! ```no_run
15//! use anthropic_api::{admin::api_keys::*, Credentials};
16//!
17//! #[tokio::main]
18//! async fn main() {
19//! let credentials = Credentials::from_env();
20//!
21//! // List API keys
22//! let api_keys = ApiKeyList::builder()
23//! .credentials(credentials.clone())
24//! .create()
25//! .await
26//! .unwrap();
27//!
28//! println!("Available API keys: {:?}", api_keys.data);
29//!
30//! // Get a specific API key
31//! if let Some(api_key) = api_keys.data.first() {
32//! let api_key_details = ApiKey::builder(&api_key.id)
33//! .credentials(credentials.clone())
34//! .create()
35//! .await
36//! .unwrap();
37//!
38//! println!("API key details: {:?}", api_key_details);
39//! }
40//! }
41//! ```
42
43use crate::{anthropic_request_json, ApiResponseOrError, Credentials};
44use derive_builder::Builder;
45use reqwest::Method;
46use serde::{Deserialize, Serialize};
47
48/// Status of an API key
49#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
50#[serde(rename_all = "lowercase")]
51pub enum ApiKeyStatus {
52 /// API key is active and can be used
53 Active,
54 /// API key is inactive and cannot be used
55 Inactive,
56 /// API key is archived and cannot be used
57 Archived,
58}
59
60/// Information about the creator of an API key
61#[derive(Deserialize, Debug, Clone, Eq, PartialEq)]
62pub struct ApiKeyCreator {
63 /// ID of the creator
64 pub id: String,
65 /// Type of the creator
66 #[serde(rename = "type")]
67 pub creator_type: String,
68}
69
70/// An API key available through the Anthropic Admin API.
71#[derive(Deserialize, Debug, Clone, Eq, PartialEq)]
72pub struct ApiKey {
73 /// Unique API key identifier
74 pub id: String,
75 /// Name of the API key
76 pub name: String,
77 /// RFC 3339 datetime string representing the time at which the API key was created
78 pub created_at: String,
79 /// Information about who created the API key
80 pub created_by: ApiKeyCreator,
81 /// Partially redacted hint for the API key
82 pub partial_key_hint: Option<String>,
83 /// Status of the API key
84 pub status: ApiKeyStatus,
85 /// Object type (always "api_key" for API Keys)
86 #[serde(rename = "type")]
87 pub key_type: String,
88 /// ID of the Workspace associated with the API key, or null if the API key belongs to the default Workspace
89 pub workspace_id: Option<String>,
90}
91
92/// Response from the List API Keys API.
93#[derive(Deserialize, Debug, Clone, Eq, PartialEq)]
94pub struct ApiKeyList {
95 /// List of available API keys
96 pub data: Vec<ApiKey>,
97 /// First ID in the data list (for pagination)
98 pub first_id: Option<String>,
99 /// Last ID in the data list (for pagination)
100 pub last_id: Option<String>,
101 /// Indicates if there are more results in the requested page direction
102 pub has_more: bool,
103}
104
105/// Request parameters for listing API keys.
106#[derive(Serialize, Builder, Debug, Clone)]
107#[builder(derive(Clone, Debug, PartialEq))]
108#[builder(pattern = "owned")]
109#[builder(name = "ApiKeyListBuilder")]
110#[builder(setter(strip_option, into))]
111pub struct ApiKeyListRequest {
112 /// ID of the object to use as a cursor for pagination (previous page)
113 #[builder(default)]
114 #[serde(skip_serializing_if = "Option::is_none")]
115 pub before_id: Option<String>,
116
117 /// ID of the object to use as a cursor for pagination (next page)
118 #[builder(default)]
119 #[serde(skip_serializing_if = "Option::is_none")]
120 pub after_id: Option<String>,
121
122 /// Number of items to return per page (1-1000)
123 #[builder(default)]
124 #[serde(skip_serializing_if = "Option::is_none")]
125 pub limit: Option<u32>,
126
127 /// Filter by API key status
128 #[builder(default)]
129 #[serde(skip_serializing_if = "Option::is_none")]
130 pub status: Option<ApiKeyStatus>,
131
132 /// Filter by Workspace ID
133 #[builder(default)]
134 #[serde(skip_serializing_if = "Option::is_none")]
135 pub workspace_id: Option<String>,
136
137 /// Filter by the ID of the User who created the object
138 #[builder(default)]
139 #[serde(skip_serializing_if = "Option::is_none")]
140 pub created_by_user_id: Option<String>,
141
142 /// Credentials for authentication (not serialized)
143 #[serde(skip_serializing)]
144 #[builder(default)]
145 pub credentials: Option<Credentials>,
146}
147
148/// Request parameters for getting a specific API key.
149#[derive(Serialize, Builder, Debug, Clone)]
150#[builder(derive(Clone, Debug, PartialEq))]
151#[builder(pattern = "owned")]
152#[builder(name = "ApiKeyBuilder")]
153#[builder(setter(strip_option, into))]
154pub struct ApiKeyRequest {
155 /// API key identifier
156 pub api_key_id: String,
157
158 /// Credentials for authentication (not serialized)
159 #[serde(skip_serializing)]
160 #[builder(default)]
161 pub credentials: Option<Credentials>,
162}
163
164/// Request parameters for updating an API key.
165#[derive(Serialize, Builder, Debug, Clone)]
166#[builder(derive(Clone, Debug, PartialEq))]
167#[builder(pattern = "owned")]
168#[builder(name = "ApiKeyUpdateBuilder")]
169#[builder(setter(strip_option, into))]
170pub struct ApiKeyUpdateRequest {
171 /// API key identifier (not serialized)
172 #[serde(skip_serializing)]
173 pub api_key_id: String,
174
175 /// New name for the API key
176 #[builder(default)]
177 #[serde(skip_serializing_if = "Option::is_none")]
178 pub name: Option<String>,
179
180 /// New status for the API key
181 #[builder(default)]
182 #[serde(skip_serializing_if = "Option::is_none")]
183 pub status: Option<ApiKeyStatus>,
184
185 /// Credentials for authentication (not serialized)
186 #[serde(skip_serializing)]
187 #[builder(default)]
188 pub credentials: Option<Credentials>,
189}
190
191impl ApiKeyList {
192 /// Creates a builder for listing API keys.
193 ///
194 /// # Example
195 ///
196 /// ```no_run
197 /// # use anthropic_api::{admin::api_keys::*, Credentials};
198 /// # #[tokio::main]
199 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
200 /// let credentials = Credentials::from_env();
201 ///
202 /// let api_keys = ApiKeyList::builder()
203 /// .credentials(credentials)
204 /// .limit(10u32)
205 /// .create()
206 /// .await?;
207 /// # Ok(())
208 /// # }
209 /// ```
210 pub fn builder() -> ApiKeyListBuilder {
211 ApiKeyListBuilder::create_empty()
212 }
213
214 /// Lists available API keys with the given request parameters.
215 ///
216 /// # Example
217 ///
218 /// ```no_run
219 /// # use anthropic_api::{admin::api_keys::*, Credentials};
220 /// # #[tokio::main]
221 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
222 /// let credentials = Credentials::from_env();
223 /// let request = ApiKeyListRequest {
224 /// before_id: None,
225 /// after_id: None,
226 /// limit: Some(20),
227 /// status: None,
228 /// workspace_id: None,
229 /// created_by_user_id: None,
230 /// credentials: Some(credentials),
231 /// };
232 ///
233 /// let api_keys = ApiKeyList::create(request).await?;
234 /// # Ok(())
235 /// # }
236 /// ```
237 pub async fn create(request: ApiKeyListRequest) -> ApiResponseOrError<Self> {
238 let credentials_opt = request.credentials.clone();
239
240 // Build query parameters
241 let mut query_params = Vec::new();
242 if let Some(before_id) = &request.before_id {
243 query_params.push(("before_id", before_id.clone()));
244 }
245 if let Some(after_id) = &request.after_id {
246 query_params.push(("after_id", after_id.clone()));
247 }
248 if let Some(limit) = request.limit {
249 query_params.push(("limit", limit.to_string()));
250 }
251 if let Some(status) = &request.status {
252 query_params.push(("status", format!("{:?}", status).to_lowercase()));
253 }
254 if let Some(workspace_id) = &request.workspace_id {
255 query_params.push(("workspace_id", workspace_id.clone()));
256 }
257 if let Some(created_by_user_id) = &request.created_by_user_id {
258 query_params.push(("created_by_user_id", created_by_user_id.clone()));
259 }
260
261 anthropic_request_json(
262 Method::GET,
263 "organizations/api_keys",
264 |r| r.query(&query_params),
265 credentials_opt,
266 )
267 .await
268 }
269}
270
271impl ApiKey {
272 /// Creates a builder for getting a specific API key.
273 ///
274 /// # Example
275 ///
276 /// ```no_run
277 /// # use anthropic_api::{admin::api_keys::*, Credentials};
278 /// # #[tokio::main]
279 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
280 /// let credentials = Credentials::from_env();
281 ///
282 /// let api_key = ApiKey::builder("api_key_123456789")
283 /// .credentials(credentials)
284 /// .create()
285 /// .await?;
286 /// # Ok(())
287 /// # }
288 /// ```
289 pub fn builder(api_key_id: impl Into<String>) -> ApiKeyBuilder {
290 ApiKeyBuilder::create_empty().api_key_id(api_key_id)
291 }
292
293 /// Gets information about a specific API key.
294 ///
295 /// # Example
296 ///
297 /// ```no_run
298 /// # use anthropic_api::{admin::api_keys::*, Credentials};
299 /// # #[tokio::main]
300 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
301 /// let credentials = Credentials::from_env();
302 /// let request = ApiKeyRequest {
303 /// api_key_id: "api_key_123456789".to_string(),
304 /// credentials: Some(credentials),
305 /// };
306 ///
307 /// let api_key = ApiKey::create(request).await?;
308 /// # Ok(())
309 /// # }
310 /// ```
311 pub async fn create(request: ApiKeyRequest) -> ApiResponseOrError<Self> {
312 let credentials_opt = request.credentials.clone();
313 let route = format!("organizations/api_keys/{}", request.api_key_id);
314
315 anthropic_request_json(Method::GET, &route, |r| r, credentials_opt).await
316 }
317
318 /// Creates a builder for updating an API key.
319 ///
320 /// # Example
321 ///
322 /// ```no_run
323 /// # use anthropic_api::{admin::api_keys::*, Credentials};
324 /// # #[tokio::main]
325 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
326 /// let credentials = Credentials::from_env();
327 ///
328 /// let updated_api_key = ApiKey::update_builder("api_key_123456789")
329 /// .credentials(credentials)
330 /// .name("New API Key Name")
331 /// .status(ApiKeyStatus::Inactive)
332 /// .create()
333 /// .await?;
334 /// # Ok(())
335 /// # }
336 /// ```
337 pub fn update_builder(api_key_id: impl Into<String>) -> ApiKeyUpdateBuilder {
338 ApiKeyUpdateBuilder::create_empty().api_key_id(api_key_id)
339 }
340
341 /// Updates an API key with the given request parameters.
342 ///
343 /// # Example
344 ///
345 /// ```no_run
346 /// # use anthropic_api::{admin::api_keys::*, Credentials};
347 /// # #[tokio::main]
348 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
349 /// let credentials = Credentials::from_env();
350 /// let request = ApiKeyUpdateRequest {
351 /// api_key_id: "api_key_123456789".to_string(),
352 /// name: Some("New API Key Name".to_string()),
353 /// status: Some(ApiKeyStatus::Inactive),
354 /// credentials: Some(credentials),
355 /// };
356 ///
357 /// let updated_api_key = ApiKey::update(request).await?;
358 /// # Ok(())
359 /// # }
360 /// ```
361 pub async fn update(request: ApiKeyUpdateRequest) -> ApiResponseOrError<Self> {
362 let credentials_opt = request.credentials.clone();
363 let route = format!("organizations/api_keys/{}", request.api_key_id);
364
365 anthropic_request_json(Method::POST, &route, |r| r.json(&request), credentials_opt).await
366 }
367}
368
369// Builder convenience methods
370impl ApiKeyListBuilder {
371 /// Creates a new API key list request and returns the response.
372 ///
373 /// This is a convenience method that builds the request from the builder
374 /// and sends it to the API Keys API.
375 ///
376 /// # Example
377 ///
378 /// ```no_run
379 /// # use anthropic_api::{admin::api_keys::*, Credentials};
380 /// # #[tokio::main]
381 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
382 /// let credentials = Credentials::from_env();
383 ///
384 /// let api_keys = ApiKeyList::builder()
385 /// .credentials(credentials)
386 /// .limit(10u32)
387 /// .create()
388 /// .await?;
389 /// # Ok(())
390 /// # }
391 /// ```
392 pub async fn create(self) -> ApiResponseOrError<ApiKeyList> {
393 let request = self.build().unwrap();
394 ApiKeyList::create(request).await
395 }
396}
397
398impl ApiKeyBuilder {
399 /// Creates a new API key request and returns the response.
400 ///
401 /// This is a convenience method that builds the request from the builder
402 /// and sends it to the API Keys API.
403 ///
404 /// # Example
405 ///
406 /// ```no_run
407 /// # use anthropic_api::{admin::api_keys::*, Credentials};
408 /// # #[tokio::main]
409 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
410 /// let credentials = Credentials::from_env();
411 ///
412 /// let api_key = ApiKey::builder("api_key_123456789")
413 /// .credentials(credentials)
414 /// .create()
415 /// .await?;
416 /// # Ok(())
417 /// # }
418 /// ```
419 pub async fn create(self) -> ApiResponseOrError<ApiKey> {
420 let request = self.build().unwrap();
421 ApiKey::create(request).await
422 }
423}
424
425impl ApiKeyUpdateBuilder {
426 /// Creates a new API key update request and returns the response.
427 ///
428 /// This is a convenience method that builds the request from the builder
429 /// and sends it to the API Keys API.
430 ///
431 /// # Example
432 ///
433 /// ```no_run
434 /// # use anthropic_api::{admin::api_keys::*, Credentials};
435 /// # #[tokio::main]
436 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
437 /// let credentials = Credentials::from_env();
438 ///
439 /// let updated_api_key = ApiKey::update_builder("api_key_123456789")
440 /// .credentials(credentials)
441 /// .name("New API Key Name")
442 /// .status(ApiKeyStatus::Inactive)
443 /// .create()
444 /// .await?;
445 /// # Ok(())
446 /// # }
447 /// ```
448 pub async fn create(self) -> ApiResponseOrError<ApiKey> {
449 let request = self.build().unwrap();
450 ApiKey::update(request).await
451 }
452}
453
454#[cfg(test)]
455mod tests {
456 use super::*;
457 use crate::Credentials;
458
459 #[tokio::test]
460 #[ignore] // Requires admin API key
461 async fn test_list_api_keys() {
462 let credentials = Credentials::from_env();
463
464 let api_keys = ApiKeyList::builder()
465 .credentials(credentials)
466 .create()
467 .await
468 .unwrap();
469
470 assert!(api_keys.data.len() > 0);
471 }
472
473 #[tokio::test]
474 #[ignore] // Requires admin API key
475 async fn test_get_api_key() {
476 let credentials = Credentials::from_env();
477
478 // First get an API key ID from the list
479 let api_keys = ApiKeyList::builder()
480 .credentials(credentials.clone())
481 .create()
482 .await
483 .unwrap();
484
485 if let Some(api_key) = api_keys.data.first() {
486 let api_key_id = &api_key.id;
487
488 // Then get that specific API key
489 let api_key_details = ApiKey::builder(api_key_id)
490 .credentials(credentials)
491 .create()
492 .await
493 .unwrap();
494
495 assert_eq!(api_key_details.id, *api_key_id);
496 }
497 }
498}