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}