Skip to main content

redis_cloud/
account.rs

1//! Account management operations and models
2//!
3//! This module provides comprehensive account management functionality for Redis Cloud,
4//! including account information retrieval, settings management, API keys, owners,
5//! payment methods, SSO/SAML configuration, and billing address management.
6//!
7//! # Overview
8//!
9//! The account module is the central point for managing organization-wide settings and
10//! configurations in Redis Cloud. It handles everything from basic account information
11//! to advanced features like SSO integration and API key management.
12//!
13//! # Key Features
14//!
15//! - **Account Information**: Get current account details and metadata
16//! - **API Key Management**: Create, list, and manage API keys for programmatic access
17//! - **Owner Management**: Manage account owners and their permissions
18//! - **Payment Methods**: Handle payment methods and billing configuration
19//! - **SSO/SAML**: Configure single sign-on and SAML integration
20//! - **Billing Address**: Manage billing address information
21//!
22//! # Example Usage
23//!
24//! ```no_run
25//! use redis_cloud::{CloudClient, AccountHandler};
26//!
27//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
28//! let client = CloudClient::builder()
29//!     .api_key("your-api-key")
30//!     .api_secret("your-api-secret")
31//!     .build()?;
32//!
33//! let handler = AccountHandler::new(client);
34//!
35//! // Get current account information
36//! let account = handler.get_current_account().await?;
37//! println!("Account info: {:?}", account);
38//!
39//! // Get payment methods
40//! let payment_methods = handler.get_account_payment_methods().await?;
41//! println!("Payment methods: {:?}", payment_methods);
42//! # Ok(())
43//! # }
44//! ```
45
46use crate::types::Link;
47use crate::{CloudClient, Result};
48use serde::{Deserialize, Serialize};
49
50// ============================================================================
51// Models
52// ============================================================================
53
54/// Database modules/capabilities response
55#[derive(Debug, Clone, Serialize, Deserialize)]
56pub struct ModulesData {
57    /// Database modules supported on this account.
58    #[serde(skip_serializing_if = "Option::is_none")]
59    pub modules: Option<Vec<Module>>,
60
61    /// HATEOAS links
62    #[serde(skip_serializing_if = "Option::is_none")]
63    pub links: Option<Vec<Link>>,
64}
65
66/// Root account response from GET /
67#[derive(Debug, Clone, Serialize, Deserialize)]
68#[serde(rename_all = "camelCase")]
69pub struct RootAccount {
70    /// Account information
71    #[serde(skip_serializing_if = "Option::is_none")]
72    pub account: Option<Account>,
73
74    /// HATEOAS links
75    #[serde(skip_serializing_if = "Option::is_none")]
76    pub links: Option<Vec<Link>>,
77}
78
79/// Account information
80#[derive(Debug, Clone, Serialize, Deserialize)]
81#[serde(rename_all = "camelCase")]
82pub struct Account {
83    /// Account ID
84    #[serde(skip_serializing_if = "Option::is_none")]
85    pub id: Option<i32>,
86
87    /// Account name
88    #[serde(skip_serializing_if = "Option::is_none")]
89    pub name: Option<String>,
90
91    /// Timestamp when the account was created
92    #[serde(skip_serializing_if = "Option::is_none")]
93    pub created_timestamp: Option<String>,
94
95    /// Timestamp when the account was last updated
96    #[serde(skip_serializing_if = "Option::is_none")]
97    pub updated_timestamp: Option<String>,
98
99    /// Marketplace status (e.g., "active", "deleted")
100    #[serde(skip_serializing_if = "Option::is_none")]
101    pub marketplace_status: Option<String>,
102
103    /// API key information used for this request
104    #[serde(skip_serializing_if = "Option::is_none")]
105    pub key: Option<AccountApiKeyInfo>,
106}
107
108/// API key information returned in account response
109#[derive(Debug, Clone, Serialize, Deserialize)]
110#[serde(rename_all = "camelCase")]
111pub struct AccountApiKeyInfo {
112    /// API key name
113    #[serde(skip_serializing_if = "Option::is_none")]
114    pub name: Option<String>,
115
116    /// Account ID this key belongs to
117    #[serde(skip_serializing_if = "Option::is_none")]
118    pub account_id: Option<i32>,
119
120    /// Account name
121    #[serde(skip_serializing_if = "Option::is_none")]
122    pub account_name: Option<String>,
123
124    /// Allowed source IP addresses/CIDRs
125    #[serde(skip_serializing_if = "Option::is_none")]
126    pub allowed_source_ips: Option<Vec<String>>,
127
128    /// Owner information
129    #[serde(skip_serializing_if = "Option::is_none")]
130    pub owner: Option<AccountApiKeyOwner>,
131
132    /// User account ID
133    #[serde(skip_serializing_if = "Option::is_none")]
134    pub user_account_id: Option<i32>,
135
136    /// HTTP source IP of the current request
137    #[serde(skip_serializing_if = "Option::is_none")]
138    pub http_source_ip: Option<String>,
139
140    /// Account marketplace ID
141    #[serde(skip_serializing_if = "Option::is_none")]
142    pub account_marketplace_id: Option<String>,
143}
144
145/// API key owner information
146#[derive(Debug, Clone, Serialize, Deserialize)]
147#[serde(rename_all = "camelCase")]
148pub struct AccountApiKeyOwner {
149    /// Owner's name
150    #[serde(skip_serializing_if = "Option::is_none")]
151    pub name: Option<String>,
152
153    /// Owner's email
154    #[serde(skip_serializing_if = "Option::is_none")]
155    pub email: Option<String>,
156}
157
158/// Account system log entry
159#[derive(Debug, Clone, Serialize, Deserialize)]
160#[serde(rename_all = "camelCase")]
161pub struct AccountSystemLogEntry {
162    /// Unique log entry ID.
163    #[serde(skip_serializing_if = "Option::is_none")]
164    pub id: Option<i32>,
165
166    /// Timestamp the event was recorded (ISO-8601).
167    #[serde(skip_serializing_if = "Option::is_none")]
168    pub time: Option<String>,
169
170    /// Originator of the event (user, system, etc.).
171    #[serde(skip_serializing_if = "Option::is_none")]
172    pub originator: Option<String>,
173
174    /// Name of the API key that initiated the action, if any.
175    #[serde(skip_serializing_if = "Option::is_none")]
176    pub api_key_name: Option<String>,
177
178    /// Resource category the event applies to (e.g. `"database"`).
179    #[serde(skip_serializing_if = "Option::is_none")]
180    pub resource: Option<String>,
181
182    /// Resource ID associated with this log entry
183    #[serde(skip_serializing_if = "Option::is_none")]
184    pub resource_id: Option<i32>,
185
186    /// Event type (e.g. `"info"`, `"warning"`, `"error"`).
187    #[serde(skip_serializing_if = "Option::is_none")]
188    pub r#type: Option<String>,
189
190    /// Human-readable description of the event.
191    #[serde(skip_serializing_if = "Option::is_none")]
192    pub description: Option<String>,
193}
194
195/// Available regions response
196#[derive(Debug, Clone, Serialize, Deserialize)]
197pub struct Regions {
198    /// Regions available on the account.
199    #[serde(skip_serializing_if = "Option::is_none")]
200    pub regions: Option<Vec<Region>>,
201
202    /// HATEOAS links
203    #[serde(skip_serializing_if = "Option::is_none")]
204    pub links: Option<Vec<Link>>,
205}
206
207/// Region information
208#[derive(Debug, Clone, Serialize, Deserialize)]
209pub struct Region {
210    /// Region ID
211    #[serde(skip_serializing_if = "Option::is_none")]
212    pub id: Option<i32>,
213
214    /// Region name (e.g., "us-east-1")
215    #[serde(skip_serializing_if = "Option::is_none")]
216    pub name: Option<String>,
217
218    /// Cloud provider (e.g., "AWS", "GCP", "Azure")
219    #[serde(skip_serializing_if = "Option::is_none")]
220    pub provider: Option<String>,
221}
222
223/// Account payment methods response
224#[derive(Debug, Clone, Serialize, Deserialize)]
225#[serde(rename_all = "camelCase")]
226pub struct PaymentMethods {
227    /// Account ID the payment methods belong to.
228    #[serde(skip_serializing_if = "Option::is_none")]
229    pub account_id: Option<i32>,
230
231    /// List of payment methods
232    #[serde(skip_serializing_if = "Option::is_none")]
233    pub payment_methods: Option<Vec<PaymentMethod>>,
234
235    /// HATEOAS links
236    #[serde(skip_serializing_if = "Option::is_none")]
237    pub links: Option<Vec<Link>>,
238}
239
240/// Deserialize a field the API may send as either a JSON number or a string
241/// into an `Option<String>`.
242///
243/// Used for `creditCardEndsWith`, which the OpenAPI schema documents as a
244/// string but the live API returns as a number (see #120). A `null` or absent
245/// field yields `None`; a number is stringified; a string is kept verbatim.
246fn deserialize_opt_string_or_number<'de, D>(
247    deserializer: D,
248) -> std::result::Result<Option<String>, D::Error>
249where
250    D: serde::Deserializer<'de>,
251{
252    match serde_json::Value::deserialize(deserializer)? {
253        serde_json::Value::Null => Ok(None),
254        serde_json::Value::String(s) => Ok(Some(s)),
255        serde_json::Value::Number(n) => Ok(Some(n.to_string())),
256        other => Err(serde::de::Error::custom(format!(
257            "expected a string or number for creditCardEndsWith, got {other}"
258        ))),
259    }
260}
261
262/// Payment method information
263#[derive(Debug, Clone, Serialize, Deserialize)]
264#[serde(rename_all = "camelCase")]
265pub struct PaymentMethod {
266    /// Payment method ID
267    #[serde(skip_serializing_if = "Option::is_none")]
268    pub id: Option<i32>,
269
270    /// Card type (e.g., "Mastercard", "Visa")
271    #[serde(skip_serializing_if = "Option::is_none")]
272    pub r#type: Option<String>,
273
274    /// Last digits of the credit card.
275    ///
276    /// Kept as `Option<String>`, but deserialized with a number-or-string
277    /// helper: the OpenAPI schema documents a string, yet the live API returns
278    /// `creditCardEndsWith` as a JSON number. Accepting both keeps the public
279    /// type stable while tolerating the real response (a plain `String` failed
280    /// to deserialize — see #120). A string is preserved as-is, so a value with
281    /// leading zeros (`"0042"`) is not lost if the API ever sends one.
282    #[serde(
283        default,
284        deserialize_with = "deserialize_opt_string_or_number",
285        skip_serializing_if = "Option::is_none"
286    )]
287    pub credit_card_ends_with: Option<String>,
288
289    /// Name on the card
290    #[serde(skip_serializing_if = "Option::is_none")]
291    pub name_on_card: Option<String>,
292
293    /// Expiration month (1-12)
294    #[serde(skip_serializing_if = "Option::is_none")]
295    pub expiration_month: Option<i32>,
296
297    /// Expiration year
298    #[serde(skip_serializing_if = "Option::is_none")]
299    pub expiration_year: Option<i32>,
300
301    /// Whether this is the shopper's default payment method.
302    ///
303    /// This field is returned by the live API but is not currently documented
304    /// in the published OpenAPI schema (see #153).
305    #[serde(skip_serializing_if = "Option::is_none")]
306    pub is_default_for_shopper: Option<bool>,
307
308    /// HATEOAS links
309    #[serde(skip_serializing_if = "Option::is_none")]
310    pub links: Option<Vec<Link>>,
311}
312
313/// Database module/capability information
314#[derive(Debug, Clone, Serialize, Deserialize)]
315#[serde(rename_all = "camelCase")]
316pub struct Module {
317    /// Module name (e.g., "`RedisJSON`", "`RediSearch`")
318    #[serde(skip_serializing_if = "Option::is_none")]
319    pub name: Option<String>,
320
321    /// Capability name (e.g., "JSON", "Search and query")
322    #[serde(skip_serializing_if = "Option::is_none")]
323    pub capability_name: Option<String>,
324
325    /// Module description
326    #[serde(skip_serializing_if = "Option::is_none")]
327    pub description: Option<String>,
328
329    /// Module parameters configuration
330    #[serde(skip_serializing_if = "Option::is_none")]
331    pub parameters: Option<Vec<ModuleParameter>>,
332}
333
334/// Module parameter configuration
335#[derive(Debug, Clone, Serialize, Deserialize)]
336#[serde(rename_all = "camelCase")]
337pub struct ModuleParameter {
338    /// Parameter name
339    #[serde(skip_serializing_if = "Option::is_none")]
340    pub name: Option<String>,
341
342    /// Parameter description
343    #[serde(skip_serializing_if = "Option::is_none")]
344    pub description: Option<String>,
345
346    /// Parameter type (e.g., "integer")
347    #[serde(skip_serializing_if = "Option::is_none")]
348    pub r#type: Option<String>,
349
350    /// Default value for the parameter
351    #[serde(skip_serializing_if = "Option::is_none")]
352    pub default_value: Option<i64>,
353
354    /// Whether this parameter is required
355    #[serde(skip_serializing_if = "Option::is_none")]
356    pub required: Option<bool>,
357}
358
359/// Account system log entries response
360#[derive(Debug, Clone, Serialize, Deserialize)]
361pub struct AccountSystemLogEntries {
362    /// System log entries returned by the server.
363    #[serde(skip_serializing_if = "Option::is_none")]
364    pub entries: Option<Vec<AccountSystemLogEntry>>,
365
366    /// HATEOAS links
367    #[serde(skip_serializing_if = "Option::is_none")]
368    pub links: Option<Vec<Link>>,
369}
370
371/// Query performance factors (search scaling) response
372#[derive(Debug, Clone, Serialize, Deserialize)]
373#[serde(rename_all = "camelCase")]
374pub struct SearchScalingFactorsData {
375    /// Available query performance factors (e.g., "Standard", "2x", "4x")
376    #[serde(skip_serializing_if = "Option::is_none")]
377    pub query_performance_factors: Option<Vec<String>>,
378
379    /// HATEOAS links
380    #[serde(skip_serializing_if = "Option::is_none")]
381    pub links: Option<Vec<Link>>,
382}
383
384/// Account session log entry
385#[derive(Debug, Clone, Serialize, Deserialize)]
386#[serde(rename_all = "camelCase")]
387pub struct AccountSessionLogEntry {
388    /// Session log entry ID (UUID)
389    #[serde(skip_serializing_if = "Option::is_none")]
390    pub id: Option<String>,
391
392    /// Timestamp of the session event
393    #[serde(skip_serializing_if = "Option::is_none")]
394    pub time: Option<String>,
395
396    /// User who performed the action
397    #[serde(skip_serializing_if = "Option::is_none")]
398    pub user: Option<String>,
399
400    /// User agent string
401    #[serde(skip_serializing_if = "Option::is_none")]
402    pub user_agent: Option<String>,
403
404    /// IP address of the session
405    #[serde(skip_serializing_if = "Option::is_none")]
406    pub ip_address: Option<String>,
407
408    /// User role (e.g., "owner")
409    #[serde(skip_serializing_if = "Option::is_none")]
410    pub user_role: Option<String>,
411
412    /// Session type (e.g., "sso")
413    #[serde(skip_serializing_if = "Option::is_none")]
414    pub r#type: Option<String>,
415
416    /// Action performed (e.g., "Successful login", "Successful logout")
417    #[serde(skip_serializing_if = "Option::is_none")]
418    pub action: Option<String>,
419}
420
421/// Data persistence option entry
422#[derive(Debug, Clone, Serialize, Deserialize)]
423pub struct DataPersistenceEntry {
424    /// Persistence option name (e.g., "none", "aof-every-1-second")
425    #[serde(skip_serializing_if = "Option::is_none")]
426    pub name: Option<String>,
427
428    /// Human-readable description
429    #[serde(skip_serializing_if = "Option::is_none")]
430    pub description: Option<String>,
431}
432
433/// Data persistence options response
434#[derive(Debug, Clone, Serialize, Deserialize)]
435#[serde(rename_all = "camelCase")]
436pub struct DataPersistenceOptions {
437    /// Available data persistence options
438    #[serde(skip_serializing_if = "Option::is_none")]
439    pub data_persistence: Option<Vec<DataPersistenceEntry>>,
440
441    /// HATEOAS links
442    #[serde(skip_serializing_if = "Option::is_none")]
443    pub links: Option<Vec<Link>>,
444}
445
446/// Account session log entries response
447#[derive(Debug, Clone, Serialize, Deserialize)]
448pub struct AccountSessionLogEntries {
449    /// Session log entries returned by the server.
450    #[serde(skip_serializing_if = "Option::is_none")]
451    pub entries: Option<Vec<AccountSessionLogEntry>>,
452
453    /// HATEOAS links
454    #[serde(skip_serializing_if = "Option::is_none")]
455    pub links: Option<Vec<Link>>,
456}
457
458// ============================================================================
459// Handler
460// ============================================================================
461
462/// Account operations handler
463/// Handler for account management operations
464///
465/// Provides methods for managing account information, API keys, owners,
466/// payment methods, SSO/SAML configuration, and billing addresses.
467pub struct AccountHandler {
468    client: CloudClient,
469}
470
471impl AccountHandler {
472    /// Create a new handler
473    #[must_use]
474    pub fn new(client: CloudClient) -> Self {
475        Self { client }
476    }
477
478    /// Get current account
479    /// Gets information on this account.
480    ///
481    /// GET /
482    ///
483    /// # Example
484    ///
485    /// ```no_run
486    /// use redis_cloud::CloudClient;
487    ///
488    /// # async fn example() -> redis_cloud::Result<()> {
489    /// let client = CloudClient::builder()
490    ///     .api_key("your-api-key")
491    ///     .api_secret("your-api-secret")
492    ///     .build()?;
493    ///
494    /// let root = client.account().get_current_account().await?;
495    /// if let Some(account) = &root.account {
496    ///     println!("Account ID: {:?}", account.id);
497    /// }
498    /// # Ok(())
499    /// # }
500    /// ```
501    pub async fn get_current_account(&self) -> Result<RootAccount> {
502        self.client.get("/").await
503    }
504
505    /// Get data persistence options
506    /// Gets a list of all [data persistence](https://redis.io/docs/latest/operate/rc/databases/configuration/data-persistence/) options for this account.
507    ///
508    /// GET /data-persistence
509    pub async fn get_data_persistence_options(&self) -> Result<DataPersistenceOptions> {
510        self.client.get("/data-persistence").await
511    }
512
513    /// Get advanced capabilities
514    /// Gets a list of Redis [advanced capabilities](https://redis.io/docs/latest/operate/rc/databases/configuration/advanced-capabilities/) (also known as modules) available for this account. Advanced capability support may differ based on subscription and database settings.
515    ///
516    /// GET /database-modules
517    pub async fn get_supported_database_modules(&self) -> Result<ModulesData> {
518        self.client.get("/database-modules").await
519    }
520
521    /// Get system logs
522    /// Gets [system logs](https://redis.io/docs/latest/operate/rc/api/examples/audit-system-logs/) for this account.
523    ///
524    /// GET /logs
525    pub async fn get_account_system_logs(
526        &self,
527        offset: Option<i32>,
528        limit: Option<i32>,
529    ) -> Result<AccountSystemLogEntries> {
530        let mut query = Vec::new();
531        if let Some(v) = offset {
532            query.push(format!("offset={v}"));
533        }
534        if let Some(v) = limit {
535            query.push(format!("limit={v}"));
536        }
537        let query_string = if query.is_empty() {
538            String::new()
539        } else {
540            format!("?{}", query.join("&"))
541        };
542        self.client.get(&format!("/logs{query_string}")).await
543    }
544
545    /// Get payment methods
546    /// Gets a list of all payment methods for this account.
547    ///
548    /// GET /payment-methods
549    pub async fn get_account_payment_methods(&self) -> Result<PaymentMethods> {
550        self.client.get("/payment-methods").await
551    }
552
553    /// Get query performance factors
554    /// Gets a list of available [query performance factors](https://redis.io/docs/latest/operate/rc/databases/configuration/advanced-capabilities/#query-performance-factor).
555    ///
556    /// GET /query-performance-factors
557    pub async fn get_supported_search_scaling_factors(&self) -> Result<SearchScalingFactorsData> {
558        self.client.get("/query-performance-factors").await
559    }
560
561    /// Get available Pro plan regions
562    /// Gets a list of available regions for Pro subscriptions. For Essentials subscriptions, use 'GET /fixed/plans'.
563    ///
564    /// GET /regions
565    pub async fn get_supported_regions(&self, provider: Option<String>) -> Result<Regions> {
566        let mut query = Vec::new();
567        if let Some(v) = provider {
568            query.push(format!("provider={v}"));
569        }
570        let query_string = if query.is_empty() {
571            String::new()
572        } else {
573            format!("?{}", query.join("&"))
574        };
575        self.client.get(&format!("/regions{query_string}")).await
576    }
577
578    /// Get session logs
579    /// Gets session logs for this account.
580    ///
581    /// GET /session-logs
582    pub async fn get_account_session_logs(
583        &self,
584        offset: Option<i32>,
585        limit: Option<i32>,
586    ) -> Result<AccountSessionLogEntries> {
587        let mut query = Vec::new();
588        if let Some(v) = offset {
589            query.push(format!("offset={v}"));
590        }
591        if let Some(v) = limit {
592            query.push(format!("limit={v}"));
593        }
594        let query_string = if query.is_empty() {
595            String::new()
596        } else {
597            format!("?{}", query.join("&"))
598        };
599        self.client
600            .get(&format!("/session-logs{query_string}"))
601            .await
602    }
603
604    // ============================================================================
605    // Simplified aliases
606    // ============================================================================
607
608    /// Get the current account (simplified)
609    ///
610    /// Alias for [`get_current_account`](Self::get_current_account).
611    ///
612    /// # Example
613    ///
614    /// ```no_run
615    /// use redis_cloud::CloudClient;
616    ///
617    /// # async fn example() -> redis_cloud::Result<()> {
618    /// let client = CloudClient::builder()
619    ///     .api_key("your-api-key")
620    ///     .api_secret("your-api-secret")
621    ///     .build()?;
622    ///
623    /// let root = client.account().get().await?;
624    /// # Ok(())
625    /// # }
626    /// ```
627    pub async fn get(&self) -> Result<RootAccount> {
628        self.get_current_account().await
629    }
630
631    /// Get system logs (simplified)
632    ///
633    /// Alias for [`get_account_system_logs`](Self::get_account_system_logs).
634    ///
635    /// # Arguments
636    ///
637    /// * `offset` - Optional pagination offset
638    /// * `limit` - Optional page size limit
639    ///
640    /// # Example
641    ///
642    /// ```no_run
643    /// use redis_cloud::CloudClient;
644    ///
645    /// # async fn example() -> redis_cloud::Result<()> {
646    /// let client = CloudClient::builder()
647    ///     .api_key("your-api-key")
648    ///     .api_secret("your-api-secret")
649    ///     .build()?;
650    ///
651    /// let logs = client.account().system_logs(None, None).await?;
652    /// # Ok(())
653    /// # }
654    /// ```
655    pub async fn system_logs(
656        &self,
657        offset: Option<i32>,
658        limit: Option<i32>,
659    ) -> Result<AccountSystemLogEntries> {
660        self.get_account_system_logs(offset, limit).await
661    }
662
663    /// Get session logs (simplified)
664    ///
665    /// Alias for [`get_account_session_logs`](Self::get_account_session_logs).
666    ///
667    /// # Arguments
668    ///
669    /// * `offset` - Optional pagination offset
670    /// * `limit` - Optional page size limit
671    ///
672    /// # Example
673    ///
674    /// ```no_run
675    /// use redis_cloud::CloudClient;
676    ///
677    /// # async fn example() -> redis_cloud::Result<()> {
678    /// let client = CloudClient::builder()
679    ///     .api_key("your-api-key")
680    ///     .api_secret("your-api-secret")
681    ///     .build()?;
682    ///
683    /// let logs = client.account().session_logs(None, None).await?;
684    /// # Ok(())
685    /// # }
686    /// ```
687    pub async fn session_logs(
688        &self,
689        offset: Option<i32>,
690        limit: Option<i32>,
691    ) -> Result<AccountSessionLogEntries> {
692        self.get_account_session_logs(offset, limit).await
693    }
694
695    /// Get payment methods (simplified)
696    ///
697    /// Alias for [`get_account_payment_methods`](Self::get_account_payment_methods).
698    ///
699    /// # Example
700    ///
701    /// ```no_run
702    /// use redis_cloud::CloudClient;
703    ///
704    /// # async fn example() -> redis_cloud::Result<()> {
705    /// let client = CloudClient::builder()
706    ///     .api_key("your-api-key")
707    ///     .api_secret("your-api-secret")
708    ///     .build()?;
709    ///
710    /// let methods = client.account().payment_methods().await?;
711    /// # Ok(())
712    /// # }
713    /// ```
714    pub async fn payment_methods(&self) -> Result<PaymentMethods> {
715        self.get_account_payment_methods().await
716    }
717}