anthropic_api/admin/
invites.rs

1//! # Organization Invites Admin API
2//!
3//! This module provides a Rust interface to Anthropic's Admin API for managing organization invites, which allows you to
4//! list, get, create, and delete invites to your organization.
5//!
6//! ## Key Features
7//!
8//! - List all invites with pagination support
9//! - Get detailed information about a specific invite
10//! - Create new invites to the organization
11//! - Delete pending invites
12//!
13//! ## Basic Usage
14//!
15//! ```no_run
16//! use anthropic_api::{admin::invites::*, Credentials};
17//!
18//! #[tokio::main]
19//! async fn main() {
20//!     let credentials = Credentials::from_env();
21//!
22//!     // List invites
23//!     let invites = InviteList::builder()
24//!         .credentials(credentials.clone())
25//!         .create()
26//!         .await
27//!         .unwrap();
28//!
29//!     println!("Organization invites: {:?}", invites.data);
30//!
31//!     // Get a specific invite
32//!     if let Some(invite) = invites.data.first() {
33//!         let invite_details = Invite::builder(&invite.id)
34//!             .credentials(credentials.clone())
35//!             .create()
36//!             .await
37//!             .unwrap();
38//!
39//!         println!("Invite details: {:?}", invite_details);
40//!     }
41//! }
42//! ```
43
44use crate::{anthropic_request_json, ApiResponseOrError, Credentials};
45use derive_builder::Builder;
46use reqwest::Method;
47use serde::{Deserialize, Serialize};
48
49/// Organization role of an invited user
50#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
51#[serde(rename_all = "lowercase")]
52pub enum InviteRole {
53    /// Regular user
54    User,
55    /// Developer role
56    Developer,
57    /// Billing administrator
58    Billing,
59    /// Organization administrator
60    Admin,
61}
62
63/// Status of an invite
64#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
65#[serde(rename_all = "lowercase")]
66pub enum InviteStatus {
67    /// Invite has been accepted
68    Accepted,
69    /// Invite has expired
70    Expired,
71    /// Invite has been deleted
72    Deleted,
73    /// Invite is pending acceptance
74    Pending,
75}
76
77/// An invite to the organization
78#[derive(Deserialize, Debug, Clone, Eq, PartialEq)]
79pub struct Invite {
80    /// Unique invite identifier
81    pub id: String,
82    /// Email of the user being invited
83    pub email: String,
84    /// RFC 3339 datetime string indicating when the invite was created
85    pub invited_at: String,
86    /// RFC 3339 datetime string indicating when the invite expires
87    pub expires_at: String,
88    /// Role assigned to the invited user
89    pub role: InviteRole,
90    /// Current status of the invite
91    pub status: InviteStatus,
92    /// Object type (always "invite" for Invites)
93    #[serde(rename = "type")]
94    pub invite_type: String,
95}
96
97/// Response from the List Invites API
98#[derive(Deserialize, Debug, Clone, Eq, PartialEq)]
99pub struct InviteList {
100    /// List of invites in the organization
101    pub data: Vec<Invite>,
102    /// First ID in the data list (for pagination)
103    pub first_id: Option<String>,
104    /// Last ID in the data list (for pagination)
105    pub last_id: Option<String>,
106    /// Indicates if there are more results in the requested page direction
107    pub has_more: bool,
108}
109
110/// Response from the Delete Invite API
111#[derive(Deserialize, Debug, Clone, Eq, PartialEq)]
112pub struct InviteDeleted {
113    /// ID of the deleted invite
114    pub id: String,
115    /// Object type (always "invite_deleted" for deleted invites)
116    #[serde(rename = "type")]
117    pub deleted_type: String,
118}
119
120/// Request parameters for listing invites
121#[derive(Serialize, Builder, Debug, Clone)]
122#[builder(derive(Clone, Debug, PartialEq))]
123#[builder(pattern = "owned")]
124#[builder(name = "InviteListBuilder")]
125#[builder(setter(strip_option, into))]
126pub struct InviteListRequest {
127    /// ID of the object to use as a cursor for pagination (previous page)
128    #[builder(default)]
129    #[serde(skip_serializing_if = "Option::is_none")]
130    pub before_id: Option<String>,
131
132    /// ID of the object to use as a cursor for pagination (next page)
133    #[builder(default)]
134    #[serde(skip_serializing_if = "Option::is_none")]
135    pub after_id: Option<String>,
136
137    /// Number of items to return per page (1-1000)
138    #[builder(default)]
139    #[serde(skip_serializing_if = "Option::is_none")]
140    pub limit: Option<u32>,
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 invite
149#[derive(Serialize, Builder, Debug, Clone)]
150#[builder(derive(Clone, Debug, PartialEq))]
151#[builder(pattern = "owned")]
152#[builder(name = "InviteBuilder")]
153#[builder(setter(strip_option, into))]
154pub struct InviteRequest {
155    /// Invite identifier
156    pub invite_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 creating an invite
165#[derive(Serialize, Builder, Debug, Clone)]
166#[builder(derive(Clone, Debug, PartialEq))]
167#[builder(pattern = "owned")]
168#[builder(name = "InviteCreateBuilder")]
169#[builder(setter(strip_option, into))]
170pub struct InviteCreateRequest {
171    /// Email of the user to invite
172    pub email: String,
173
174    /// Role for the invited user (cannot be "admin")
175    pub role: InviteRole,
176
177    /// Credentials for authentication (not serialized)
178    #[serde(skip_serializing)]
179    #[builder(default)]
180    pub credentials: Option<Credentials>,
181}
182
183/// Request parameters for deleting an invite
184#[derive(Serialize, Builder, Debug, Clone)]
185#[builder(derive(Clone, Debug, PartialEq))]
186#[builder(pattern = "owned")]
187#[builder(name = "InviteDeleteBuilder")]
188#[builder(setter(strip_option, into))]
189pub struct InviteDeleteRequest {
190    /// Invite identifier
191    pub invite_id: String,
192
193    /// Credentials for authentication (not serialized)
194    #[serde(skip_serializing)]
195    #[builder(default)]
196    pub credentials: Option<Credentials>,
197}
198
199impl InviteList {
200    /// Creates a builder for listing invites.
201    ///
202    /// # Example
203    ///
204    /// ```no_run
205    /// # use anthropic_api::{admin::invites::*, Credentials};
206    /// # #[tokio::main]
207    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
208    /// let credentials = Credentials::from_env();
209    ///
210    /// let invites = InviteList::builder()
211    ///     .credentials(credentials)
212    ///     .limit(10u32)
213    ///     .create()
214    ///     .await?;
215    /// # Ok(())
216    /// # }
217    /// ```
218    pub fn builder() -> InviteListBuilder {
219        InviteListBuilder::create_empty()
220    }
221
222    /// Lists invites in the organization with the given request parameters.
223    ///
224    /// # Example
225    ///
226    /// ```no_run
227    /// # use anthropic_api::{admin::invites::*, Credentials};
228    /// # #[tokio::main]
229    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
230    /// let credentials = Credentials::from_env();
231    /// let request = InviteListRequest {
232    ///     before_id: None,
233    ///     after_id: None,
234    ///     limit: Some(20),
235    ///     credentials: Some(credentials),
236    /// };
237    ///
238    /// let invites = InviteList::create(request).await?;
239    /// # Ok(())
240    /// # }
241    /// ```
242    pub async fn create(request: InviteListRequest) -> ApiResponseOrError<Self> {
243        let credentials_opt = request.credentials.clone();
244
245        // Build query parameters
246        let mut query_params = Vec::new();
247        if let Some(before_id) = &request.before_id {
248            query_params.push(("before_id", before_id.clone()));
249        }
250        if let Some(after_id) = &request.after_id {
251            query_params.push(("after_id", after_id.clone()));
252        }
253        if let Some(limit) = request.limit {
254            query_params.push(("limit", limit.to_string()));
255        }
256
257        anthropic_request_json(
258            Method::GET,
259            "organizations/invites",
260            |r| r.query(&query_params),
261            credentials_opt,
262        )
263        .await
264    }
265}
266
267impl Invite {
268    /// Creates a builder for getting a specific invite.
269    ///
270    /// # Example
271    ///
272    /// ```no_run
273    /// # use anthropic_api::{admin::invites::*, Credentials};
274    /// # #[tokio::main]
275    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
276    /// let credentials = Credentials::from_env();
277    ///
278    /// let invite = Invite::builder("invite_123456789")
279    ///     .credentials(credentials)
280    ///     .create()
281    ///     .await?;
282    /// # Ok(())
283    /// # }
284    /// ```
285    pub fn builder(invite_id: impl Into<String>) -> InviteBuilder {
286        InviteBuilder::create_empty().invite_id(invite_id)
287    }
288
289    /// Gets information about a specific invite.
290    ///
291    /// # Example
292    ///
293    /// ```no_run
294    /// # use anthropic_api::{admin::invites::*, Credentials};
295    /// # #[tokio::main]
296    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
297    /// let credentials = Credentials::from_env();
298    /// let request = InviteRequest {
299    ///     invite_id: "invite_123456789".to_string(),
300    ///     credentials: Some(credentials),
301    /// };
302    ///
303    /// let invite = Invite::create(request).await?;
304    /// # Ok(())
305    /// # }
306    /// ```
307    pub async fn create(request: InviteRequest) -> ApiResponseOrError<Self> {
308        let credentials_opt = request.credentials.clone();
309        let route = format!("organizations/invites/{}", request.invite_id);
310
311        anthropic_request_json(Method::GET, &route, |r| r, credentials_opt).await
312    }
313
314    /// Creates a builder for creating a new invite.
315    ///
316    /// # Example
317    ///
318    /// ```no_run
319    /// # use anthropic_api::{admin::invites::*, Credentials};
320    /// # #[tokio::main]
321    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
322    /// let credentials = Credentials::from_env();
323    ///
324    /// let new_invite = Invite::create_builder()
325    ///     .credentials(credentials)
326    ///     .email("user@example.com")
327    ///     .role(InviteRole::Developer)
328    ///     .create()
329    ///     .await?;
330    /// # Ok(())
331    /// # }
332    /// ```
333    pub fn create_builder() -> InviteCreateBuilder {
334        InviteCreateBuilder::create_empty()
335    }
336
337    /// Creates a new invite with the given request parameters.
338    ///
339    /// # Example
340    ///
341    /// ```no_run
342    /// # use anthropic_api::{admin::invites::*, Credentials};
343    /// # #[tokio::main]
344    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
345    /// let credentials = Credentials::from_env();
346    /// let request = InviteCreateRequest {
347    ///     email: "user@example.com".to_string(),
348    ///     role: InviteRole::Developer,
349    ///     credentials: Some(credentials),
350    /// };
351    ///
352    /// let new_invite = Invite::create_new(request).await?;
353    /// # Ok(())
354    /// # }
355    /// ```
356    pub async fn create_new(request: InviteCreateRequest) -> ApiResponseOrError<Self> {
357        let credentials_opt = request.credentials.clone();
358
359        anthropic_request_json(
360            Method::POST,
361            "organizations/invites",
362            |r| r.json(&request),
363            credentials_opt,
364        )
365        .await
366    }
367
368    /// Creates a builder for deleting an invite.
369    ///
370    /// # Example
371    ///
372    /// ```no_run
373    /// # use anthropic_api::{admin::invites::*, Credentials};
374    /// # #[tokio::main]
375    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
376    /// let credentials = Credentials::from_env();
377    ///
378    /// let deleted_invite = Invite::delete_builder("invite_123456789")
379    ///     .credentials(credentials)
380    ///     .create()
381    ///     .await?;
382    /// # Ok(())
383    /// # }
384    /// ```
385    pub fn delete_builder(invite_id: impl Into<String>) -> InviteDeleteBuilder {
386        InviteDeleteBuilder::create_empty().invite_id(invite_id)
387    }
388
389    /// Deletes an invite from the organization.
390    ///
391    /// # Example
392    ///
393    /// ```no_run
394    /// # use anthropic_api::{admin::invites::*, Credentials};
395    /// # #[tokio::main]
396    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
397    /// let credentials = Credentials::from_env();
398    /// let request = InviteDeleteRequest {
399    ///     invite_id: "invite_123456789".to_string(),
400    ///     credentials: Some(credentials),
401    /// };
402    ///
403    /// let deleted_invite = Invite::delete(request).await?;
404    /// # Ok(())
405    /// # }
406    /// ```
407    pub async fn delete(request: InviteDeleteRequest) -> ApiResponseOrError<InviteDeleted> {
408        let credentials_opt = request.credentials.clone();
409        let route = format!("organizations/invites/{}", request.invite_id);
410
411        anthropic_request_json(Method::DELETE, &route, |r| r, credentials_opt).await
412    }
413}
414
415// Builder convenience methods
416impl InviteListBuilder {
417    /// Creates a new invite list request and returns the response.
418    ///
419    /// This is a convenience method that builds the request from the builder
420    /// and sends it to the Invites API.
421    ///
422    /// # Example
423    ///
424    /// ```no_run
425    /// # use anthropic_api::{admin::invites::*, Credentials};
426    /// # #[tokio::main]
427    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
428    /// let credentials = Credentials::from_env();
429    ///
430    /// let invites = InviteList::builder()
431    ///     .credentials(credentials)
432    ///     .limit(10u32)
433    ///     .create()
434    ///     .await?;
435    /// # Ok(())
436    /// # }
437    /// ```
438    pub async fn create(self) -> ApiResponseOrError<InviteList> {
439        let request = self.build().unwrap();
440        InviteList::create(request).await
441    }
442}
443
444impl InviteBuilder {
445    /// Creates a new invite request and returns the response.
446    ///
447    /// This is a convenience method that builds the request from the builder
448    /// and sends it to the Invites API.
449    ///
450    /// # Example
451    ///
452    /// ```no_run
453    /// # use anthropic_api::{admin::invites::*, Credentials};
454    /// # #[tokio::main]
455    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
456    /// let credentials = Credentials::from_env();
457    ///
458    /// let invite = Invite::builder("invite_123456789")
459    ///     .credentials(credentials)
460    ///     .create()
461    ///     .await?;
462    /// # Ok(())
463    /// # }
464    /// ```
465    pub async fn create(self) -> ApiResponseOrError<Invite> {
466        let request = self.build().unwrap();
467        Invite::create(request).await
468    }
469}
470
471impl InviteCreateBuilder {
472    /// Creates a new invite create request and returns the response.
473    ///
474    /// This is a convenience method that builds the request from the builder
475    /// and sends it to the Invites API.
476    ///
477    /// # Example
478    ///
479    /// ```no_run
480    /// # use anthropic_api::{admin::invites::*, Credentials};
481    /// # #[tokio::main]
482    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
483    /// let credentials = Credentials::from_env();
484    ///
485    /// let new_invite = Invite::create_builder()
486    ///     .credentials(credentials)
487    ///     .email("user@example.com")
488    ///     .role(InviteRole::Developer)
489    ///     .create()
490    ///     .await?;
491    /// # Ok(())
492    /// # }
493    /// ```
494    pub async fn create(self) -> ApiResponseOrError<Invite> {
495        let request = self.build().unwrap();
496        Invite::create_new(request).await
497    }
498}
499
500impl InviteDeleteBuilder {
501    /// Creates a new invite delete request and returns the response.
502    ///
503    /// This is a convenience method that builds the request from the builder
504    /// and sends it to the Invites API.
505    ///
506    /// # Example
507    ///
508    /// ```no_run
509    /// # use anthropic_api::{admin::invites::*, Credentials};
510    /// # #[tokio::main]
511    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
512    /// let credentials = Credentials::from_env();
513    ///
514    /// let deleted_invite = Invite::delete_builder("invite_123456789")
515    ///     .credentials(credentials)
516    ///     .create()
517    ///     .await?;
518    /// # Ok(())
519    /// # }
520    /// ```
521    pub async fn create(self) -> ApiResponseOrError<InviteDeleted> {
522        let request = self.build().unwrap();
523        Invite::delete(request).await
524    }
525}
526
527#[cfg(test)]
528mod tests {
529    use super::*;
530    use crate::Credentials;
531
532    #[tokio::test]
533    #[ignore] // Requires admin API key
534    async fn test_list_invites() {
535        let credentials = Credentials::from_env();
536
537        let invites = InviteList::builder()
538            .credentials(credentials)
539            .create()
540            .await
541            .unwrap();
542
543        assert!(invites.data.len() > 0);
544    }
545
546    #[tokio::test]
547    #[ignore] // Requires admin API key
548    async fn test_get_invite() {
549        let credentials = Credentials::from_env();
550
551        // First get an invite ID from the list
552        let invites = InviteList::builder()
553            .credentials(credentials.clone())
554            .create()
555            .await
556            .unwrap();
557
558        if let Some(invite) = invites.data.first() {
559            let invite_id = &invite.id;
560
561            // Then get that specific invite
562            let invite_details = Invite::builder(invite_id)
563                .credentials(credentials)
564                .create()
565                .await
566                .unwrap();
567
568            assert_eq!(invite_details.id, *invite_id);
569        }
570    }
571}