Skip to main content

clickhouse_cloud_api/
client.rs

1//! HTTP client for the ClickHouse Cloud API.
2//!
3//! Auto-generated from the OpenAPI specification.
4
5use crate::error::Error;
6use crate::models::*;
7
8/// Authentication mode for the API client.
9#[derive(Debug, Clone)]
10enum Auth {
11    Basic { key_id: String, key_secret: String },
12    Bearer { token: String },
13}
14
15/// Credentials for a single Query API request. Basic carries a per-service
16/// Query API key; Bearer carries the user's OAuth token.
17enum QueryAuth<'a> {
18    Basic {
19        key_id: &'a str,
20        key_secret: &'a str,
21    },
22    Bearer {
23        token: &'a str,
24    },
25}
26
27/// ClickHouse Cloud API client.
28///
29/// Supports both HTTP Basic Auth (API key/secret) and Bearer token (OAuth) authentication.
30#[derive(Debug, Clone)]
31pub struct Client {
32    http: reqwest::Client,
33    base_url: String,
34    auth: Auth,
35    /// Explicit Query API host override; see [`Client::with_query_host`].
36    query_host: Option<String>,
37}
38
39/// Derive the Query API host from a management API base URL by swapping the
40/// `api.` host prefix for `queries.`, so each environment talks to its own
41/// query host. Staging and dev serve the management API under an extra
42/// `control-plane.` label that the query host doesn't have, so it is
43/// dropped too:
44///
45/// - `https://api.clickhouse.cloud` → `https://queries.clickhouse.cloud`
46/// - `https://api.control-plane.clickhouse-staging.com` →
47///   `https://queries.clickhouse-staging.com`
48///
49/// Returns `None` when the base URL isn't of that shape (e.g. a localhost
50/// test server).
51fn derive_query_host(base_url: &str) -> Option<String> {
52    let parsed = url::Url::parse(base_url).ok()?;
53    let rest = parsed.host_str()?.strip_prefix("api.")?;
54    let rest = rest.strip_prefix("control-plane.").unwrap_or(rest);
55    let port = parsed.port().map(|p| format!(":{p}")).unwrap_or_default();
56    Some(format!("{}://queries.{}{}", parsed.scheme(), rest, port))
57}
58
59impl Client {
60    /// Create a new client with the default base URL (`https://api.clickhouse.cloud`).
61    pub fn new(key_id: impl Into<String>, key_secret: impl Into<String>) -> Self {
62        Self::with_base_url("https://api.clickhouse.cloud", key_id, key_secret)
63    }
64
65    /// Create a new client with a custom base URL.
66    pub fn with_base_url(
67        base_url: impl Into<String>,
68        key_id: impl Into<String>,
69        key_secret: impl Into<String>,
70    ) -> Self {
71        Self {
72            http: reqwest::Client::new(),
73            base_url: base_url.into().trim_end_matches('/').to_string(),
74            auth: Auth::Basic {
75                key_id: key_id.into(),
76                key_secret: key_secret.into(),
77            },
78            query_host: None,
79        }
80    }
81
82    /// Create a new client with Bearer token authentication and a custom base URL.
83    pub fn with_bearer_token(base_url: impl Into<String>, token: impl Into<String>) -> Self {
84        Self {
85            http: reqwest::Client::new(),
86            base_url: base_url.into().trim_end_matches('/').to_string(),
87            auth: Auth::Bearer {
88                token: token.into(),
89            },
90            query_host: None,
91        }
92    }
93
94    /// Create a new client with a pre-built HTTP client and Basic auth.
95    ///
96    /// Use this when you need to customize the underlying `reqwest::Client`
97    /// (e.g. to set a custom user-agent or timeout).
98    pub fn with_http_client(
99        http: reqwest::Client,
100        base_url: impl Into<String>,
101        key_id: impl Into<String>,
102        key_secret: impl Into<String>,
103    ) -> Self {
104        Self {
105            http,
106            base_url: base_url.into().trim_end_matches('/').to_string(),
107            auth: Auth::Basic {
108                key_id: key_id.into(),
109                key_secret: key_secret.into(),
110            },
111            query_host: None,
112        }
113    }
114
115    /// Create a new client with a pre-built HTTP client and Bearer auth.
116    ///
117    /// Use this when you need to customize the underlying `reqwest::Client`
118    /// (e.g. to set a custom user-agent or timeout).
119    pub fn with_http_client_bearer(
120        http: reqwest::Client,
121        base_url: impl Into<String>,
122        token: impl Into<String>,
123    ) -> Self {
124        Self {
125            http,
126            base_url: base_url.into().trim_end_matches('/').to_string(),
127            auth: Auth::Bearer {
128                token: token.into(),
129            },
130            query_host: None,
131        }
132    }
133
134    /// Replace the Bearer token without rebuilding the client.
135    ///
136    /// Useful for refreshing an expired OAuth token.
137    /// Returns an error if the client is using Basic auth.
138    pub fn set_bearer_token(&mut self, token: impl Into<String>) -> Result<(), Error> {
139        match &mut self.auth {
140            Auth::Bearer { token: t } => {
141                *t = token.into();
142                Ok(())
143            }
144            Auth::Basic { .. } => Err(Error::AuthMismatch(
145                "set_bearer_token called on a Basic-auth client".into(),
146            )),
147        }
148    }
149
150    /// Override the Query API host used by [`Client::run_query`] and
151    /// [`Client::run_query_bearer`].
152    ///
153    /// When not set, the host is taken from the `CLICKHOUSE_CLOUD_QUERY_HOST`
154    /// env var if present, otherwise derived from the client's base URL
155    /// (`api.<domain>` → `queries.<domain>`), falling back to the production
156    /// host `https://queries.clickhouse.cloud`.
157    pub fn with_query_host(mut self, host: impl Into<String>) -> Self {
158        self.query_host = Some(host.into().trim_end_matches('/').to_string());
159        self
160    }
161
162    /// Resolve the Query API host: explicit override, then env var, then
163    /// derivation from the base URL, then the production default.
164    fn resolved_query_host(&self) -> String {
165        if let Some(host) = &self.query_host {
166            return host.clone();
167        }
168        if let Ok(host) = std::env::var("CLICKHOUSE_CLOUD_QUERY_HOST") {
169            return host;
170        }
171        derive_query_host(&self.base_url)
172            .unwrap_or_else(|| "https://queries.clickhouse.cloud".to_string())
173    }
174
175    fn request(&self, method: reqwest::Method, path: &str) -> reqwest::RequestBuilder {
176        let builder = self
177            .http
178            .request(method, format!("{}{}", self.base_url, path));
179        match &self.auth {
180            Auth::Basic { key_id, key_secret } => builder.basic_auth(key_id, Some(key_secret)),
181            Auth::Bearer { token } => builder.bearer_auth(token),
182        }
183    }
184
185    /// Run a SQL statement against a service's Query API endpoint.
186    ///
187    /// Hits the environment's query host (see [`Client::with_query_host`]
188    /// for resolution order) using Basic auth with the provided
189    /// `key_id`/`key_secret` — a per-service key bound to a query endpoint
190    /// with role `sql_console_read_only` (or `sql_console_admin`). This
191    /// bypasses the client's primary auth because Query API keys are scoped
192    /// to a single service.
193    ///
194    /// `wake_service` resends the wake confirmation the query host asks for
195    /// when the target service is idled — see [`Error::ServiceIdle`].
196    ///
197    /// Returns the streaming response so the caller can forward it to
198    /// stdout or buffer it into memory.
199    #[allow(clippy::too_many_arguments)]
200    pub async fn run_query(
201        &self,
202        service_id: &str,
203        key_id: &str,
204        key_secret: &str,
205        sql: &str,
206        database: Option<&str>,
207        format: &str,
208        wake_service: bool,
209    ) -> Result<reqwest::Response, Error> {
210        self.run_query_with(
211            QueryAuth::Basic { key_id, key_secret },
212            service_id,
213            sql,
214            database,
215            format,
216            wake_service,
217        )
218        .await
219    }
220
221    /// Run a SQL statement against a service's Query API endpoint using the
222    /// client's own OAuth Bearer token.
223    ///
224    /// Unlike [`Client::run_query`], no per-service Query API key and no
225    /// query-endpoint configuration are needed: the Query API authenticates
226    /// the user's identity directly and grants read-only SQL access (SELECT
227    /// and other read statements only; no INSERT, DDL, or other writes).
228    ///
229    /// `wake_service` resends the wake confirmation the query host asks for
230    /// when the target service is idled — see [`Error::ServiceIdle`].
231    ///
232    /// Returns an error if the client is using Basic auth.
233    pub async fn run_query_bearer(
234        &self,
235        service_id: &str,
236        sql: &str,
237        database: Option<&str>,
238        format: &str,
239        wake_service: bool,
240    ) -> Result<reqwest::Response, Error> {
241        let token = match &self.auth {
242            Auth::Bearer { token } => token,
243            Auth::Basic { .. } => {
244                return Err(Error::AuthMismatch(
245                    "run_query_bearer called on a Basic-auth client".into(),
246                ));
247            }
248        };
249        self.run_query_with(
250            QueryAuth::Bearer { token },
251            service_id,
252            sql,
253            database,
254            format,
255            wake_service,
256        )
257        .await
258    }
259
260    async fn run_query_with(
261        &self,
262        auth: QueryAuth<'_>,
263        service_id: &str,
264        sql: &str,
265        database: Option<&str>,
266        format: &str,
267        wake_service: bool,
268    ) -> Result<reqwest::Response, Error> {
269        #[derive(serde::Serialize)]
270        #[serde(rename_all = "camelCase")]
271        struct RunQueryBody<'a> {
272            run_id: String,
273            sql: &'a str,
274            #[serde(skip_serializing_if = "Option::is_none")]
275            database: Option<&'a str>,
276        }
277
278        let url = format!(
279            "{}/service/{}/run",
280            self.resolved_query_host().trim_end_matches('/'),
281            service_id,
282        );
283
284        let body = RunQueryBody {
285            run_id: uuid::Uuid::new_v4().to_string(),
286            sql,
287            database,
288        };
289
290        let request = self
291            .http
292            .post(url)
293            .query(&[("format", format)])
294            .header("content-type", "text/plain;charset=UTF-8")
295            .header("x-service-type", "clickhouse");
296        // `wake-service: true` is the wake confirmation the query host asks
297        // for via a 206 `Confirm wake service` response (the SQL console
298        // sends it after prompting the user).
299        let request = if wake_service {
300            request.header("wake-service", "true")
301        } else {
302            request
303        };
304        // `auth-provider: custom` tells the query host the credentials are a
305        // custom (user-provisioned) Query API key. Bearer tokens carry their
306        // own provider information, so the header is omitted for them.
307        let request = match auth {
308            QueryAuth::Basic { key_id, key_secret } => request
309                .basic_auth(key_id, Some(key_secret))
310                .header("auth-provider", "custom"),
311            QueryAuth::Bearer { token } => request.bearer_auth(token),
312        };
313
314        let response = request.json(&body).send().await?;
315
316        let status = response.status();
317        // 206 means the service can't take the query in its current state:
318        // `Confirm wake service` for an idled service (resend with the
319        // wake confirmation to wake it and run the query), `Service is
320        // stopped` for one that must be started explicitly.
321        if status.as_u16() == 206 {
322            let body_text = response.text().await.unwrap_or_default();
323            #[derive(serde::Deserialize)]
324            struct StateBody {
325                data: Option<String>,
326            }
327            let data = serde_json::from_str::<StateBody>(&body_text)
328                .ok()
329                .and_then(|b| b.data);
330            return Err(match data.as_deref() {
331                Some("Confirm wake service") => Error::ServiceIdle,
332                Some("Service is stopped") => Error::ServiceStopped,
333                _ => Error::Api {
334                    status: 206,
335                    message: body_text,
336                },
337            });
338        }
339        if !status.is_success() {
340            let body_text = response.text().await.unwrap_or_default();
341            return Err(Error::Api {
342                status: status.as_u16(),
343                message: if body_text.is_empty() {
344                    format!("Query API returned {status}")
345                } else {
346                    body_text
347                },
348            });
349        }
350
351        Ok(response)
352    }
353
354    /// Get list of available organizations
355    pub async fn organization_get_list(&self) -> Result<ApiResponse<Vec<Organization>>, Error> {
356        let path = "/v1/organizations".to_string();
357        let req = self.request(reqwest::Method::GET, &path);
358        let resp = req.send().await?;
359        let status = resp.status();
360        let body_text = resp.text().await?;
361        if !status.is_success() {
362            return Err(Error::Api {
363                status: status.as_u16(),
364                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
365                    .ok()
366                    .and_then(|r| r.error)
367                    .unwrap_or(body_text.clone()),
368            });
369        }
370        Ok(serde_json::from_str(&body_text)?)
371    }
372
373    /// Get organization details
374    pub async fn organization_get(
375        &self,
376        organization_id: &str,
377    ) -> Result<ApiResponse<Organization>, Error> {
378        let path = format!("/v1/organizations/{organization_id}");
379        let req = self.request(reqwest::Method::GET, &path);
380        let resp = req.send().await?;
381        let status = resp.status();
382        let body_text = resp.text().await?;
383        if !status.is_success() {
384            return Err(Error::Api {
385                status: status.as_u16(),
386                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
387                    .ok()
388                    .and_then(|r| r.error)
389                    .unwrap_or(body_text.clone()),
390            });
391        }
392        Ok(serde_json::from_str(&body_text)?)
393    }
394
395    /// Get organization quotas
396    pub async fn organization_quotas_get_list(
397        &self,
398        organization_id: &str,
399    ) -> Result<ApiResponse<Vec<OrganizationQuota>>, Error> {
400        let path = format!("/v1/organizations/{organization_id}/quotas");
401        let req = self.request(reqwest::Method::GET, &path);
402        let resp = req.send().await?;
403        let status = resp.status();
404        let body_text = resp.text().await?;
405        if !status.is_success() {
406            return Err(Error::Api {
407                status: status.as_u16(),
408                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
409                    .ok()
410                    .and_then(|r| r.error)
411                    .unwrap_or(body_text.clone()),
412            });
413        }
414        Ok(serde_json::from_str(&body_text)?)
415    }
416
417    /// Get organization quota details
418    pub async fn organization_quota_get(
419        &self,
420        organization_id: &str,
421        quota_code: &str,
422    ) -> Result<ApiResponse<OrganizationQuota>, Error> {
423        let path = format!("/v1/organizations/{organization_id}/quotas/{quota_code}");
424        let req = self.request(reqwest::Method::GET, &path);
425        let resp = req.send().await?;
426        let status = resp.status();
427        let body_text = resp.text().await?;
428        if !status.is_success() {
429            return Err(Error::Api {
430                status: status.as_u16(),
431                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
432                    .ok()
433                    .and_then(|r| r.error)
434                    .unwrap_or(body_text.clone()),
435            });
436        }
437        Ok(serde_json::from_str(&body_text)?)
438    }
439
440    /// Update organization details
441    pub async fn organization_update(
442        &self,
443        organization_id: &str,
444        body: &OrganizationPatchRequest,
445    ) -> Result<ApiResponse<Organization>, Error> {
446        let path = format!("/v1/organizations/{organization_id}");
447        let mut req = self.request(reqwest::Method::PATCH, &path);
448        req = req.json(body);
449        let resp = req.send().await?;
450        let status = resp.status();
451        let body_text = resp.text().await?;
452        if !status.is_success() {
453            return Err(Error::Api {
454                status: status.as_u16(),
455                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
456                    .ok()
457                    .and_then(|r| r.error)
458                    .unwrap_or(body_text.clone()),
459            });
460        }
461        Ok(serde_json::from_str(&body_text)?)
462    }
463
464    /// List of organization activities
465    pub async fn activity_get_list(
466        &self,
467        organization_id: &str,
468        from_date: Option<&str>,
469        to_date: Option<&str>,
470    ) -> Result<ApiResponse<Vec<Activity>>, Error> {
471        let path = format!("/v1/organizations/{organization_id}/activities");
472        let mut req = self.request(reqwest::Method::GET, &path);
473        if let Some(v) = from_date {
474            req = req.query(&[("from_date", v)]);
475        }
476        if let Some(v) = to_date {
477            req = req.query(&[("to_date", v)]);
478        }
479        let resp = req.send().await?;
480        let status = resp.status();
481        let body_text = resp.text().await?;
482        if !status.is_success() {
483            return Err(Error::Api {
484                status: status.as_u16(),
485                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
486                    .ok()
487                    .and_then(|r| r.error)
488                    .unwrap_or(body_text.clone()),
489            });
490        }
491        Ok(serde_json::from_str(&body_text)?)
492    }
493
494    /// Organization activity
495    pub async fn activity_get(
496        &self,
497        organization_id: &str,
498        activity_id: &str,
499    ) -> Result<ApiResponse<Activity>, Error> {
500        let path = format!("/v1/organizations/{organization_id}/activities/{activity_id}");
501        let req = self.request(reqwest::Method::GET, &path);
502        let resp = req.send().await?;
503        let status = resp.status();
504        let body_text = resp.text().await?;
505        if !status.is_success() {
506            return Err(Error::Api {
507                status: status.as_u16(),
508                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
509                    .ok()
510                    .and_then(|r| r.error)
511                    .unwrap_or(body_text.clone()),
512            });
513        }
514        Ok(serde_json::from_str(&body_text)?)
515    }
516
517    /// Create BYOC Infrastructure
518    pub async fn organization_byoc_infrastructure_create(
519        &self,
520        organization_id: &str,
521        body: &ByocInfrastructurePostRequest,
522    ) -> Result<ApiResponse<ByocConfig>, Error> {
523        let path = format!("/v1/organizations/{organization_id}/byocInfrastructure");
524        let mut req = self.request(reqwest::Method::POST, &path);
525        req = req.json(body);
526        let resp = req.send().await?;
527        let status = resp.status();
528        let body_text = resp.text().await?;
529        if !status.is_success() {
530            return Err(Error::Api {
531                status: status.as_u16(),
532                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
533                    .ok()
534                    .and_then(|r| r.error)
535                    .unwrap_or(body_text.clone()),
536            });
537        }
538        Ok(serde_json::from_str(&body_text)?)
539    }
540
541    /// Remove a BYOC infrastructure
542    pub async fn organization_byoc_infrastructure_delete(
543        &self,
544        organization_id: &str,
545        byoc_infrastructure_id: &str,
546    ) -> Result<ApiResponse<serde_json::Value>, Error> {
547        let path = format!(
548            "/v1/organizations/{organization_id}/byocInfrastructure/{byoc_infrastructure_id}"
549        );
550        let req = self.request(reqwest::Method::DELETE, &path);
551        let resp = req.send().await?;
552        let status = resp.status();
553        let body_text = resp.text().await?;
554        if !status.is_success() {
555            return Err(Error::Api {
556                status: status.as_u16(),
557                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
558                    .ok()
559                    .and_then(|r| r.error)
560                    .unwrap_or(body_text.clone()),
561            });
562        }
563        Ok(serde_json::from_str(&body_text)?)
564    }
565
566    /// Update BYOC Infrastructure
567    pub async fn organization_byoc_infrastructure_update(
568        &self,
569        organization_id: &str,
570        byoc_infrastructure_id: &str,
571        body: &ByocInfrastructurePatchRequest,
572    ) -> Result<ApiResponse<ByocConfig>, Error> {
573        let path = format!(
574            "/v1/organizations/{organization_id}/byocInfrastructure/{byoc_infrastructure_id}"
575        );
576        let mut req = self.request(reqwest::Method::PATCH, &path);
577        req = req.json(body);
578        let resp = req.send().await?;
579        let status = resp.status();
580        let body_text = resp.text().await?;
581        if !status.is_success() {
582            return Err(Error::Api {
583                status: status.as_u16(),
584                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
585                    .ok()
586                    .and_then(|r| r.error)
587                    .unwrap_or(body_text.clone()),
588            });
589        }
590        Ok(serde_json::from_str(&body_text)?)
591    }
592
593    /// List all invitations
594    pub async fn invitation_get_list(
595        &self,
596        organization_id: &str,
597    ) -> Result<ApiResponse<Vec<Invitation>>, Error> {
598        let path = format!("/v1/organizations/{organization_id}/invitations");
599        let req = self.request(reqwest::Method::GET, &path);
600        let resp = req.send().await?;
601        let status = resp.status();
602        let body_text = resp.text().await?;
603        if !status.is_success() {
604            return Err(Error::Api {
605                status: status.as_u16(),
606                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
607                    .ok()
608                    .and_then(|r| r.error)
609                    .unwrap_or(body_text.clone()),
610            });
611        }
612        Ok(serde_json::from_str(&body_text)?)
613    }
614
615    /// Create an invitation
616    pub async fn invitation_create(
617        &self,
618        organization_id: &str,
619        body: &InvitationPostRequest,
620    ) -> Result<ApiResponse<Invitation>, Error> {
621        let path = format!("/v1/organizations/{organization_id}/invitations");
622        let mut req = self.request(reqwest::Method::POST, &path);
623        req = req.json(body);
624        let resp = req.send().await?;
625        let status = resp.status();
626        let body_text = resp.text().await?;
627        if !status.is_success() {
628            return Err(Error::Api {
629                status: status.as_u16(),
630                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
631                    .ok()
632                    .and_then(|r| r.error)
633                    .unwrap_or(body_text.clone()),
634            });
635        }
636        Ok(serde_json::from_str(&body_text)?)
637    }
638
639    /// Get invitation details
640    pub async fn invitation_get(
641        &self,
642        organization_id: &str,
643        invitation_id: &str,
644    ) -> Result<ApiResponse<Invitation>, Error> {
645        let path = format!("/v1/organizations/{organization_id}/invitations/{invitation_id}");
646        let req = self.request(reqwest::Method::GET, &path);
647        let resp = req.send().await?;
648        let status = resp.status();
649        let body_text = resp.text().await?;
650        if !status.is_success() {
651            return Err(Error::Api {
652                status: status.as_u16(),
653                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
654                    .ok()
655                    .and_then(|r| r.error)
656                    .unwrap_or(body_text.clone()),
657            });
658        }
659        Ok(serde_json::from_str(&body_text)?)
660    }
661
662    /// Delete organization invitation
663    pub async fn invitation_delete(
664        &self,
665        organization_id: &str,
666        invitation_id: &str,
667    ) -> Result<ApiResponse<serde_json::Value>, Error> {
668        let path = format!("/v1/organizations/{organization_id}/invitations/{invitation_id}");
669        let req = self.request(reqwest::Method::DELETE, &path);
670        let resp = req.send().await?;
671        let status = resp.status();
672        let body_text = resp.text().await?;
673        if !status.is_success() {
674            return Err(Error::Api {
675                status: status.as_u16(),
676                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
677                    .ok()
678                    .and_then(|r| r.error)
679                    .unwrap_or(body_text.clone()),
680            });
681        }
682        Ok(serde_json::from_str(&body_text)?)
683    }
684
685    /// Get list of all keys
686    pub async fn openapi_key_get_list(
687        &self,
688        organization_id: &str,
689    ) -> Result<ApiResponse<Vec<ApiKey>>, Error> {
690        let path = format!("/v1/organizations/{organization_id}/keys");
691        let req = self.request(reqwest::Method::GET, &path);
692        let resp = req.send().await?;
693        let status = resp.status();
694        let body_text = resp.text().await?;
695        if !status.is_success() {
696            return Err(Error::Api {
697                status: status.as_u16(),
698                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
699                    .ok()
700                    .and_then(|r| r.error)
701                    .unwrap_or(body_text.clone()),
702            });
703        }
704        Ok(serde_json::from_str(&body_text)?)
705    }
706
707    /// Create key
708    pub async fn openapi_key_create(
709        &self,
710        organization_id: &str,
711        body: &ApiKeyPostRequest,
712    ) -> Result<ApiResponse<ApiKeyPostResponse>, Error> {
713        let path = format!("/v1/organizations/{organization_id}/keys");
714        let mut req = self.request(reqwest::Method::POST, &path);
715        req = req.json(body);
716        let resp = req.send().await?;
717        let status = resp.status();
718        let body_text = resp.text().await?;
719        if !status.is_success() {
720            return Err(Error::Api {
721                status: status.as_u16(),
722                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
723                    .ok()
724                    .and_then(|r| r.error)
725                    .unwrap_or(body_text.clone()),
726            });
727        }
728        Ok(serde_json::from_str(&body_text)?)
729    }
730
731    /// Get key details
732    pub async fn openapi_key_get(
733        &self,
734        organization_id: &str,
735        key_id: &str,
736    ) -> Result<ApiResponse<ApiKey>, Error> {
737        let path = format!("/v1/organizations/{organization_id}/keys/{key_id}");
738        let req = self.request(reqwest::Method::GET, &path);
739        let resp = req.send().await?;
740        let status = resp.status();
741        let body_text = resp.text().await?;
742        if !status.is_success() {
743            return Err(Error::Api {
744                status: status.as_u16(),
745                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
746                    .ok()
747                    .and_then(|r| r.error)
748                    .unwrap_or(body_text.clone()),
749            });
750        }
751        Ok(serde_json::from_str(&body_text)?)
752    }
753
754    /// Update key
755    pub async fn openapi_key_update(
756        &self,
757        organization_id: &str,
758        key_id: &str,
759        body: &ApiKeyPatchRequest,
760    ) -> Result<ApiResponse<ApiKey>, Error> {
761        let path = format!("/v1/organizations/{organization_id}/keys/{key_id}");
762        let mut req = self.request(reqwest::Method::PATCH, &path);
763        req = req.json(body);
764        let resp = req.send().await?;
765        let status = resp.status();
766        let body_text = resp.text().await?;
767        if !status.is_success() {
768            return Err(Error::Api {
769                status: status.as_u16(),
770                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
771                    .ok()
772                    .and_then(|r| r.error)
773                    .unwrap_or(body_text.clone()),
774            });
775        }
776        Ok(serde_json::from_str(&body_text)?)
777    }
778
779    /// Delete key
780    pub async fn openapi_key_delete(
781        &self,
782        organization_id: &str,
783        key_id: &str,
784    ) -> Result<ApiResponse<serde_json::Value>, Error> {
785        let path = format!("/v1/organizations/{organization_id}/keys/{key_id}");
786        let req = self.request(reqwest::Method::DELETE, &path);
787        let resp = req.send().await?;
788        let status = resp.status();
789        let body_text = resp.text().await?;
790        if !status.is_success() {
791            return Err(Error::Api {
792                status: status.as_u16(),
793                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
794                    .ok()
795                    .and_then(|r| r.error)
796                    .unwrap_or(body_text.clone()),
797            });
798        }
799        Ok(serde_json::from_str(&body_text)?)
800    }
801
802    /// List organization members
803    pub async fn member_get_list(
804        &self,
805        organization_id: &str,
806    ) -> Result<ApiResponse<Vec<Member>>, Error> {
807        let path = format!("/v1/organizations/{organization_id}/members");
808        let req = self.request(reqwest::Method::GET, &path);
809        let resp = req.send().await?;
810        let status = resp.status();
811        let body_text = resp.text().await?;
812        if !status.is_success() {
813            return Err(Error::Api {
814                status: status.as_u16(),
815                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
816                    .ok()
817                    .and_then(|r| r.error)
818                    .unwrap_or(body_text.clone()),
819            });
820        }
821        Ok(serde_json::from_str(&body_text)?)
822    }
823
824    /// Get member details
825    pub async fn member_get(
826        &self,
827        organization_id: &str,
828        user_id: &str,
829    ) -> Result<ApiResponse<Member>, Error> {
830        let path = format!("/v1/organizations/{organization_id}/members/{user_id}");
831        let req = self.request(reqwest::Method::GET, &path);
832        let resp = req.send().await?;
833        let status = resp.status();
834        let body_text = resp.text().await?;
835        if !status.is_success() {
836            return Err(Error::Api {
837                status: status.as_u16(),
838                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
839                    .ok()
840                    .and_then(|r| r.error)
841                    .unwrap_or(body_text.clone()),
842            });
843        }
844        Ok(serde_json::from_str(&body_text)?)
845    }
846
847    /// Update organization member
848    pub async fn member_update(
849        &self,
850        organization_id: &str,
851        user_id: &str,
852        body: &MemberPatchRequest,
853    ) -> Result<ApiResponse<Member>, Error> {
854        let path = format!("/v1/organizations/{organization_id}/members/{user_id}");
855        let mut req = self.request(reqwest::Method::PATCH, &path);
856        req = req.json(body);
857        let resp = req.send().await?;
858        let status = resp.status();
859        let body_text = resp.text().await?;
860        if !status.is_success() {
861            return Err(Error::Api {
862                status: status.as_u16(),
863                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
864                    .ok()
865                    .and_then(|r| r.error)
866                    .unwrap_or(body_text.clone()),
867            });
868        }
869        Ok(serde_json::from_str(&body_text)?)
870    }
871
872    /// Remove an organization member
873    pub async fn member_delete(
874        &self,
875        organization_id: &str,
876        user_id: &str,
877    ) -> Result<ApiResponse<serde_json::Value>, Error> {
878        let path = format!("/v1/organizations/{organization_id}/members/{user_id}");
879        let req = self.request(reqwest::Method::DELETE, &path);
880        let resp = req.send().await?;
881        let status = resp.status();
882        let body_text = resp.text().await?;
883        if !status.is_success() {
884            return Err(Error::Api {
885                status: status.as_u16(),
886                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
887                    .ok()
888                    .and_then(|r| r.error)
889                    .unwrap_or(body_text.clone()),
890            });
891        }
892        Ok(serde_json::from_str(&body_text)?)
893    }
894
895    /// List all available roles for an organization
896    pub async fn organization_roles_get_list(
897        &self,
898        organization_id: &str,
899    ) -> Result<ApiResponse<Vec<RBACRole>>, Error> {
900        let path = format!("/v1/organizations/{organization_id}/roles");
901        let req = self.request(reqwest::Method::GET, &path);
902        let resp = req.send().await?;
903        let status = resp.status();
904        let body_text = resp.text().await?;
905        if !status.is_success() {
906            return Err(Error::Api {
907                status: status.as_u16(),
908                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
909                    .ok()
910                    .and_then(|r| r.error)
911                    .unwrap_or(body_text.clone()),
912            });
913        }
914        Ok(serde_json::from_str(&body_text)?)
915    }
916
917    /// Create a new role
918    pub async fn organization_role_post(
919        &self,
920        organization_id: &str,
921        body: &RoleCreateRequest,
922    ) -> Result<ApiResponse<RBACRole>, Error> {
923        let path = format!("/v1/organizations/{organization_id}/roles");
924        let mut req = self.request(reqwest::Method::POST, &path);
925        req = req.json(body);
926        let resp = req.send().await?;
927        let status = resp.status();
928        let body_text = resp.text().await?;
929        if !status.is_success() {
930            return Err(Error::Api {
931                status: status.as_u16(),
932                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
933                    .ok()
934                    .and_then(|r| r.error)
935                    .unwrap_or(body_text.clone()),
936            });
937        }
938        Ok(serde_json::from_str(&body_text)?)
939    }
940
941    /// Get role details
942    pub async fn organization_role_get(
943        &self,
944        organization_id: &str,
945        role_id: &str,
946    ) -> Result<ApiResponse<RBACRole>, Error> {
947        let path = format!("/v1/organizations/{organization_id}/roles/{role_id}");
948        let req = self.request(reqwest::Method::GET, &path);
949        let resp = req.send().await?;
950        let status = resp.status();
951        let body_text = resp.text().await?;
952        if !status.is_success() {
953            return Err(Error::Api {
954                status: status.as_u16(),
955                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
956                    .ok()
957                    .and_then(|r| r.error)
958                    .unwrap_or(body_text.clone()),
959            });
960        }
961        Ok(serde_json::from_str(&body_text)?)
962    }
963
964    /// Update a role
965    pub async fn organization_role_patch(
966        &self,
967        organization_id: &str,
968        role_id: &str,
969        body: &RoleUpdateRequest,
970    ) -> Result<ApiResponse<RBACRole>, Error> {
971        let path = format!("/v1/organizations/{organization_id}/roles/{role_id}");
972        let mut req = self.request(reqwest::Method::PATCH, &path);
973        req = req.json(body);
974        let resp = req.send().await?;
975        let status = resp.status();
976        let body_text = resp.text().await?;
977        if !status.is_success() {
978            return Err(Error::Api {
979                status: status.as_u16(),
980                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
981                    .ok()
982                    .and_then(|r| r.error)
983                    .unwrap_or(body_text.clone()),
984            });
985        }
986        Ok(serde_json::from_str(&body_text)?)
987    }
988
989    /// Delete a role
990    pub async fn organization_role_delete(
991        &self,
992        organization_id: &str,
993        role_id: &str,
994    ) -> Result<ApiResponse<serde_json::Value>, Error> {
995        let path = format!("/v1/organizations/{organization_id}/roles/{role_id}");
996        let req = self.request(reqwest::Method::DELETE, &path);
997        let resp = req.send().await?;
998        let status = resp.status();
999        let body_text = resp.text().await?;
1000        if !status.is_success() {
1001            return Err(Error::Api {
1002                status: status.as_u16(),
1003                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
1004                    .ok()
1005                    .and_then(|r| r.error)
1006                    .unwrap_or(body_text.clone()),
1007            });
1008        }
1009        Ok(serde_json::from_str(&body_text)?)
1010    }
1011
1012    /// Create new Postgres service
1013    pub async fn postgres_service_create(
1014        &self,
1015        organization_id: &str,
1016        body: &PostgresServicePostRequest,
1017    ) -> Result<ApiResponse<PostgresService>, Error> {
1018        let path = format!("/v1/organizations/{organization_id}/postgres");
1019        let mut req = self.request(reqwest::Method::POST, &path);
1020        req = req.json(body);
1021        let resp = req.send().await?;
1022        let status = resp.status();
1023        let body_text = resp.text().await?;
1024        if !status.is_success() {
1025            return Err(Error::Api {
1026                status: status.as_u16(),
1027                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
1028                    .ok()
1029                    .and_then(|r| r.error)
1030                    .unwrap_or(body_text.clone()),
1031            });
1032        }
1033        Ok(serde_json::from_str(&body_text)?)
1034    }
1035
1036    /// List of organization Postgres services
1037    pub async fn postgres_service_get_list(
1038        &self,
1039        organization_id: &str,
1040    ) -> Result<ApiResponse<Vec<PostgresServiceListItem>>, Error> {
1041        let path = format!("/v1/organizations/{organization_id}/postgres");
1042        let req = self.request(reqwest::Method::GET, &path);
1043        let resp = req.send().await?;
1044        let status = resp.status();
1045        let body_text = resp.text().await?;
1046        if !status.is_success() {
1047            return Err(Error::Api {
1048                status: status.as_u16(),
1049                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
1050                    .ok()
1051                    .and_then(|r| r.error)
1052                    .unwrap_or(body_text.clone()),
1053            });
1054        }
1055        Ok(serde_json::from_str(&body_text)?)
1056    }
1057
1058    /// Get PostgreSQL service details
1059    pub async fn postgres_service_get(
1060        &self,
1061        organization_id: &str,
1062        postgres_id: &str,
1063    ) -> Result<ApiResponse<PostgresService>, Error> {
1064        let path = format!("/v1/organizations/{organization_id}/postgres/{postgres_id}");
1065        let req = self.request(reqwest::Method::GET, &path);
1066        let resp = req.send().await?;
1067        let status = resp.status();
1068        let body_text = resp.text().await?;
1069        if !status.is_success() {
1070            return Err(Error::Api {
1071                status: status.as_u16(),
1072                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
1073                    .ok()
1074                    .and_then(|r| r.error)
1075                    .unwrap_or(body_text.clone()),
1076            });
1077        }
1078        Ok(serde_json::from_str(&body_text)?)
1079    }
1080
1081    /// Delete a PostgreSQL service
1082    pub async fn postgres_service_delete(
1083        &self,
1084        organization_id: &str,
1085        postgres_id: &str,
1086    ) -> Result<ApiResponse<serde_json::Value>, Error> {
1087        let path = format!("/v1/organizations/{organization_id}/postgres/{postgres_id}");
1088        let req = self.request(reqwest::Method::DELETE, &path);
1089        let resp = req.send().await?;
1090        let status = resp.status();
1091        let body_text = resp.text().await?;
1092        if !status.is_success() {
1093            return Err(Error::Api {
1094                status: status.as_u16(),
1095                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
1096                    .ok()
1097                    .and_then(|r| r.error)
1098                    .unwrap_or(body_text.clone()),
1099            });
1100        }
1101        Ok(serde_json::from_str(&body_text)?)
1102    }
1103
1104    /// Update a PostgreSQL service
1105    pub async fn postgres_service_patch(
1106        &self,
1107        organization_id: &str,
1108        postgres_id: &str,
1109        body: &PostgresServicePatchRequest,
1110    ) -> Result<ApiResponse<PostgresService>, Error> {
1111        let path = format!("/v1/organizations/{organization_id}/postgres/{postgres_id}");
1112        let mut req = self.request(reqwest::Method::PATCH, &path);
1113        req = req.json(body);
1114        let resp = req.send().await?;
1115        let status = resp.status();
1116        let body_text = resp.text().await?;
1117        if !status.is_success() {
1118            return Err(Error::Api {
1119                status: status.as_u16(),
1120                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
1121                    .ok()
1122                    .and_then(|r| r.error)
1123                    .unwrap_or(body_text.clone()),
1124            });
1125        }
1126        Ok(serde_json::from_str(&body_text)?)
1127    }
1128
1129    /// Get Postgres CA certs
1130    pub async fn postgres_service_certs_get(
1131        &self,
1132        organization_id: &str,
1133        postgres_id: &str,
1134    ) -> Result<String, Error> {
1135        let path =
1136            format!("/v1/organizations/{organization_id}/postgres/{postgres_id}/caCertificates");
1137        let req = self.request(reqwest::Method::GET, &path);
1138        let resp = req.send().await?;
1139        let status = resp.status();
1140        let body_text = resp.text().await?;
1141        if !status.is_success() {
1142            return Err(Error::Api {
1143                status: status.as_u16(),
1144                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
1145                    .ok()
1146                    .and_then(|r| r.error)
1147                    .unwrap_or(body_text.clone()),
1148            });
1149        }
1150        Ok(body_text)
1151    }
1152
1153    /// Get PostgreSQL service configuration
1154    pub async fn postgres_instance_config_get(
1155        &self,
1156        organization_id: &str,
1157        postgres_id: &str,
1158    ) -> Result<ApiResponse<PostgresInstanceConfigResponse>, Error> {
1159        let path = format!("/v1/organizations/{organization_id}/postgres/{postgres_id}/config");
1160        let req = self.request(reqwest::Method::GET, &path);
1161        let resp = req.send().await?;
1162        let status = resp.status();
1163        let body_text = resp.text().await?;
1164        if !status.is_success() {
1165            return Err(Error::Api {
1166                status: status.as_u16(),
1167                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
1168                    .ok()
1169                    .and_then(|r| r.error)
1170                    .unwrap_or(body_text.clone()),
1171            });
1172        }
1173        Ok(serde_json::from_str(&body_text)?)
1174    }
1175
1176    /// Replace Postgres service configuration
1177    pub async fn postgres_instance_config_post(
1178        &self,
1179        organization_id: &str,
1180        postgres_id: &str,
1181        body: &PostgresInstanceConfig,
1182    ) -> Result<ApiResponse<PostgresInstanceUpdateConfigResponse>, Error> {
1183        let path = format!("/v1/organizations/{organization_id}/postgres/{postgres_id}/config");
1184        let mut req = self.request(reqwest::Method::POST, &path);
1185        req = req.json(body);
1186        let resp = req.send().await?;
1187        let status = resp.status();
1188        let body_text = resp.text().await?;
1189        if !status.is_success() {
1190            return Err(Error::Api {
1191                status: status.as_u16(),
1192                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
1193                    .ok()
1194                    .and_then(|r| r.error)
1195                    .unwrap_or(body_text.clone()),
1196            });
1197        }
1198        Ok(serde_json::from_str(&body_text)?)
1199    }
1200
1201    /// Update Postgres service configuration
1202    pub async fn postgres_instance_config_patch(
1203        &self,
1204        organization_id: &str,
1205        postgres_id: &str,
1206        body: &PostgresInstanceConfig,
1207    ) -> Result<ApiResponse<PostgresInstanceUpdateConfigResponse>, Error> {
1208        let path = format!("/v1/organizations/{organization_id}/postgres/{postgres_id}/config");
1209        let mut req = self.request(reqwest::Method::PATCH, &path);
1210        req = req.json(body);
1211        let resp = req.send().await?;
1212        let status = resp.status();
1213        let body_text = resp.text().await?;
1214        if !status.is_success() {
1215            return Err(Error::Api {
1216                status: status.as_u16(),
1217                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
1218                    .ok()
1219                    .and_then(|r| r.error)
1220                    .unwrap_or(body_text.clone()),
1221            });
1222        }
1223        Ok(serde_json::from_str(&body_text)?)
1224    }
1225
1226    /// Update Postgres superuser password
1227    pub async fn postgres_service_set_password(
1228        &self,
1229        organization_id: &str,
1230        postgres_id: &str,
1231        body: &PostgresServiceSetPassword,
1232    ) -> Result<ApiResponse<PostgresServicePasswordResource>, Error> {
1233        let path = format!("/v1/organizations/{organization_id}/postgres/{postgres_id}/password");
1234        let mut req = self.request(reqwest::Method::PATCH, &path);
1235        req = req.json(body);
1236        let resp = req.send().await?;
1237        let status = resp.status();
1238        let body_text = resp.text().await?;
1239        if !status.is_success() {
1240            return Err(Error::Api {
1241                status: status.as_u16(),
1242                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
1243                    .ok()
1244                    .and_then(|r| r.error)
1245                    .unwrap_or(body_text.clone()),
1246            });
1247        }
1248        Ok(serde_json::from_str(&body_text)?)
1249    }
1250
1251    /// Create a read replica for a Postgres service
1252    pub async fn postgres_instance_create_read_replica(
1253        &self,
1254        organization_id: &str,
1255        postgres_id: &str,
1256        body: &PostgresServiceReadReplicaRequest,
1257    ) -> Result<ApiResponse<PostgresService>, Error> {
1258        let path =
1259            format!("/v1/organizations/{organization_id}/postgres/{postgres_id}/readReplica");
1260        let mut req = self.request(reqwest::Method::POST, &path);
1261        req = req.json(body);
1262        let resp = req.send().await?;
1263        let status = resp.status();
1264        let body_text = resp.text().await?;
1265        if !status.is_success() {
1266            return Err(Error::Api {
1267                status: status.as_u16(),
1268                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
1269                    .ok()
1270                    .and_then(|r| r.error)
1271                    .unwrap_or(body_text.clone()),
1272            });
1273        }
1274        Ok(serde_json::from_str(&body_text)?)
1275    }
1276
1277    /// Get PostgreSQL service metrics
1278    pub async fn postgres_instance_prometheus_get(
1279        &self,
1280        organization_id: &str,
1281        postgres_id: &str,
1282    ) -> Result<String, Error> {
1283        let path = format!("/v1/organizations/{organization_id}/postgres/{postgres_id}/prometheus");
1284        let req = self.request(reqwest::Method::GET, &path);
1285        let resp = req.send().await?;
1286        let status = resp.status();
1287        if !status.is_success() {
1288            let body_text = resp.text().await?;
1289            return Err(Error::Api {
1290                status: status.as_u16(),
1291                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
1292                    .ok()
1293                    .and_then(|r| r.error)
1294                    .unwrap_or(body_text),
1295            });
1296        }
1297        Ok(resp.text().await?)
1298    }
1299
1300    /// Get organization PostgreSQL metrics
1301    pub async fn postgres_org_prometheus_get(
1302        &self,
1303        organization_id: &str,
1304    ) -> Result<String, Error> {
1305        let path = format!("/v1/organizations/{organization_id}/postgres/prometheus");
1306        let req = self.request(reqwest::Method::GET, &path);
1307        let resp = req.send().await?;
1308        let status = resp.status();
1309        if !status.is_success() {
1310            let body_text = resp.text().await?;
1311            return Err(Error::Api {
1312                status: status.as_u16(),
1313                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
1314                    .ok()
1315                    .and_then(|r| r.error)
1316                    .unwrap_or(body_text),
1317            });
1318        }
1319        Ok(resp.text().await?)
1320    }
1321
1322    /// Restore a Postgres service
1323    pub async fn postgres_instance_restore(
1324        &self,
1325        organization_id: &str,
1326        postgres_id: &str,
1327        body: &PostgresServiceRestoreRequest,
1328    ) -> Result<ApiResponse<PostgresService>, Error> {
1329        let path =
1330            format!("/v1/organizations/{organization_id}/postgres/{postgres_id}/restoredService");
1331        let mut req = self.request(reqwest::Method::POST, &path);
1332        req = req.json(body);
1333        let resp = req.send().await?;
1334        let status = resp.status();
1335        let body_text = resp.text().await?;
1336        if !status.is_success() {
1337            return Err(Error::Api {
1338                status: status.as_u16(),
1339                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
1340                    .ok()
1341                    .and_then(|r| r.error)
1342                    .unwrap_or(body_text.clone()),
1343            });
1344        }
1345        Ok(serde_json::from_str(&body_text)?)
1346    }
1347
1348    /// Update Postgres service state
1349    pub async fn postgres_service_patch_state(
1350        &self,
1351        organization_id: &str,
1352        postgres_id: &str,
1353        body: &PostgresServiceSetState,
1354    ) -> Result<ApiResponse<PostgresService>, Error> {
1355        let path = format!("/v1/organizations/{organization_id}/postgres/{postgres_id}/state");
1356        let mut req = self.request(reqwest::Method::PATCH, &path);
1357        req = req.json(body);
1358        let resp = req.send().await?;
1359        let status = resp.status();
1360        let body_text = resp.text().await?;
1361        if !status.is_success() {
1362            return Err(Error::Api {
1363                status: status.as_u16(),
1364                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
1365                    .ok()
1366                    .and_then(|r| r.error)
1367                    .unwrap_or(body_text.clone()),
1368            });
1369        }
1370        Ok(serde_json::from_str(&body_text)?)
1371    }
1372
1373    /// Get Postgres metrics
1374    #[allow(clippy::too_many_arguments)]
1375    pub async fn postgres_instance_metrics_get(
1376        &self,
1377        organization_id: &str,
1378        postgres_id: &str,
1379        from_date: &str,
1380        to_date: &str,
1381        bucket_size_seconds: Option<i64>,
1382    ) -> Result<ApiResponse<PostgresMetrics>, Error> {
1383        let path = format!("/v1/organizations/{organization_id}/postgres/{postgres_id}/metrics");
1384        let mut req = self.request(reqwest::Method::GET, &path);
1385        req = req.query(&[("from_date", from_date), ("to_date", to_date)]);
1386        if let Some(v) = bucket_size_seconds {
1387            req = req.query(&[("bucket_size_seconds", v)]);
1388        }
1389        let resp = req.send().await?;
1390        let status = resp.status();
1391        let body_text = resp.text().await?;
1392        if !status.is_success() {
1393            return Err(Error::Api {
1394                status: status.as_u16(),
1395                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
1396                    .ok()
1397                    .and_then(|r| r.error)
1398                    .unwrap_or(body_text.clone()),
1399            });
1400        }
1401        Ok(serde_json::from_str(&body_text)?)
1402    }
1403
1404    /// List Postgres slow query patterns
1405    #[allow(clippy::too_many_arguments)]
1406    pub async fn slow_query_patterns_get_list(
1407        &self,
1408        organization_id: &str,
1409        postgres_id: &str,
1410        from_date: &str,
1411        to_date: &str,
1412        db_name: Option<&str>,
1413        db_user: Option<&str>,
1414        db_operation: Option<&str>,
1415        app: Option<&str>,
1416        sort_by: Option<&str>,
1417        sort_order: Option<&str>,
1418        limit: Option<i64>,
1419        offset: Option<i64>,
1420    ) -> Result<ApiResponse<Vec<PostgresSlowQueryPattern>>, Error> {
1421        let path =
1422            format!("/v1/organizations/{organization_id}/postgres/{postgres_id}/slowQueryPatterns");
1423        let mut req = self.request(reqwest::Method::GET, &path);
1424        req = req.query(&[("from_date", from_date), ("to_date", to_date)]);
1425        if let Some(v) = db_name {
1426            req = req.query(&[("db_name", v)]);
1427        }
1428        if let Some(v) = db_user {
1429            req = req.query(&[("db_user", v)]);
1430        }
1431        if let Some(v) = db_operation {
1432            req = req.query(&[("db_operation", v)]);
1433        }
1434        if let Some(v) = app {
1435            req = req.query(&[("app", v)]);
1436        }
1437        if let Some(v) = sort_by {
1438            req = req.query(&[("sort_by", v)]);
1439        }
1440        if let Some(v) = sort_order {
1441            req = req.query(&[("sort_order", v)]);
1442        }
1443        if let Some(v) = limit {
1444            req = req.query(&[("limit", v)]);
1445        }
1446        if let Some(v) = offset {
1447            req = req.query(&[("offset", v)]);
1448        }
1449        let resp = req.send().await?;
1450        let status = resp.status();
1451        let body_text = resp.text().await?;
1452        if !status.is_success() {
1453            return Err(Error::Api {
1454                status: status.as_u16(),
1455                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
1456                    .ok()
1457                    .and_then(|r| r.error)
1458                    .unwrap_or(body_text.clone()),
1459            });
1460        }
1461        Ok(serde_json::from_str(&body_text)?)
1462    }
1463
1464    /// Get a Postgres slow query pattern with recent executions
1465    #[allow(clippy::too_many_arguments)]
1466    pub async fn slow_query_pattern_get(
1467        &self,
1468        organization_id: &str,
1469        postgres_id: &str,
1470        query_id: &str,
1471        db_name: &str,
1472        db_user: &str,
1473        db_operation: &str,
1474        app: Option<&str>,
1475        timestamp: Option<&str>,
1476    ) -> Result<ApiResponse<PostgresSlowQueryPatternDetail>, Error> {
1477        let path = format!(
1478            "/v1/organizations/{organization_id}/postgres/{postgres_id}/slowQueryPatterns/{query_id}"
1479        );
1480        let mut req = self.request(reqwest::Method::GET, &path);
1481        req = req.query(&[
1482            ("db_name", db_name),
1483            ("db_user", db_user),
1484            ("db_operation", db_operation),
1485        ]);
1486        if let Some(v) = app {
1487            req = req.query(&[("app", v)]);
1488        }
1489        if let Some(v) = timestamp {
1490            req = req.query(&[("timestamp", v)]);
1491        }
1492        let resp = req.send().await?;
1493        let status = resp.status();
1494        let body_text = resp.text().await?;
1495        if !status.is_success() {
1496            return Err(Error::Api {
1497                status: status.as_u16(),
1498                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
1499                    .ok()
1500                    .and_then(|r| r.error)
1501                    .unwrap_or(body_text.clone()),
1502            });
1503        }
1504        Ok(serde_json::from_str(&body_text)?)
1505    }
1506
1507    /// Get private endpoint configuration for region within cloud provider for an organization
1508    #[deprecated]
1509    #[allow(deprecated)]
1510    pub async fn organization_private_endpoint_config_get_list(
1511        &self,
1512        organization_id: &str,
1513        cloud_provider: &str,
1514        region_id: &str,
1515    ) -> Result<ApiResponse<OrganizationCloudRegionPrivateEndpointConfig>, Error> {
1516        let path = format!("/v1/organizations/{organization_id}/privateEndpointConfig");
1517        let mut req = self.request(reqwest::Method::GET, &path);
1518        req = req.query(&[("cloud_provider", cloud_provider)]);
1519        req = req.query(&[("region_id", region_id)]);
1520        let resp = req.send().await?;
1521        let status = resp.status();
1522        let body_text = resp.text().await?;
1523        if !status.is_success() {
1524            return Err(Error::Api {
1525                status: status.as_u16(),
1526                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
1527                    .ok()
1528                    .and_then(|r| r.error)
1529                    .unwrap_or(body_text.clone()),
1530            });
1531        }
1532        Ok(serde_json::from_str(&body_text)?)
1533    }
1534
1535    /// Get organization metrics
1536    pub async fn organization_prometheus_get(
1537        &self,
1538        organization_id: &str,
1539        filtered_metrics: Option<&str>,
1540    ) -> Result<String, Error> {
1541        let path = format!("/v1/organizations/{organization_id}/prometheus");
1542        let mut req = self.request(reqwest::Method::GET, &path);
1543        if let Some(v) = filtered_metrics {
1544            req = req.query(&[("filtered_metrics", v)]);
1545        }
1546        let resp = req.send().await?;
1547        let status = resp.status();
1548        if !status.is_success() {
1549            let body_text = resp.text().await?;
1550            return Err(Error::Api {
1551                status: status.as_u16(),
1552                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
1553                    .ok()
1554                    .and_then(|r| r.error)
1555                    .unwrap_or(body_text),
1556            });
1557        }
1558        Ok(resp.text().await?)
1559    }
1560
1561    /// List of organization services
1562    pub async fn instance_get_list(
1563        &self,
1564        organization_id: &str,
1565        filters: &[&str],
1566    ) -> Result<ApiResponse<Vec<Service>>, Error> {
1567        let path = format!("/v1/organizations/{organization_id}/services");
1568        let mut req = self.request(reqwest::Method::GET, &path);
1569        for f in filters {
1570            req = req.query(&[("filter", f)]);
1571        }
1572        let resp = req.send().await?;
1573        let status = resp.status();
1574        let body_text = resp.text().await?;
1575        if !status.is_success() {
1576            return Err(Error::Api {
1577                status: status.as_u16(),
1578                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
1579                    .ok()
1580                    .and_then(|r| r.error)
1581                    .unwrap_or(body_text.clone()),
1582            });
1583        }
1584        Ok(serde_json::from_str(&body_text)?)
1585    }
1586
1587    /// Create new service
1588    pub async fn instance_create(
1589        &self,
1590        organization_id: &str,
1591        body: &ServicePostRequest,
1592    ) -> Result<ApiResponse<ServicePostResponse>, Error> {
1593        let path = format!("/v1/organizations/{organization_id}/services");
1594        let mut req = self.request(reqwest::Method::POST, &path);
1595        req = req.json(body);
1596        let resp = req.send().await?;
1597        let status = resp.status();
1598        let body_text = resp.text().await?;
1599        if !status.is_success() {
1600            return Err(Error::Api {
1601                status: status.as_u16(),
1602                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
1603                    .ok()
1604                    .and_then(|r| r.error)
1605                    .unwrap_or(body_text.clone()),
1606            });
1607        }
1608        Ok(serde_json::from_str(&body_text)?)
1609    }
1610
1611    /// Get service details
1612    pub async fn instance_get(
1613        &self,
1614        organization_id: &str,
1615        service_id: &str,
1616    ) -> Result<ApiResponse<Service>, Error> {
1617        let path = format!("/v1/organizations/{organization_id}/services/{service_id}");
1618        let req = self.request(reqwest::Method::GET, &path);
1619        let resp = req.send().await?;
1620        let status = resp.status();
1621        let body_text = resp.text().await?;
1622        if !status.is_success() {
1623            return Err(Error::Api {
1624                status: status.as_u16(),
1625                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
1626                    .ok()
1627                    .and_then(|r| r.error)
1628                    .unwrap_or(body_text.clone()),
1629            });
1630        }
1631        Ok(serde_json::from_str(&body_text)?)
1632    }
1633
1634    /// Update service basic details
1635    pub async fn instance_update(
1636        &self,
1637        organization_id: &str,
1638        service_id: &str,
1639        body: &ServicePatchRequest,
1640    ) -> Result<ApiResponse<Service>, Error> {
1641        let path = format!("/v1/organizations/{organization_id}/services/{service_id}");
1642        let mut req = self.request(reqwest::Method::PATCH, &path);
1643        req = req.json(body);
1644        let resp = req.send().await?;
1645        let status = resp.status();
1646        let body_text = resp.text().await?;
1647        if !status.is_success() {
1648            return Err(Error::Api {
1649                status: status.as_u16(),
1650                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
1651                    .ok()
1652                    .and_then(|r| r.error)
1653                    .unwrap_or(body_text.clone()),
1654            });
1655        }
1656        Ok(serde_json::from_str(&body_text)?)
1657    }
1658
1659    /// Delete service
1660    pub async fn instance_delete(
1661        &self,
1662        organization_id: &str,
1663        service_id: &str,
1664    ) -> Result<ApiResponse<serde_json::Value>, Error> {
1665        let path = format!("/v1/organizations/{organization_id}/services/{service_id}");
1666        let req = self.request(reqwest::Method::DELETE, &path);
1667        let resp = req.send().await?;
1668        let status = resp.status();
1669        let body_text = resp.text().await?;
1670        if !status.is_success() {
1671            return Err(Error::Api {
1672                status: status.as_u16(),
1673                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
1674                    .ok()
1675                    .and_then(|r| r.error)
1676                    .unwrap_or(body_text.clone()),
1677            });
1678        }
1679        Ok(serde_json::from_str(&body_text)?)
1680    }
1681
1682    /// Get service backup bucket
1683    pub async fn backup_bucket_get(
1684        &self,
1685        organization_id: &str,
1686        service_id: &str,
1687    ) -> Result<ApiResponse<BackupBucket>, Error> {
1688        let path =
1689            format!("/v1/organizations/{organization_id}/services/{service_id}/backupBucket");
1690        let req = self.request(reqwest::Method::GET, &path);
1691        let resp = req.send().await?;
1692        let status = resp.status();
1693        let body_text = resp.text().await?;
1694        if !status.is_success() {
1695            return Err(Error::Api {
1696                status: status.as_u16(),
1697                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
1698                    .ok()
1699                    .and_then(|r| r.error)
1700                    .unwrap_or(body_text.clone()),
1701            });
1702        }
1703        Ok(serde_json::from_str(&body_text)?)
1704    }
1705
1706    /// Create service backup bucket
1707    pub async fn backup_bucket_create(
1708        &self,
1709        organization_id: &str,
1710        service_id: &str,
1711        body: &BackupBucketPostRequest,
1712    ) -> Result<ApiResponse<BackupBucket>, Error> {
1713        let path =
1714            format!("/v1/organizations/{organization_id}/services/{service_id}/backupBucket");
1715        let mut req = self.request(reqwest::Method::POST, &path);
1716        req = req.json(body);
1717        let resp = req.send().await?;
1718        let status = resp.status();
1719        let body_text = resp.text().await?;
1720        if !status.is_success() {
1721            return Err(Error::Api {
1722                status: status.as_u16(),
1723                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
1724                    .ok()
1725                    .and_then(|r| r.error)
1726                    .unwrap_or(body_text.clone()),
1727            });
1728        }
1729        Ok(serde_json::from_str(&body_text)?)
1730    }
1731
1732    /// Update service backup bucket
1733    pub async fn backup_bucket_update(
1734        &self,
1735        organization_id: &str,
1736        service_id: &str,
1737        body: &BackupBucketPatchRequest,
1738    ) -> Result<ApiResponse<BackupBucket>, Error> {
1739        let path =
1740            format!("/v1/organizations/{organization_id}/services/{service_id}/backupBucket");
1741        let mut req = self.request(reqwest::Method::PATCH, &path);
1742        req = req.json(body);
1743        let resp = req.send().await?;
1744        let status = resp.status();
1745        let body_text = resp.text().await?;
1746        if !status.is_success() {
1747            return Err(Error::Api {
1748                status: status.as_u16(),
1749                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
1750                    .ok()
1751                    .and_then(|r| r.error)
1752                    .unwrap_or(body_text.clone()),
1753            });
1754        }
1755        Ok(serde_json::from_str(&body_text)?)
1756    }
1757
1758    /// Delete service backup bucket
1759    pub async fn backup_bucket_delete(
1760        &self,
1761        organization_id: &str,
1762        service_id: &str,
1763    ) -> Result<ApiResponse<serde_json::Value>, Error> {
1764        let path =
1765            format!("/v1/organizations/{organization_id}/services/{service_id}/backupBucket");
1766        let req = self.request(reqwest::Method::DELETE, &path);
1767        let resp = req.send().await?;
1768        let status = resp.status();
1769        let body_text = resp.text().await?;
1770        if !status.is_success() {
1771            return Err(Error::Api {
1772                status: status.as_u16(),
1773                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
1774                    .ok()
1775                    .and_then(|r| r.error)
1776                    .unwrap_or(body_text.clone()),
1777            });
1778        }
1779        Ok(serde_json::from_str(&body_text)?)
1780    }
1781
1782    /// Get service backup configuration
1783    pub async fn backup_configuration_get(
1784        &self,
1785        organization_id: &str,
1786        service_id: &str,
1787    ) -> Result<ApiResponse<BackupConfiguration>, Error> {
1788        let path = format!(
1789            "/v1/organizations/{organization_id}/services/{service_id}/backupConfiguration"
1790        );
1791        let req = self.request(reqwest::Method::GET, &path);
1792        let resp = req.send().await?;
1793        let status = resp.status();
1794        let body_text = resp.text().await?;
1795        if !status.is_success() {
1796            return Err(Error::Api {
1797                status: status.as_u16(),
1798                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
1799                    .ok()
1800                    .and_then(|r| r.error)
1801                    .unwrap_or(body_text.clone()),
1802            });
1803        }
1804        Ok(serde_json::from_str(&body_text)?)
1805    }
1806
1807    /// Update service backup configuration
1808    pub async fn backup_configuration_update(
1809        &self,
1810        organization_id: &str,
1811        service_id: &str,
1812        body: &BackupConfigurationPatchRequest,
1813    ) -> Result<ApiResponse<BackupConfiguration>, Error> {
1814        let path = format!(
1815            "/v1/organizations/{organization_id}/services/{service_id}/backupConfiguration"
1816        );
1817        let mut req = self.request(reqwest::Method::PATCH, &path);
1818        req = req.json(body);
1819        let resp = req.send().await?;
1820        let status = resp.status();
1821        let body_text = resp.text().await?;
1822        if !status.is_success() {
1823            return Err(Error::Api {
1824                status: status.as_u16(),
1825                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
1826                    .ok()
1827                    .and_then(|r| r.error)
1828                    .unwrap_or(body_text.clone()),
1829            });
1830        }
1831        Ok(serde_json::from_str(&body_text)?)
1832    }
1833
1834    /// List of service backups
1835    pub async fn backup_get_list(
1836        &self,
1837        organization_id: &str,
1838        service_id: &str,
1839    ) -> Result<ApiResponse<Vec<Backup>>, Error> {
1840        let path = format!("/v1/organizations/{organization_id}/services/{service_id}/backups");
1841        let req = self.request(reqwest::Method::GET, &path);
1842        let resp = req.send().await?;
1843        let status = resp.status();
1844        let body_text = resp.text().await?;
1845        if !status.is_success() {
1846            return Err(Error::Api {
1847                status: status.as_u16(),
1848                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
1849                    .ok()
1850                    .and_then(|r| r.error)
1851                    .unwrap_or(body_text.clone()),
1852            });
1853        }
1854        Ok(serde_json::from_str(&body_text)?)
1855    }
1856
1857    /// Get backup details
1858    pub async fn backup_get(
1859        &self,
1860        organization_id: &str,
1861        service_id: &str,
1862        backup_id: &str,
1863    ) -> Result<ApiResponse<Backup>, Error> {
1864        let path = format!(
1865            "/v1/organizations/{organization_id}/services/{service_id}/backups/{backup_id}"
1866        );
1867        let req = self.request(reqwest::Method::GET, &path);
1868        let resp = req.send().await?;
1869        let status = resp.status();
1870        let body_text = resp.text().await?;
1871        if !status.is_success() {
1872            return Err(Error::Api {
1873                status: status.as_u16(),
1874                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
1875                    .ok()
1876                    .and_then(|r| r.error)
1877                    .unwrap_or(body_text.clone()),
1878            });
1879        }
1880        Ok(serde_json::from_str(&body_text)?)
1881    }
1882
1883    /// List ClickPipes
1884    pub async fn click_pipe_get_list(
1885        &self,
1886        organization_id: &str,
1887        service_id: &str,
1888    ) -> Result<ApiResponse<Vec<ClickPipe>>, Error> {
1889        let path = format!("/v1/organizations/{organization_id}/services/{service_id}/clickpipes");
1890        let req = self.request(reqwest::Method::GET, &path);
1891        let resp = req.send().await?;
1892        let status = resp.status();
1893        let body_text = resp.text().await?;
1894        if !status.is_success() {
1895            return Err(Error::Api {
1896                status: status.as_u16(),
1897                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
1898                    .ok()
1899                    .and_then(|r| r.error)
1900                    .unwrap_or(body_text.clone()),
1901            });
1902        }
1903        Ok(serde_json::from_str(&body_text)?)
1904    }
1905
1906    /// Create ClickPipe
1907    pub async fn click_pipe_create(
1908        &self,
1909        organization_id: &str,
1910        service_id: &str,
1911        body: &ClickPipePostRequest,
1912    ) -> Result<ApiResponse<ClickPipe>, Error> {
1913        let path = format!("/v1/organizations/{organization_id}/services/{service_id}/clickpipes");
1914        let mut req = self.request(reqwest::Method::POST, &path);
1915        req = req.json(body);
1916        let resp = req.send().await?;
1917        let status = resp.status();
1918        let body_text = resp.text().await?;
1919        if !status.is_success() {
1920            return Err(Error::Api {
1921                status: status.as_u16(),
1922                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
1923                    .ok()
1924                    .and_then(|r| r.error)
1925                    .unwrap_or(body_text.clone()),
1926            });
1927        }
1928        Ok(serde_json::from_str(&body_text)?)
1929    }
1930
1931    /// Get ClickPipe
1932    pub async fn click_pipe_get(
1933        &self,
1934        organization_id: &str,
1935        service_id: &str,
1936        click_pipe_id: &str,
1937    ) -> Result<ApiResponse<ClickPipe>, Error> {
1938        let path = format!(
1939            "/v1/organizations/{organization_id}/services/{service_id}/clickpipes/{click_pipe_id}"
1940        );
1941        let req = self.request(reqwest::Method::GET, &path);
1942        let resp = req.send().await?;
1943        let status = resp.status();
1944        let body_text = resp.text().await?;
1945        if !status.is_success() {
1946            return Err(Error::Api {
1947                status: status.as_u16(),
1948                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
1949                    .ok()
1950                    .and_then(|r| r.error)
1951                    .unwrap_or(body_text.clone()),
1952            });
1953        }
1954        Ok(serde_json::from_str(&body_text)?)
1955    }
1956
1957    /// Update ClickPipe
1958    pub async fn click_pipe_update(
1959        &self,
1960        organization_id: &str,
1961        service_id: &str,
1962        click_pipe_id: &str,
1963        body: &ClickPipePatchRequest,
1964    ) -> Result<ApiResponse<ClickPipe>, Error> {
1965        let path = format!(
1966            "/v1/organizations/{organization_id}/services/{service_id}/clickpipes/{click_pipe_id}"
1967        );
1968        let mut req = self.request(reqwest::Method::PATCH, &path);
1969        req = req.json(body);
1970        let resp = req.send().await?;
1971        let status = resp.status();
1972        let body_text = resp.text().await?;
1973        if !status.is_success() {
1974            return Err(Error::Api {
1975                status: status.as_u16(),
1976                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
1977                    .ok()
1978                    .and_then(|r| r.error)
1979                    .unwrap_or(body_text.clone()),
1980            });
1981        }
1982        Ok(serde_json::from_str(&body_text)?)
1983    }
1984
1985    /// Delete ClickPipe
1986    pub async fn click_pipe_delete(
1987        &self,
1988        organization_id: &str,
1989        service_id: &str,
1990        click_pipe_id: &str,
1991    ) -> Result<ApiResponse<serde_json::Value>, Error> {
1992        let path = format!(
1993            "/v1/organizations/{organization_id}/services/{service_id}/clickpipes/{click_pipe_id}"
1994        );
1995        let req = self.request(reqwest::Method::DELETE, &path);
1996        let resp = req.send().await?;
1997        let status = resp.status();
1998        let body_text = resp.text().await?;
1999        if !status.is_success() {
2000            return Err(Error::Api {
2001                status: status.as_u16(),
2002                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
2003                    .ok()
2004                    .and_then(|r| r.error)
2005                    .unwrap_or(body_text.clone()),
2006            });
2007        }
2008        Ok(serde_json::from_str(&body_text)?)
2009    }
2010
2011    /// Update ClickPipe scaling
2012    pub async fn click_pipe_scaling_update(
2013        &self,
2014        organization_id: &str,
2015        service_id: &str,
2016        click_pipe_id: &str,
2017        body: &ClickPipeScalingPatchRequest,
2018    ) -> Result<ApiResponse<ClickPipe>, Error> {
2019        let path = format!(
2020            "/v1/organizations/{organization_id}/services/{service_id}/clickpipes/{click_pipe_id}/scaling"
2021        );
2022        let mut req = self.request(reqwest::Method::PATCH, &path);
2023        req = req.json(body);
2024        let resp = req.send().await?;
2025        let status = resp.status();
2026        let body_text = resp.text().await?;
2027        if !status.is_success() {
2028            return Err(Error::Api {
2029                status: status.as_u16(),
2030                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
2031                    .ok()
2032                    .and_then(|r| r.error)
2033                    .unwrap_or(body_text.clone()),
2034            });
2035        }
2036        Ok(serde_json::from_str(&body_text)?)
2037    }
2038
2039    /// Get ClickPipe settings
2040    pub async fn click_pipe_settings_get(
2041        &self,
2042        organization_id: &str,
2043        service_id: &str,
2044        click_pipe_id: &str,
2045    ) -> Result<ApiResponse<ClickPipeSettingsResponse>, Error> {
2046        let path = format!(
2047            "/v1/organizations/{organization_id}/services/{service_id}/clickpipes/{click_pipe_id}/settings"
2048        );
2049        let req = self.request(reqwest::Method::GET, &path);
2050        let resp = req.send().await?;
2051        let status = resp.status();
2052        let body_text = resp.text().await?;
2053        if !status.is_success() {
2054            return Err(Error::Api {
2055                status: status.as_u16(),
2056                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
2057                    .ok()
2058                    .and_then(|r| r.error)
2059                    .unwrap_or(body_text.clone()),
2060            });
2061        }
2062        Ok(serde_json::from_str(&body_text)?)
2063    }
2064
2065    /// Update ClickPipe settings
2066    pub async fn click_pipe_settings_update(
2067        &self,
2068        organization_id: &str,
2069        service_id: &str,
2070        click_pipe_id: &str,
2071        body: &ClickPipeSettingsPutRequest,
2072    ) -> Result<ApiResponse<ClickPipeSettingsResponse>, Error> {
2073        let path = format!(
2074            "/v1/organizations/{organization_id}/services/{service_id}/clickpipes/{click_pipe_id}/settings"
2075        );
2076        let mut req = self.request(reqwest::Method::PUT, &path);
2077        req = req.json(body);
2078        let resp = req.send().await?;
2079        let status = resp.status();
2080        let body_text = resp.text().await?;
2081        if !status.is_success() {
2082            return Err(Error::Api {
2083                status: status.as_u16(),
2084                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
2085                    .ok()
2086                    .and_then(|r| r.error)
2087                    .unwrap_or(body_text.clone()),
2088            });
2089        }
2090        Ok(serde_json::from_str(&body_text)?)
2091    }
2092
2093    /// Update ClickPipe state
2094    pub async fn click_pipe_state_update(
2095        &self,
2096        organization_id: &str,
2097        service_id: &str,
2098        click_pipe_id: &str,
2099        body: &ClickPipeStatePatchRequest,
2100    ) -> Result<ApiResponse<ClickPipe>, Error> {
2101        let path = format!(
2102            "/v1/organizations/{organization_id}/services/{service_id}/clickpipes/{click_pipe_id}/state"
2103        );
2104        let mut req = self.request(reqwest::Method::PATCH, &path);
2105        req = req.json(body);
2106        let resp = req.send().await?;
2107        let status = resp.status();
2108        let body_text = resp.text().await?;
2109        if !status.is_success() {
2110            return Err(Error::Api {
2111                status: status.as_u16(),
2112                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
2113                    .ok()
2114                    .and_then(|r| r.error)
2115                    .unwrap_or(body_text.clone()),
2116            });
2117        }
2118        Ok(serde_json::from_str(&body_text)?)
2119    }
2120
2121    /// Get CDC ClickPipes scaling
2122    pub async fn click_pipe_cdc_scaling_get(
2123        &self,
2124        organization_id: &str,
2125        service_id: &str,
2126    ) -> Result<ApiResponse<ClickPipesCdcScaling>, Error> {
2127        let path = format!(
2128            "/v1/organizations/{organization_id}/services/{service_id}/clickpipesCdcScaling"
2129        );
2130        let req = self.request(reqwest::Method::GET, &path);
2131        let resp = req.send().await?;
2132        let status = resp.status();
2133        let body_text = resp.text().await?;
2134        if !status.is_success() {
2135            return Err(Error::Api {
2136                status: status.as_u16(),
2137                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
2138                    .ok()
2139                    .and_then(|r| r.error)
2140                    .unwrap_or(body_text.clone()),
2141            });
2142        }
2143        Ok(serde_json::from_str(&body_text)?)
2144    }
2145
2146    /// Update CDC ClickPipes scaling
2147    pub async fn click_pipe_cdc_scaling_update(
2148        &self,
2149        organization_id: &str,
2150        service_id: &str,
2151        body: &ClickPipesCdcScalingPatchRequest,
2152    ) -> Result<ApiResponse<ClickPipesCdcScaling>, Error> {
2153        let path = format!(
2154            "/v1/organizations/{organization_id}/services/{service_id}/clickpipesCdcScaling"
2155        );
2156        let mut req = self.request(reqwest::Method::PATCH, &path);
2157        req = req.json(body);
2158        let resp = req.send().await?;
2159        let status = resp.status();
2160        let body_text = resp.text().await?;
2161        if !status.is_success() {
2162            return Err(Error::Api {
2163                status: status.as_u16(),
2164                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
2165                    .ok()
2166                    .and_then(|r| r.error)
2167                    .unwrap_or(body_text.clone()),
2168            });
2169        }
2170        Ok(serde_json::from_str(&body_text)?)
2171    }
2172
2173    /// List reverse private endpoints
2174    pub async fn click_pipe_reverse_private_endpoint_get_list(
2175        &self,
2176        organization_id: &str,
2177        service_id: &str,
2178    ) -> Result<ApiResponse<Vec<ReversePrivateEndpoint>>, Error> {
2179        let path = format!(
2180            "/v1/organizations/{organization_id}/services/{service_id}/clickpipesReversePrivateEndpoints"
2181        );
2182        let req = self.request(reqwest::Method::GET, &path);
2183        let resp = req.send().await?;
2184        let status = resp.status();
2185        let body_text = resp.text().await?;
2186        if !status.is_success() {
2187            return Err(Error::Api {
2188                status: status.as_u16(),
2189                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
2190                    .ok()
2191                    .and_then(|r| r.error)
2192                    .unwrap_or(body_text.clone()),
2193            });
2194        }
2195        Ok(serde_json::from_str(&body_text)?)
2196    }
2197
2198    /// Create reverse private endpoint
2199    pub async fn click_pipe_reverse_private_endpoint_create(
2200        &self,
2201        organization_id: &str,
2202        service_id: &str,
2203        body: &CreateReversePrivateEndpoint,
2204    ) -> Result<ApiResponse<ReversePrivateEndpoint>, Error> {
2205        let path = format!(
2206            "/v1/organizations/{organization_id}/services/{service_id}/clickpipesReversePrivateEndpoints"
2207        );
2208        let mut req = self.request(reqwest::Method::POST, &path);
2209        req = req.json(body);
2210        let resp = req.send().await?;
2211        let status = resp.status();
2212        let body_text = resp.text().await?;
2213        if !status.is_success() {
2214            return Err(Error::Api {
2215                status: status.as_u16(),
2216                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
2217                    .ok()
2218                    .and_then(|r| r.error)
2219                    .unwrap_or(body_text.clone()),
2220            });
2221        }
2222        Ok(serde_json::from_str(&body_text)?)
2223    }
2224
2225    /// Get reverse private endpoint
2226    pub async fn click_pipe_reverse_private_endpoint_get(
2227        &self,
2228        organization_id: &str,
2229        service_id: &str,
2230        reverse_private_endpoint_id: &str,
2231    ) -> Result<ApiResponse<ReversePrivateEndpoint>, Error> {
2232        let path = format!(
2233            "/v1/organizations/{organization_id}/services/{service_id}/clickpipesReversePrivateEndpoints/{reverse_private_endpoint_id}"
2234        );
2235        let req = self.request(reqwest::Method::GET, &path);
2236        let resp = req.send().await?;
2237        let status = resp.status();
2238        let body_text = resp.text().await?;
2239        if !status.is_success() {
2240            return Err(Error::Api {
2241                status: status.as_u16(),
2242                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
2243                    .ok()
2244                    .and_then(|r| r.error)
2245                    .unwrap_or(body_text.clone()),
2246            });
2247        }
2248        Ok(serde_json::from_str(&body_text)?)
2249    }
2250
2251    /// Delete reverse private endpoint
2252    pub async fn click_pipe_reverse_private_endpoint_delete(
2253        &self,
2254        organization_id: &str,
2255        service_id: &str,
2256        reverse_private_endpoint_id: &str,
2257    ) -> Result<ApiResponse<serde_json::Value>, Error> {
2258        let path = format!(
2259            "/v1/organizations/{organization_id}/services/{service_id}/clickpipesReversePrivateEndpoints/{reverse_private_endpoint_id}"
2260        );
2261        let req = self.request(reqwest::Method::DELETE, &path);
2262        let resp = req.send().await?;
2263        let status = resp.status();
2264        let body_text = resp.text().await?;
2265        if !status.is_success() {
2266            return Err(Error::Api {
2267                status: status.as_u16(),
2268                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
2269                    .ok()
2270                    .and_then(|r| r.error)
2271                    .unwrap_or(body_text.clone()),
2272            });
2273        }
2274        Ok(serde_json::from_str(&body_text)?)
2275    }
2276
2277    /// Update reverse private endpoint
2278    pub async fn click_pipe_reverse_private_endpoint_update(
2279        &self,
2280        organization_id: &str,
2281        service_id: &str,
2282        reverse_private_endpoint_id: &str,
2283        body: &UpdateReversePrivateEndpoint,
2284    ) -> Result<ApiResponse<ReversePrivateEndpoint>, Error> {
2285        let path = format!(
2286            "/v1/organizations/{organization_id}/services/{service_id}/clickpipesReversePrivateEndpoints/{reverse_private_endpoint_id}"
2287        );
2288        let mut req = self.request(reqwest::Method::PATCH, &path);
2289        req = req.json(body);
2290        let resp = req.send().await?;
2291        let status = resp.status();
2292        let body_text = resp.text().await?;
2293        if !status.is_success() {
2294            return Err(Error::Api {
2295                status: status.as_u16(),
2296                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
2297                    .ok()
2298                    .and_then(|r| r.error)
2299                    .unwrap_or(body_text.clone()),
2300            });
2301        }
2302        Ok(serde_json::from_str(&body_text)?)
2303    }
2304
2305    /// Discover ClickPipe source schema (Beta).
2306    pub async fn click_pipe_schema_discovery(
2307        &self,
2308        organization_id: &str,
2309        service_id: &str,
2310        body: &ClickPipeSchemaDiscoveryRequest,
2311    ) -> Result<ApiResponse<ClickPipeSchemaDiscoveryResponse>, Error> {
2312        let path = format!(
2313            "/v1/organizations/{organization_id}/services/{service_id}/clickpipes/schemaDiscovery"
2314        );
2315        let mut req = self.request(reqwest::Method::POST, &path);
2316        req = req.json(body);
2317        let resp = req.send().await?;
2318        let status = resp.status();
2319        let body_text = resp.text().await?;
2320        if !status.is_success() {
2321            return Err(Error::Api {
2322                status: status.as_u16(),
2323                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
2324                    .ok()
2325                    .and_then(|r| r.error)
2326                    .unwrap_or(body_text.clone()),
2327            });
2328        }
2329        Ok(serde_json::from_str(&body_text)?)
2330    }
2331
2332    /// ClickStack: List Alerts
2333    pub async fn click_stack_list_alerts(
2334        &self,
2335        organization_id: &str,
2336        service_id: &str,
2337    ) -> Result<ApiResponse<Vec<ClickStackAlertResponse>>, Error> {
2338        let path =
2339            format!("/v1/organizations/{organization_id}/services/{service_id}/clickstack/alerts");
2340        let req = self.request(reqwest::Method::GET, &path);
2341        let resp = req.send().await?;
2342        let status = resp.status();
2343        let body_text = resp.text().await?;
2344        if !status.is_success() {
2345            return Err(Error::Api {
2346                status: status.as_u16(),
2347                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
2348                    .ok()
2349                    .and_then(|r| r.error)
2350                    .unwrap_or(body_text.clone()),
2351            });
2352        }
2353        Ok(serde_json::from_str(&body_text)?)
2354    }
2355
2356    /// ClickStack: Create Alert
2357    pub async fn click_stack_create_alert(
2358        &self,
2359        organization_id: &str,
2360        service_id: &str,
2361        body: &ClickStackCreateAlertRequest,
2362    ) -> Result<ApiResponse<ClickStackAlertResponse>, Error> {
2363        let path =
2364            format!("/v1/organizations/{organization_id}/services/{service_id}/clickstack/alerts");
2365        let mut req = self.request(reqwest::Method::POST, &path);
2366        req = req.json(body);
2367        let resp = req.send().await?;
2368        let status = resp.status();
2369        let body_text = resp.text().await?;
2370        if !status.is_success() {
2371            return Err(Error::Api {
2372                status: status.as_u16(),
2373                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
2374                    .ok()
2375                    .and_then(|r| r.error)
2376                    .unwrap_or(body_text.clone()),
2377            });
2378        }
2379        Ok(serde_json::from_str(&body_text)?)
2380    }
2381
2382    /// ClickStack: Get Alert
2383    pub async fn click_stack_get_alert(
2384        &self,
2385        organization_id: &str,
2386        service_id: &str,
2387        click_stack_alert_id: &str,
2388    ) -> Result<ApiResponse<ClickStackAlertResponse>, Error> {
2389        let path = format!(
2390            "/v1/organizations/{organization_id}/services/{service_id}/clickstack/alerts/{click_stack_alert_id}"
2391        );
2392        let req = self.request(reqwest::Method::GET, &path);
2393        let resp = req.send().await?;
2394        let status = resp.status();
2395        let body_text = resp.text().await?;
2396        if !status.is_success() {
2397            return Err(Error::Api {
2398                status: status.as_u16(),
2399                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
2400                    .ok()
2401                    .and_then(|r| r.error)
2402                    .unwrap_or(body_text.clone()),
2403            });
2404        }
2405        Ok(serde_json::from_str(&body_text)?)
2406    }
2407
2408    /// ClickStack: Update Alert
2409    pub async fn click_stack_update_alert(
2410        &self,
2411        organization_id: &str,
2412        service_id: &str,
2413        click_stack_alert_id: &str,
2414        body: &ClickStackUpdateAlertRequest,
2415    ) -> Result<ApiResponse<ClickStackAlertResponse>, Error> {
2416        let path = format!(
2417            "/v1/organizations/{organization_id}/services/{service_id}/clickstack/alerts/{click_stack_alert_id}"
2418        );
2419        let mut req = self.request(reqwest::Method::PUT, &path);
2420        req = req.json(body);
2421        let resp = req.send().await?;
2422        let status = resp.status();
2423        let body_text = resp.text().await?;
2424        if !status.is_success() {
2425            return Err(Error::Api {
2426                status: status.as_u16(),
2427                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
2428                    .ok()
2429                    .and_then(|r| r.error)
2430                    .unwrap_or(body_text.clone()),
2431            });
2432        }
2433        Ok(serde_json::from_str(&body_text)?)
2434    }
2435
2436    /// ClickStack: Delete Alert
2437    pub async fn click_stack_delete_alert(
2438        &self,
2439        organization_id: &str,
2440        service_id: &str,
2441        click_stack_alert_id: &str,
2442    ) -> Result<ApiResponse<serde_json::Value>, Error> {
2443        let path = format!(
2444            "/v1/organizations/{organization_id}/services/{service_id}/clickstack/alerts/{click_stack_alert_id}"
2445        );
2446        let req = self.request(reqwest::Method::DELETE, &path);
2447        let resp = req.send().await?;
2448        let status = resp.status();
2449        let body_text = resp.text().await?;
2450        if !status.is_success() {
2451            return Err(Error::Api {
2452                status: status.as_u16(),
2453                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
2454                    .ok()
2455                    .and_then(|r| r.error)
2456                    .unwrap_or(body_text.clone()),
2457            });
2458        }
2459        Ok(serde_json::from_str(&body_text)?)
2460    }
2461
2462    /// ClickStack: List Saved Searches
2463    pub async fn click_stack_list_saved_searches(
2464        &self,
2465        organization_id: &str,
2466        service_id: &str,
2467    ) -> Result<ApiResponse<Vec<ClickStackSavedSearch>>, Error> {
2468        let path = format!(
2469            "/v1/organizations/{organization_id}/services/{service_id}/clickstack/saved-searches"
2470        );
2471        let req = self.request(reqwest::Method::GET, &path);
2472        let resp = req.send().await?;
2473        let status = resp.status();
2474        let body_text = resp.text().await?;
2475        if !status.is_success() {
2476            return Err(Error::Api {
2477                status: status.as_u16(),
2478                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
2479                    .ok()
2480                    .and_then(|r| r.error)
2481                    .unwrap_or(body_text.clone()),
2482            });
2483        }
2484        Ok(serde_json::from_str(&body_text)?)
2485    }
2486
2487    /// ClickStack: Create Saved Search
2488    pub async fn click_stack_create_saved_search(
2489        &self,
2490        organization_id: &str,
2491        service_id: &str,
2492        body: &ClickStackSavedSearchInput,
2493    ) -> Result<ApiResponse<ClickStackSavedSearch>, Error> {
2494        let path = format!(
2495            "/v1/organizations/{organization_id}/services/{service_id}/clickstack/saved-searches"
2496        );
2497        let mut req = self.request(reqwest::Method::POST, &path);
2498        req = req.json(body);
2499        let resp = req.send().await?;
2500        let status = resp.status();
2501        let body_text = resp.text().await?;
2502        if !status.is_success() {
2503            return Err(Error::Api {
2504                status: status.as_u16(),
2505                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
2506                    .ok()
2507                    .and_then(|r| r.error)
2508                    .unwrap_or(body_text.clone()),
2509            });
2510        }
2511        Ok(serde_json::from_str(&body_text)?)
2512    }
2513
2514    /// ClickStack: Get Saved Search
2515    pub async fn click_stack_get_saved_search(
2516        &self,
2517        organization_id: &str,
2518        service_id: &str,
2519        click_stack_saved_search_id: &str,
2520    ) -> Result<ApiResponse<ClickStackSavedSearch>, Error> {
2521        let path = format!(
2522            "/v1/organizations/{organization_id}/services/{service_id}/clickstack/saved-searches/{click_stack_saved_search_id}"
2523        );
2524        let req = self.request(reqwest::Method::GET, &path);
2525        let resp = req.send().await?;
2526        let status = resp.status();
2527        let body_text = resp.text().await?;
2528        if !status.is_success() {
2529            return Err(Error::Api {
2530                status: status.as_u16(),
2531                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
2532                    .ok()
2533                    .and_then(|r| r.error)
2534                    .unwrap_or(body_text.clone()),
2535            });
2536        }
2537        Ok(serde_json::from_str(&body_text)?)
2538    }
2539
2540    /// ClickStack: Update Saved Search
2541    pub async fn click_stack_update_saved_search(
2542        &self,
2543        organization_id: &str,
2544        service_id: &str,
2545        click_stack_saved_search_id: &str,
2546        body: &ClickStackSavedSearchInput,
2547    ) -> Result<ApiResponse<ClickStackSavedSearch>, Error> {
2548        let path = format!(
2549            "/v1/organizations/{organization_id}/services/{service_id}/clickstack/saved-searches/{click_stack_saved_search_id}"
2550        );
2551        let mut req = self.request(reqwest::Method::PUT, &path);
2552        req = req.json(body);
2553        let resp = req.send().await?;
2554        let status = resp.status();
2555        let body_text = resp.text().await?;
2556        if !status.is_success() {
2557            return Err(Error::Api {
2558                status: status.as_u16(),
2559                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
2560                    .ok()
2561                    .and_then(|r| r.error)
2562                    .unwrap_or(body_text.clone()),
2563            });
2564        }
2565        Ok(serde_json::from_str(&body_text)?)
2566    }
2567
2568    /// ClickStack: Delete Saved Search
2569    pub async fn click_stack_delete_saved_search(
2570        &self,
2571        organization_id: &str,
2572        service_id: &str,
2573        click_stack_saved_search_id: &str,
2574    ) -> Result<ApiResponse<serde_json::Value>, Error> {
2575        let path = format!(
2576            "/v1/organizations/{organization_id}/services/{service_id}/clickstack/saved-searches/{click_stack_saved_search_id}"
2577        );
2578        let req = self.request(reqwest::Method::DELETE, &path);
2579        let resp = req.send().await?;
2580        let status = resp.status();
2581        let body_text = resp.text().await?;
2582        if !status.is_success() {
2583            return Err(Error::Api {
2584                status: status.as_u16(),
2585                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
2586                    .ok()
2587                    .and_then(|r| r.error)
2588                    .unwrap_or(body_text.clone()),
2589            });
2590        }
2591        Ok(serde_json::from_str(&body_text)?)
2592    }
2593
2594    /// ClickStack: List Dashboards
2595    pub async fn click_stack_list_dashboards(
2596        &self,
2597        organization_id: &str,
2598        service_id: &str,
2599    ) -> Result<ApiResponse<Vec<ClickStackDashboardResponse>>, Error> {
2600        let path = format!(
2601            "/v1/organizations/{organization_id}/services/{service_id}/clickstack/dashboards"
2602        );
2603        let req = self.request(reqwest::Method::GET, &path);
2604        let resp = req.send().await?;
2605        let status = resp.status();
2606        let body_text = resp.text().await?;
2607        if !status.is_success() {
2608            return Err(Error::Api {
2609                status: status.as_u16(),
2610                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
2611                    .ok()
2612                    .and_then(|r| r.error)
2613                    .unwrap_or(body_text.clone()),
2614            });
2615        }
2616        Ok(serde_json::from_str(&body_text)?)
2617    }
2618
2619    /// ClickStack: Create Dashboard
2620    pub async fn click_stack_create_dashboard(
2621        &self,
2622        organization_id: &str,
2623        service_id: &str,
2624        body: &ClickStackCreateDashboardRequest,
2625    ) -> Result<ApiResponse<ClickStackDashboardResponse>, Error> {
2626        let path = format!(
2627            "/v1/organizations/{organization_id}/services/{service_id}/clickstack/dashboards"
2628        );
2629        let mut req = self.request(reqwest::Method::POST, &path);
2630        req = req.json(body);
2631        let resp = req.send().await?;
2632        let status = resp.status();
2633        let body_text = resp.text().await?;
2634        if !status.is_success() {
2635            return Err(Error::Api {
2636                status: status.as_u16(),
2637                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
2638                    .ok()
2639                    .and_then(|r| r.error)
2640                    .unwrap_or(body_text.clone()),
2641            });
2642        }
2643        Ok(serde_json::from_str(&body_text)?)
2644    }
2645
2646    /// ClickStack: Get Dashboard
2647    pub async fn click_stack_get_dashboard(
2648        &self,
2649        organization_id: &str,
2650        service_id: &str,
2651        click_stack_dashboard_id: &str,
2652    ) -> Result<ApiResponse<ClickStackDashboardResponse>, Error> {
2653        let path = format!(
2654            "/v1/organizations/{organization_id}/services/{service_id}/clickstack/dashboards/{click_stack_dashboard_id}"
2655        );
2656        let req = self.request(reqwest::Method::GET, &path);
2657        let resp = req.send().await?;
2658        let status = resp.status();
2659        let body_text = resp.text().await?;
2660        if !status.is_success() {
2661            return Err(Error::Api {
2662                status: status.as_u16(),
2663                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
2664                    .ok()
2665                    .and_then(|r| r.error)
2666                    .unwrap_or(body_text.clone()),
2667            });
2668        }
2669        Ok(serde_json::from_str(&body_text)?)
2670    }
2671
2672    /// ClickStack: Update Dashboard
2673    pub async fn click_stack_update_dashboard(
2674        &self,
2675        organization_id: &str,
2676        service_id: &str,
2677        click_stack_dashboard_id: &str,
2678        body: &ClickStackUpdateDashboardRequest,
2679    ) -> Result<ApiResponse<ClickStackDashboardResponse>, Error> {
2680        let path = format!(
2681            "/v1/organizations/{organization_id}/services/{service_id}/clickstack/dashboards/{click_stack_dashboard_id}"
2682        );
2683        let mut req = self.request(reqwest::Method::PUT, &path);
2684        req = req.json(body);
2685        let resp = req.send().await?;
2686        let status = resp.status();
2687        let body_text = resp.text().await?;
2688        if !status.is_success() {
2689            return Err(Error::Api {
2690                status: status.as_u16(),
2691                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
2692                    .ok()
2693                    .and_then(|r| r.error)
2694                    .unwrap_or(body_text.clone()),
2695            });
2696        }
2697        Ok(serde_json::from_str(&body_text)?)
2698    }
2699
2700    /// ClickStack: Delete Dashboard
2701    pub async fn click_stack_delete_dashboard(
2702        &self,
2703        organization_id: &str,
2704        service_id: &str,
2705        click_stack_dashboard_id: &str,
2706    ) -> Result<ApiResponse<serde_json::Value>, Error> {
2707        let path = format!(
2708            "/v1/organizations/{organization_id}/services/{service_id}/clickstack/dashboards/{click_stack_dashboard_id}"
2709        );
2710        let req = self.request(reqwest::Method::DELETE, &path);
2711        let resp = req.send().await?;
2712        let status = resp.status();
2713        let body_text = resp.text().await?;
2714        if !status.is_success() {
2715            return Err(Error::Api {
2716                status: status.as_u16(),
2717                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
2718                    .ok()
2719                    .and_then(|r| r.error)
2720                    .unwrap_or(body_text.clone()),
2721            });
2722        }
2723        Ok(serde_json::from_str(&body_text)?)
2724    }
2725
2726    /// ClickStack: List Sources
2727    pub async fn click_stack_list_sources(
2728        &self,
2729        organization_id: &str,
2730        service_id: &str,
2731    ) -> Result<ApiResponse<Vec<ClickStackSourceResponse>>, Error> {
2732        let path =
2733            format!("/v1/organizations/{organization_id}/services/{service_id}/clickstack/sources");
2734        let req = self.request(reqwest::Method::GET, &path);
2735        let resp = req.send().await?;
2736        let status = resp.status();
2737        let body_text = resp.text().await?;
2738        if !status.is_success() {
2739            return Err(Error::Api {
2740                status: status.as_u16(),
2741                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
2742                    .ok()
2743                    .and_then(|r| r.error)
2744                    .unwrap_or(body_text.clone()),
2745            });
2746        }
2747        Ok(serde_json::from_str(&body_text)?)
2748    }
2749
2750    /// ClickStack: Create Source
2751    pub async fn click_stack_create_source(
2752        &self,
2753        organization_id: &str,
2754        service_id: &str,
2755        body: &ClickStackSource,
2756    ) -> Result<ApiResponse<ClickStackSourceResponse>, Error> {
2757        let path =
2758            format!("/v1/organizations/{organization_id}/services/{service_id}/clickstack/sources");
2759        let mut req = self.request(reqwest::Method::POST, &path);
2760        req = req.json(body);
2761        let resp = req.send().await?;
2762        let status = resp.status();
2763        let body_text = resp.text().await?;
2764        if !status.is_success() {
2765            return Err(Error::Api {
2766                status: status.as_u16(),
2767                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
2768                    .ok()
2769                    .and_then(|r| r.error)
2770                    .unwrap_or(body_text.clone()),
2771            });
2772        }
2773        Ok(serde_json::from_str(&body_text)?)
2774    }
2775
2776    /// ClickStack: Get Source
2777    pub async fn click_stack_get_source(
2778        &self,
2779        organization_id: &str,
2780        service_id: &str,
2781        click_stack_source_id: &str,
2782    ) -> Result<ApiResponse<ClickStackSourceResponse>, Error> {
2783        let path = format!(
2784            "/v1/organizations/{organization_id}/services/{service_id}/clickstack/sources/{click_stack_source_id}"
2785        );
2786        let req = self.request(reqwest::Method::GET, &path);
2787        let resp = req.send().await?;
2788        let status = resp.status();
2789        let body_text = resp.text().await?;
2790        if !status.is_success() {
2791            return Err(Error::Api {
2792                status: status.as_u16(),
2793                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
2794                    .ok()
2795                    .and_then(|r| r.error)
2796                    .unwrap_or(body_text.clone()),
2797            });
2798        }
2799        Ok(serde_json::from_str(&body_text)?)
2800    }
2801
2802    /// ClickStack: Update Source
2803    pub async fn click_stack_update_source(
2804        &self,
2805        organization_id: &str,
2806        service_id: &str,
2807        click_stack_source_id: &str,
2808        body: &ClickStackSource,
2809    ) -> Result<ApiResponse<ClickStackSourceResponse>, Error> {
2810        let path = format!(
2811            "/v1/organizations/{organization_id}/services/{service_id}/clickstack/sources/{click_stack_source_id}"
2812        );
2813        let mut req = self.request(reqwest::Method::PUT, &path);
2814        req = req.json(body);
2815        let resp = req.send().await?;
2816        let status = resp.status();
2817        let body_text = resp.text().await?;
2818        if !status.is_success() {
2819            return Err(Error::Api {
2820                status: status.as_u16(),
2821                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
2822                    .ok()
2823                    .and_then(|r| r.error)
2824                    .unwrap_or(body_text.clone()),
2825            });
2826        }
2827        Ok(serde_json::from_str(&body_text)?)
2828    }
2829
2830    /// ClickStack: Delete Source
2831    pub async fn click_stack_delete_source(
2832        &self,
2833        organization_id: &str,
2834        service_id: &str,
2835        click_stack_source_id: &str,
2836    ) -> Result<ApiResponse<serde_json::Value>, Error> {
2837        let path = format!(
2838            "/v1/organizations/{organization_id}/services/{service_id}/clickstack/sources/{click_stack_source_id}"
2839        );
2840        let req = self.request(reqwest::Method::DELETE, &path);
2841        let resp = req.send().await?;
2842        let status = resp.status();
2843        let body_text = resp.text().await?;
2844        if !status.is_success() {
2845            return Err(Error::Api {
2846                status: status.as_u16(),
2847                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
2848                    .ok()
2849                    .and_then(|r| r.error)
2850                    .unwrap_or(body_text.clone()),
2851            });
2852        }
2853        Ok(serde_json::from_str(&body_text)?)
2854    }
2855
2856    /// ClickStack: List Connections
2857    pub async fn click_stack_list_connections(
2858        &self,
2859        organization_id: &str,
2860        service_id: &str,
2861    ) -> Result<ApiResponse<Vec<ClickStackConnection>>, Error> {
2862        let path = format!(
2863            "/v1/organizations/{organization_id}/services/{service_id}/clickstack/connections"
2864        );
2865        let req = self.request(reqwest::Method::GET, &path);
2866        let resp = req.send().await?;
2867        let status = resp.status();
2868        let body_text = resp.text().await?;
2869        if !status.is_success() {
2870            return Err(Error::Api {
2871                status: status.as_u16(),
2872                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
2873                    .ok()
2874                    .and_then(|r| r.error)
2875                    .unwrap_or(body_text.clone()),
2876            });
2877        }
2878        Ok(serde_json::from_str(&body_text)?)
2879    }
2880
2881    /// ClickStack: Create Connection
2882    pub async fn click_stack_create_connection(
2883        &self,
2884        organization_id: &str,
2885        service_id: &str,
2886        body: &ClickStackCreateConnectionRequest,
2887    ) -> Result<ApiResponse<ClickStackConnection>, Error> {
2888        let path = format!(
2889            "/v1/organizations/{organization_id}/services/{service_id}/clickstack/connections"
2890        );
2891        let mut req = self.request(reqwest::Method::POST, &path);
2892        req = req.json(body);
2893        let resp = req.send().await?;
2894        let status = resp.status();
2895        let body_text = resp.text().await?;
2896        if !status.is_success() {
2897            return Err(Error::Api {
2898                status: status.as_u16(),
2899                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
2900                    .ok()
2901                    .and_then(|r| r.error)
2902                    .unwrap_or(body_text.clone()),
2903            });
2904        }
2905        Ok(serde_json::from_str(&body_text)?)
2906    }
2907
2908    /// ClickStack: Get Connection
2909    pub async fn click_stack_get_connection(
2910        &self,
2911        organization_id: &str,
2912        service_id: &str,
2913        click_stack_connection_id: &str,
2914    ) -> Result<ApiResponse<ClickStackConnection>, Error> {
2915        let path = format!(
2916            "/v1/organizations/{organization_id}/services/{service_id}/clickstack/connections/{click_stack_connection_id}"
2917        );
2918        let req = self.request(reqwest::Method::GET, &path);
2919        let resp = req.send().await?;
2920        let status = resp.status();
2921        let body_text = resp.text().await?;
2922        if !status.is_success() {
2923            return Err(Error::Api {
2924                status: status.as_u16(),
2925                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
2926                    .ok()
2927                    .and_then(|r| r.error)
2928                    .unwrap_or(body_text.clone()),
2929            });
2930        }
2931        Ok(serde_json::from_str(&body_text)?)
2932    }
2933
2934    /// ClickStack: Update Connection
2935    pub async fn click_stack_update_connection(
2936        &self,
2937        organization_id: &str,
2938        service_id: &str,
2939        click_stack_connection_id: &str,
2940        body: &ClickStackUpdateConnectionRequest,
2941    ) -> Result<ApiResponse<ClickStackConnection>, Error> {
2942        let path = format!(
2943            "/v1/organizations/{organization_id}/services/{service_id}/clickstack/connections/{click_stack_connection_id}"
2944        );
2945        let mut req = self.request(reqwest::Method::PUT, &path);
2946        req = req.json(body);
2947        let resp = req.send().await?;
2948        let status = resp.status();
2949        let body_text = resp.text().await?;
2950        if !status.is_success() {
2951            return Err(Error::Api {
2952                status: status.as_u16(),
2953                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
2954                    .ok()
2955                    .and_then(|r| r.error)
2956                    .unwrap_or(body_text.clone()),
2957            });
2958        }
2959        Ok(serde_json::from_str(&body_text)?)
2960    }
2961
2962    /// ClickStack: Delete Connection
2963    pub async fn click_stack_delete_connection(
2964        &self,
2965        organization_id: &str,
2966        service_id: &str,
2967        click_stack_connection_id: &str,
2968    ) -> Result<ApiResponse<serde_json::Value>, Error> {
2969        let path = format!(
2970            "/v1/organizations/{organization_id}/services/{service_id}/clickstack/connections/{click_stack_connection_id}"
2971        );
2972        let req = self.request(reqwest::Method::DELETE, &path);
2973        let resp = req.send().await?;
2974        let status = resp.status();
2975        let body_text = resp.text().await?;
2976        if !status.is_success() {
2977            return Err(Error::Api {
2978                status: status.as_u16(),
2979                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
2980                    .ok()
2981                    .and_then(|r| r.error)
2982                    .unwrap_or(body_text.clone()),
2983            });
2984        }
2985        Ok(serde_json::from_str(&body_text)?)
2986    }
2987
2988    /// ClickStack: List Roles
2989    pub async fn click_stack_list_roles(
2990        &self,
2991        organization_id: &str,
2992        service_id: &str,
2993    ) -> Result<ApiResponse<Vec<ClickStackRole>>, Error> {
2994        let path =
2995            format!("/v1/organizations/{organization_id}/services/{service_id}/clickstack/roles");
2996        let req = self.request(reqwest::Method::GET, &path);
2997        let resp = req.send().await?;
2998        let status = resp.status();
2999        let body_text = resp.text().await?;
3000        if !status.is_success() {
3001            return Err(Error::Api {
3002                status: status.as_u16(),
3003                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
3004                    .ok()
3005                    .and_then(|r| r.error)
3006                    .unwrap_or(body_text.clone()),
3007            });
3008        }
3009        Ok(serde_json::from_str(&body_text)?)
3010    }
3011
3012    /// ClickStack: Create Role
3013    pub async fn click_stack_create_role(
3014        &self,
3015        organization_id: &str,
3016        service_id: &str,
3017        body: &ClickStackCreateRoleRequest,
3018    ) -> Result<ApiResponse<ClickStackRole>, Error> {
3019        let path =
3020            format!("/v1/organizations/{organization_id}/services/{service_id}/clickstack/roles");
3021        let mut req = self.request(reqwest::Method::POST, &path);
3022        req = req.json(body);
3023        let resp = req.send().await?;
3024        let status = resp.status();
3025        let body_text = resp.text().await?;
3026        if !status.is_success() {
3027            return Err(Error::Api {
3028                status: status.as_u16(),
3029                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
3030                    .ok()
3031                    .and_then(|r| r.error)
3032                    .unwrap_or(body_text.clone()),
3033            });
3034        }
3035        Ok(serde_json::from_str(&body_text)?)
3036    }
3037
3038    /// ClickStack: Get Role
3039    pub async fn click_stack_get_role(
3040        &self,
3041        organization_id: &str,
3042        service_id: &str,
3043        click_stack_role_id: &str,
3044    ) -> Result<ApiResponse<ClickStackRole>, Error> {
3045        let path = format!(
3046            "/v1/organizations/{organization_id}/services/{service_id}/clickstack/roles/{click_stack_role_id}"
3047        );
3048        let req = self.request(reqwest::Method::GET, &path);
3049        let resp = req.send().await?;
3050        let status = resp.status();
3051        let body_text = resp.text().await?;
3052        if !status.is_success() {
3053            return Err(Error::Api {
3054                status: status.as_u16(),
3055                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
3056                    .ok()
3057                    .and_then(|r| r.error)
3058                    .unwrap_or(body_text.clone()),
3059            });
3060        }
3061        Ok(serde_json::from_str(&body_text)?)
3062    }
3063
3064    /// ClickStack: Update Role
3065    pub async fn click_stack_update_role(
3066        &self,
3067        organization_id: &str,
3068        service_id: &str,
3069        click_stack_role_id: &str,
3070        body: &ClickStackUpdateRoleRequest,
3071    ) -> Result<ApiResponse<ClickStackRole>, Error> {
3072        let path = format!(
3073            "/v1/organizations/{organization_id}/services/{service_id}/clickstack/roles/{click_stack_role_id}"
3074        );
3075        let mut req = self.request(reqwest::Method::PUT, &path);
3076        req = req.json(body);
3077        let resp = req.send().await?;
3078        let status = resp.status();
3079        let body_text = resp.text().await?;
3080        if !status.is_success() {
3081            return Err(Error::Api {
3082                status: status.as_u16(),
3083                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
3084                    .ok()
3085                    .and_then(|r| r.error)
3086                    .unwrap_or(body_text.clone()),
3087            });
3088        }
3089        Ok(serde_json::from_str(&body_text)?)
3090    }
3091
3092    /// ClickStack: Delete Role
3093    pub async fn click_stack_delete_role(
3094        &self,
3095        organization_id: &str,
3096        service_id: &str,
3097        click_stack_role_id: &str,
3098    ) -> Result<ApiResponse<serde_json::Value>, Error> {
3099        let path = format!(
3100            "/v1/organizations/{organization_id}/services/{service_id}/clickstack/roles/{click_stack_role_id}"
3101        );
3102        let req = self.request(reqwest::Method::DELETE, &path);
3103        let resp = req.send().await?;
3104        let status = resp.status();
3105        let body_text = resp.text().await?;
3106        if !status.is_success() {
3107            return Err(Error::Api {
3108                status: status.as_u16(),
3109                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
3110                    .ok()
3111                    .and_then(|r| r.error)
3112                    .unwrap_or(body_text.clone()),
3113            });
3114        }
3115        Ok(serde_json::from_str(&body_text)?)
3116    }
3117
3118    /// ClickStack: List Webhooks
3119    pub async fn click_stack_list_webhooks(
3120        &self,
3121        organization_id: &str,
3122        service_id: &str,
3123    ) -> Result<ApiResponse<Vec<ClickStackWebhook>>, Error> {
3124        let path = format!(
3125            "/v1/organizations/{organization_id}/services/{service_id}/clickstack/webhooks"
3126        );
3127        let req = self.request(reqwest::Method::GET, &path);
3128        let resp = req.send().await?;
3129        let status = resp.status();
3130        let body_text = resp.text().await?;
3131        if !status.is_success() {
3132            return Err(Error::Api {
3133                status: status.as_u16(),
3134                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
3135                    .ok()
3136                    .and_then(|r| r.error)
3137                    .unwrap_or(body_text.clone()),
3138            });
3139        }
3140        Ok(serde_json::from_str(&body_text)?)
3141    }
3142
3143    /// ClickStack: Create Webhook
3144    pub async fn click_stack_create_webhook(
3145        &self,
3146        organization_id: &str,
3147        service_id: &str,
3148        body: &ClickStackWebhookInput,
3149    ) -> Result<ApiResponse<ClickStackWebhook>, Error> {
3150        let path = format!(
3151            "/v1/organizations/{organization_id}/services/{service_id}/clickstack/webhooks"
3152        );
3153        let mut req = self.request(reqwest::Method::POST, &path);
3154        req = req.json(body);
3155        let resp = req.send().await?;
3156        let status = resp.status();
3157        let body_text = resp.text().await?;
3158        if !status.is_success() {
3159            return Err(Error::Api {
3160                status: status.as_u16(),
3161                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
3162                    .ok()
3163                    .and_then(|r| r.error)
3164                    .unwrap_or(body_text.clone()),
3165            });
3166        }
3167        Ok(serde_json::from_str(&body_text)?)
3168    }
3169
3170    /// ClickStack: Update Webhook
3171    pub async fn click_stack_update_webhook(
3172        &self,
3173        organization_id: &str,
3174        service_id: &str,
3175        click_stack_webhook_id: &str,
3176        body: &ClickStackWebhookInput,
3177    ) -> Result<ApiResponse<ClickStackWebhook>, Error> {
3178        let path = format!(
3179            "/v1/organizations/{organization_id}/services/{service_id}/clickstack/webhooks/{click_stack_webhook_id}"
3180        );
3181        let mut req = self.request(reqwest::Method::PUT, &path);
3182        req = req.json(body);
3183        let resp = req.send().await?;
3184        let status = resp.status();
3185        let body_text = resp.text().await?;
3186        if !status.is_success() {
3187            return Err(Error::Api {
3188                status: status.as_u16(),
3189                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
3190                    .ok()
3191                    .and_then(|r| r.error)
3192                    .unwrap_or(body_text.clone()),
3193            });
3194        }
3195        Ok(serde_json::from_str(&body_text)?)
3196    }
3197
3198    /// ClickStack: Delete Webhook
3199    pub async fn click_stack_delete_webhook(
3200        &self,
3201        organization_id: &str,
3202        service_id: &str,
3203        click_stack_webhook_id: &str,
3204    ) -> Result<ApiResponse<serde_json::Value>, Error> {
3205        let path = format!(
3206            "/v1/organizations/{organization_id}/services/{service_id}/clickstack/webhooks/{click_stack_webhook_id}"
3207        );
3208        let req = self.request(reqwest::Method::DELETE, &path);
3209        let resp = req.send().await?;
3210        let status = resp.status();
3211        let body_text = resp.text().await?;
3212        if !status.is_success() {
3213            return Err(Error::Api {
3214                status: status.as_u16(),
3215                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
3216                    .ok()
3217                    .and_then(|r| r.error)
3218                    .unwrap_or(body_text.clone()),
3219            });
3220        }
3221        Ok(serde_json::from_str(&body_text)?)
3222    }
3223
3224    /// ClickStack: Validate Dashboard
3225    pub async fn click_stack_validate_dashboard(
3226        &self,
3227        organization_id: &str,
3228        service_id: &str,
3229        body: &ClickStackCreateDashboardRequest,
3230    ) -> Result<ApiResponse<ClickStackValidateDashboardResponse>, Error> {
3231        let path = format!(
3232            "/v1/organizations/{organization_id}/services/{service_id}/clickstack/dashboards/validate"
3233        );
3234        let mut req = self.request(reqwest::Method::POST, &path);
3235        req = req.json(body);
3236        let resp = req.send().await?;
3237        let status = resp.status();
3238        let body_text = resp.text().await?;
3239        if !status.is_success() {
3240            return Err(Error::Api {
3241                status: status.as_u16(),
3242                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
3243                    .ok()
3244                    .and_then(|r| r.error)
3245                    .unwrap_or(body_text.clone()),
3246            });
3247        }
3248        Ok(serde_json::from_str(&body_text)?)
3249    }
3250
3251    /// Update service password
3252    pub async fn instance_password_update(
3253        &self,
3254        organization_id: &str,
3255        service_id: &str,
3256        body: &ServicePasswordPatchRequest,
3257    ) -> Result<ApiResponse<ServicePasswordPatchResponse>, Error> {
3258        let path = format!("/v1/organizations/{organization_id}/services/{service_id}/password");
3259        let mut req = self.request(reqwest::Method::PATCH, &path);
3260        req = req.json(body);
3261        let resp = req.send().await?;
3262        let status = resp.status();
3263        let body_text = resp.text().await?;
3264        if !status.is_success() {
3265            return Err(Error::Api {
3266                status: status.as_u16(),
3267                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
3268                    .ok()
3269                    .and_then(|r| r.error)
3270                    .unwrap_or(body_text.clone()),
3271            });
3272        }
3273        Ok(serde_json::from_str(&body_text)?)
3274    }
3275
3276    /// Create a private endpoint
3277    pub async fn instance_private_endpoint_create(
3278        &self,
3279        organization_id: &str,
3280        service_id: &str,
3281        body: &ServicPrivateEndpointePostRequest,
3282    ) -> Result<ApiResponse<InstancePrivateEndpoint>, Error> {
3283        let path =
3284            format!("/v1/organizations/{organization_id}/services/{service_id}/privateEndpoint");
3285        let mut req = self.request(reqwest::Method::POST, &path);
3286        req = req.json(body);
3287        let resp = req.send().await?;
3288        let status = resp.status();
3289        let body_text = resp.text().await?;
3290        if !status.is_success() {
3291            return Err(Error::Api {
3292                status: status.as_u16(),
3293                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
3294                    .ok()
3295                    .and_then(|r| r.error)
3296                    .unwrap_or(body_text.clone()),
3297            });
3298        }
3299        Ok(serde_json::from_str(&body_text)?)
3300    }
3301
3302    /// Get private endpoint configuration
3303    pub async fn instance_private_endpoint_config_get(
3304        &self,
3305        organization_id: &str,
3306        service_id: &str,
3307    ) -> Result<ApiResponse<PrivateEndpointConfig>, Error> {
3308        let path = format!(
3309            "/v1/organizations/{organization_id}/services/{service_id}/privateEndpointConfig"
3310        );
3311        let req = self.request(reqwest::Method::GET, &path);
3312        let resp = req.send().await?;
3313        let status = resp.status();
3314        let body_text = resp.text().await?;
3315        if !status.is_success() {
3316            return Err(Error::Api {
3317                status: status.as_u16(),
3318                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
3319                    .ok()
3320                    .and_then(|r| r.error)
3321                    .unwrap_or(body_text.clone()),
3322            });
3323        }
3324        Ok(serde_json::from_str(&body_text)?)
3325    }
3326
3327    /// Get service metrics
3328    pub async fn instance_prometheus_get(
3329        &self,
3330        organization_id: &str,
3331        service_id: &str,
3332        filtered_metrics: Option<&str>,
3333    ) -> Result<String, Error> {
3334        let path = format!("/v1/organizations/{organization_id}/services/{service_id}/prometheus");
3335        let mut req = self.request(reqwest::Method::GET, &path);
3336        if let Some(v) = filtered_metrics {
3337            req = req.query(&[("filtered_metrics", v)]);
3338        }
3339        let resp = req.send().await?;
3340        let status = resp.status();
3341        if !status.is_success() {
3342            let body_text = resp.text().await?;
3343            return Err(Error::Api {
3344                status: status.as_u16(),
3345                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
3346                    .ok()
3347                    .and_then(|r| r.error)
3348                    .unwrap_or(body_text),
3349            });
3350        }
3351        Ok(resp.text().await?)
3352    }
3353
3354    /// Update service auto scaling settings
3355    pub async fn instance_replica_scaling_update(
3356        &self,
3357        organization_id: &str,
3358        service_id: &str,
3359        body: &ServiceReplicaScalingPatchRequest,
3360    ) -> Result<ApiResponse<ServiceScalingPatchResponse>, Error> {
3361        let path =
3362            format!("/v1/organizations/{organization_id}/services/{service_id}/replicaScaling");
3363        let mut req = self.request(reqwest::Method::PATCH, &path);
3364        req = req.json(body);
3365        let resp = req.send().await?;
3366        let status = resp.status();
3367        let body_text = resp.text().await?;
3368        if !status.is_success() {
3369            return Err(Error::Api {
3370                status: status.as_u16(),
3371                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
3372                    .ok()
3373                    .and_then(|r| r.error)
3374                    .unwrap_or(body_text.clone()),
3375            });
3376        }
3377        Ok(serde_json::from_str(&body_text)?)
3378    }
3379
3380    /// Update service auto scaling settings
3381    #[deprecated]
3382    #[allow(deprecated)]
3383    pub async fn instance_scaling_update(
3384        &self,
3385        organization_id: &str,
3386        service_id: &str,
3387        body: &ServiceScalingPatchRequest,
3388    ) -> Result<ApiResponse<Service>, Error> {
3389        let path = format!("/v1/organizations/{organization_id}/services/{service_id}/scaling");
3390        let mut req = self.request(reqwest::Method::PATCH, &path);
3391        req = req.json(body);
3392        let resp = req.send().await?;
3393        let status = resp.status();
3394        let body_text = resp.text().await?;
3395        if !status.is_success() {
3396            return Err(Error::Api {
3397                status: status.as_u16(),
3398                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
3399                    .ok()
3400                    .and_then(|r| r.error)
3401                    .unwrap_or(body_text.clone()),
3402            });
3403        }
3404        Ok(serde_json::from_str(&body_text)?)
3405    }
3406
3407    /// Get service autoscaling schedule
3408    pub async fn scaling_schedule_get(
3409        &self,
3410        organization_id: &str,
3411        service_id: &str,
3412    ) -> Result<ApiResponse<ScalingSchedule>, Error> {
3413        let path =
3414            format!("/v1/organizations/{organization_id}/services/{service_id}/scalingSchedule");
3415        let req = self.request(reqwest::Method::GET, &path);
3416        let resp = req.send().await?;
3417        let status = resp.status();
3418        let body_text = resp.text().await?;
3419        if !status.is_success() {
3420            return Err(Error::Api {
3421                status: status.as_u16(),
3422                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
3423                    .ok()
3424                    .and_then(|r| r.error)
3425                    .unwrap_or(body_text.clone()),
3426            });
3427        }
3428        Ok(serde_json::from_str(&body_text)?)
3429    }
3430
3431    /// Create or replace service autoscaling schedule
3432    pub async fn scaling_schedule_upsert(
3433        &self,
3434        organization_id: &str,
3435        service_id: &str,
3436        body: &ScalingSchedulePostRequest,
3437    ) -> Result<ApiResponse<ScalingSchedule>, Error> {
3438        let path =
3439            format!("/v1/organizations/{organization_id}/services/{service_id}/scalingSchedule");
3440        let mut req = self.request(reqwest::Method::POST, &path);
3441        req = req.json(body);
3442        let resp = req.send().await?;
3443        let status = resp.status();
3444        let body_text = resp.text().await?;
3445        if !status.is_success() {
3446            return Err(Error::Api {
3447                status: status.as_u16(),
3448                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
3449                    .ok()
3450                    .and_then(|r| r.error)
3451                    .unwrap_or(body_text.clone()),
3452            });
3453        }
3454        Ok(serde_json::from_str(&body_text)?)
3455    }
3456
3457    /// Delete service scheduled scaling
3458    pub async fn scaling_schedule_delete(
3459        &self,
3460        organization_id: &str,
3461        service_id: &str,
3462    ) -> Result<ApiResponse<serde_json::Value>, Error> {
3463        let path =
3464            format!("/v1/organizations/{organization_id}/services/{service_id}/scalingSchedule");
3465        let req = self.request(reqwest::Method::DELETE, &path);
3466        let resp = req.send().await?;
3467        let status = resp.status();
3468        let body_text = resp.text().await?;
3469        if !status.is_success() {
3470            return Err(Error::Api {
3471                status: status.as_u16(),
3472                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
3473                    .ok()
3474                    .and_then(|r| r.error)
3475                    .unwrap_or(body_text.clone()),
3476            });
3477        }
3478        Ok(serde_json::from_str(&body_text)?)
3479    }
3480
3481    /// Get service upgrade window
3482    pub async fn upgrade_window_get(
3483        &self,
3484        organization_id: &str,
3485        service_id: &str,
3486    ) -> Result<ApiResponse<UpgradeWindow>, Error> {
3487        let path =
3488            format!("/v1/organizations/{organization_id}/services/{service_id}/upgradeWindow");
3489        let req = self.request(reqwest::Method::GET, &path);
3490        let resp = req.send().await?;
3491        let status = resp.status();
3492        let body_text = resp.text().await?;
3493        if !status.is_success() {
3494            return Err(Error::Api {
3495                status: status.as_u16(),
3496                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
3497                    .ok()
3498                    .and_then(|r| r.error)
3499                    .unwrap_or(body_text.clone()),
3500            });
3501        }
3502        Ok(serde_json::from_str(&body_text)?)
3503    }
3504
3505    /// Set service upgrade window
3506    pub async fn upgrade_window_update(
3507        &self,
3508        organization_id: &str,
3509        service_id: &str,
3510        body: &UpgradeWindowPutRequest,
3511    ) -> Result<ApiResponse<UpgradeWindow>, Error> {
3512        let path =
3513            format!("/v1/organizations/{organization_id}/services/{service_id}/upgradeWindow");
3514        let mut req = self.request(reqwest::Method::PUT, &path);
3515        req = req.json(body);
3516        let resp = req.send().await?;
3517        let status = resp.status();
3518        let body_text = resp.text().await?;
3519        if !status.is_success() {
3520            return Err(Error::Api {
3521                status: status.as_u16(),
3522                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
3523                    .ok()
3524                    .and_then(|r| r.error)
3525                    .unwrap_or(body_text.clone()),
3526            });
3527        }
3528        Ok(serde_json::from_str(&body_text)?)
3529    }
3530
3531    /// Delete service upgrade window
3532    pub async fn upgrade_window_delete(
3533        &self,
3534        organization_id: &str,
3535        service_id: &str,
3536    ) -> Result<ApiResponse<serde_json::Value>, Error> {
3537        let path =
3538            format!("/v1/organizations/{organization_id}/services/{service_id}/upgradeWindow");
3539        let req = self.request(reqwest::Method::DELETE, &path);
3540        let resp = req.send().await?;
3541        let status = resp.status();
3542        let body_text = resp.text().await?;
3543        if !status.is_success() {
3544            return Err(Error::Api {
3545                status: status.as_u16(),
3546                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
3547                    .ok()
3548                    .and_then(|r| r.error)
3549                    .unwrap_or(body_text.clone()),
3550            });
3551        }
3552        Ok(serde_json::from_str(&body_text)?)
3553    }
3554
3555    /// Get the service query endpoint for a given instance
3556    pub async fn instance_query_endpoint_get(
3557        &self,
3558        organization_id: &str,
3559        service_id: &str,
3560    ) -> Result<ApiResponse<ServiceQueryAPIEndpoint>, Error> {
3561        let path = format!(
3562            "/v1/organizations/{organization_id}/services/{service_id}/serviceQueryEndpoint"
3563        );
3564        let req = self.request(reqwest::Method::GET, &path);
3565        let resp = req.send().await?;
3566        let status = resp.status();
3567        let body_text = resp.text().await?;
3568        if !status.is_success() {
3569            return Err(Error::Api {
3570                status: status.as_u16(),
3571                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
3572                    .ok()
3573                    .and_then(|r| r.error)
3574                    .unwrap_or(body_text.clone()),
3575            });
3576        }
3577        Ok(serde_json::from_str(&body_text)?)
3578    }
3579
3580    /// Delete the service query endpoint for a given instance
3581    pub async fn instance_query_endpoint_delete(
3582        &self,
3583        organization_id: &str,
3584        service_id: &str,
3585    ) -> Result<ApiResponse<serde_json::Value>, Error> {
3586        let path = format!(
3587            "/v1/organizations/{organization_id}/services/{service_id}/serviceQueryEndpoint"
3588        );
3589        let req = self.request(reqwest::Method::DELETE, &path);
3590        let resp = req.send().await?;
3591        let status = resp.status();
3592        let body_text = resp.text().await?;
3593        if !status.is_success() {
3594            return Err(Error::Api {
3595                status: status.as_u16(),
3596                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
3597                    .ok()
3598                    .and_then(|r| r.error)
3599                    .unwrap_or(body_text.clone()),
3600            });
3601        }
3602        Ok(serde_json::from_str(&body_text)?)
3603    }
3604
3605    /// Upsert the service query endpoint for a given instance
3606    pub async fn instance_query_endpoint_upsert(
3607        &self,
3608        organization_id: &str,
3609        service_id: &str,
3610        body: &InstanceServiceQueryApiEndpointsPostRequest,
3611    ) -> Result<ApiResponse<ServiceQueryAPIEndpoint>, Error> {
3612        let path = format!(
3613            "/v1/organizations/{organization_id}/services/{service_id}/serviceQueryEndpoint"
3614        );
3615        let mut req = self.request(reqwest::Method::POST, &path);
3616        req = req.json(body);
3617        let resp = req.send().await?;
3618        let status = resp.status();
3619        let body_text = resp.text().await?;
3620        if !status.is_success() {
3621            return Err(Error::Api {
3622                status: status.as_u16(),
3623                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
3624                    .ok()
3625                    .and_then(|r| r.error)
3626                    .unwrap_or(body_text.clone()),
3627            });
3628        }
3629        Ok(serde_json::from_str(&body_text)?)
3630    }
3631
3632    /// Update service state
3633    pub async fn instance_state_update(
3634        &self,
3635        organization_id: &str,
3636        service_id: &str,
3637        body: &ServiceStatePatchRequest,
3638    ) -> Result<ApiResponse<Service>, Error> {
3639        let path = format!("/v1/organizations/{organization_id}/services/{service_id}/state");
3640        let mut req = self.request(reqwest::Method::PATCH, &path);
3641        req = req.json(body);
3642        let resp = req.send().await?;
3643        let status = resp.status();
3644        let body_text = resp.text().await?;
3645        if !status.is_success() {
3646            return Err(Error::Api {
3647                status: status.as_u16(),
3648                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
3649                    .ok()
3650                    .and_then(|r| r.error)
3651                    .unwrap_or(body_text.clone()),
3652            });
3653        }
3654        Ok(serde_json::from_str(&body_text)?)
3655    }
3656
3657    /// Get organization usage costs
3658    pub async fn usage_cost_get(
3659        &self,
3660        organization_id: &str,
3661        from_date: &str,
3662        to_date: &str,
3663        filters: &[&str],
3664    ) -> Result<ApiResponse<UsageCost>, Error> {
3665        let path = format!("/v1/organizations/{organization_id}/usageCost");
3666        let mut req = self.request(reqwest::Method::GET, &path);
3667        req = req.query(&[("from_date", from_date)]);
3668        req = req.query(&[("to_date", to_date)]);
3669        for f in filters {
3670            req = req.query(&[("filter", f)]);
3671        }
3672        let resp = req.send().await?;
3673        let status = resp.status();
3674        let body_text = resp.text().await?;
3675        if !status.is_success() {
3676            return Err(Error::Api {
3677                status: status.as_u16(),
3678                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
3679                    .ok()
3680                    .and_then(|r| r.error)
3681                    .unwrap_or(body_text.clone()),
3682            });
3683        }
3684        Ok(serde_json::from_str(&body_text)?)
3685    }
3686
3687    /// List ClickHouse settings
3688    pub async fn service_clickhouse_settings_list_get(
3689        &self,
3690        organization_id: &str,
3691        service_id: &str,
3692    ) -> Result<ApiResponse<ServiceClickhouseSettingsList>, Error> {
3693        let path =
3694            format!("/v1/organizations/{organization_id}/services/{service_id}/clickhouseSettings");
3695        let req = self.request(reqwest::Method::GET, &path);
3696        let resp = req.send().await?;
3697        let status = resp.status();
3698        let body_text = resp.text().await?;
3699        if !status.is_success() {
3700            return Err(Error::Api {
3701                status: status.as_u16(),
3702                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
3703                    .ok()
3704                    .and_then(|r| r.error)
3705                    .unwrap_or(body_text.clone()),
3706            });
3707        }
3708        Ok(serde_json::from_str(&body_text)?)
3709    }
3710
3711    /// Update ClickHouse settings
3712    pub async fn service_clickhouse_settings_update(
3713        &self,
3714        organization_id: &str,
3715        service_id: &str,
3716        body: &ServiceClickhouseSettingsPatchRequest,
3717    ) -> Result<ApiResponse<ServiceClickhouseSettingsPatchResponse>, Error> {
3718        let path =
3719            format!("/v1/organizations/{organization_id}/services/{service_id}/clickhouseSettings");
3720        let mut req = self.request(reqwest::Method::PATCH, &path);
3721        req = req.json(body);
3722        let resp = req.send().await?;
3723        let status = resp.status();
3724        let body_text = resp.text().await?;
3725        if !status.is_success() {
3726            return Err(Error::Api {
3727                status: status.as_u16(),
3728                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
3729                    .ok()
3730                    .and_then(|r| r.error)
3731                    .unwrap_or(body_text.clone()),
3732            });
3733        }
3734        Ok(serde_json::from_str(&body_text)?)
3735    }
3736
3737    /// Get ClickHouse settings schema
3738    pub async fn service_clickhouse_settings_schema_get(
3739        &self,
3740        organization_id: &str,
3741        service_id: &str,
3742    ) -> Result<ApiResponse<ServiceClickhouseSettingsSchema>, Error> {
3743        let path = format!(
3744            "/v1/organizations/{organization_id}/services/{service_id}/clickhouseSettings/schema"
3745        );
3746        let req = self.request(reqwest::Method::GET, &path);
3747        let resp = req.send().await?;
3748        let status = resp.status();
3749        let body_text = resp.text().await?;
3750        if !status.is_success() {
3751            return Err(Error::Api {
3752                status: status.as_u16(),
3753                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
3754                    .ok()
3755                    .and_then(|r| r.error)
3756                    .unwrap_or(body_text.clone()),
3757            });
3758        }
3759        Ok(serde_json::from_str(&body_text)?)
3760    }
3761
3762    /// Get ClickHouse setting
3763    pub async fn service_clickhouse_setting_get(
3764        &self,
3765        organization_id: &str,
3766        service_id: &str,
3767        setting_name: &str,
3768    ) -> Result<ApiResponse<ServiceClickhouseSetting>, Error> {
3769        let path = format!(
3770            "/v1/organizations/{organization_id}/services/{service_id}/clickhouseSettings/{setting_name}"
3771        );
3772        let req = self.request(reqwest::Method::GET, &path);
3773        let resp = req.send().await?;
3774        let status = resp.status();
3775        let body_text = resp.text().await?;
3776        if !status.is_success() {
3777            return Err(Error::Api {
3778                status: status.as_u16(),
3779                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
3780                    .ok()
3781                    .and_then(|r| r.error)
3782                    .unwrap_or(body_text.clone()),
3783            });
3784        }
3785        Ok(serde_json::from_str(&body_text)?)
3786    }
3787
3788    /// Delete ClickHouse setting
3789    pub async fn service_clickhouse_setting_delete(
3790        &self,
3791        organization_id: &str,
3792        service_id: &str,
3793        setting_name: &str,
3794    ) -> Result<ApiResponse<serde_json::Value>, Error> {
3795        let path = format!(
3796            "/v1/organizations/{organization_id}/services/{service_id}/clickhouseSettings/{setting_name}"
3797        );
3798        let req = self.request(reqwest::Method::DELETE, &path);
3799        let resp = req.send().await?;
3800        let status = resp.status();
3801        let body_text = resp.text().await?;
3802        if !status.is_success() {
3803            return Err(Error::Api {
3804                status: status.as_u16(),
3805                message: serde_json::from_str::<ApiResponse<serde_json::Value>>(&body_text)
3806                    .ok()
3807                    .and_then(|r| r.error)
3808                    .unwrap_or(body_text.clone()),
3809            });
3810        }
3811        Ok(serde_json::from_str(&body_text)?)
3812    }
3813}
3814
3815#[cfg(test)]
3816mod tests {
3817    use super::derive_query_host;
3818
3819    #[test]
3820    fn derive_query_host_prod() {
3821        assert_eq!(
3822            derive_query_host("https://api.clickhouse.cloud").as_deref(),
3823            Some("https://queries.clickhouse.cloud")
3824        );
3825    }
3826
3827    #[test]
3828    fn derive_query_host_staging() {
3829        assert_eq!(
3830            derive_query_host("https://api.control-plane.clickhouse-staging.com").as_deref(),
3831            Some("https://queries.clickhouse-staging.com")
3832        );
3833    }
3834
3835    #[test]
3836    fn derive_query_host_dev() {
3837        assert_eq!(
3838            derive_query_host("https://api.control-plane.clickhouse-dev.com").as_deref(),
3839            Some("https://queries.clickhouse-dev.com")
3840        );
3841    }
3842
3843    #[test]
3844    fn derive_query_host_plain_api_prefix_without_control_plane() {
3845        assert_eq!(
3846            derive_query_host("https://api.clickhouse-staging.com").as_deref(),
3847            Some("https://queries.clickhouse-staging.com")
3848        );
3849    }
3850
3851    #[test]
3852    fn derive_query_host_non_api_host_is_none() {
3853        assert_eq!(derive_query_host("http://127.0.0.1:8123"), None);
3854        assert_eq!(derive_query_host("https://example.com"), None);
3855    }
3856
3857    #[test]
3858    fn derive_query_host_invalid_url_is_none() {
3859        assert_eq!(derive_query_host("not a url"), None);
3860    }
3861
3862    #[test]
3863    fn derive_query_host_preserves_non_default_port() {
3864        assert_eq!(
3865            derive_query_host("https://api.mycorp.example.com:8443").as_deref(),
3866            Some("https://queries.mycorp.example.com:8443")
3867        );
3868        // Default ports are normalized away by the URL parser and stay off
3869        // the derived host.
3870        assert_eq!(
3871            derive_query_host("https://api.clickhouse.cloud:443").as_deref(),
3872            Some("https://queries.clickhouse.cloud")
3873        );
3874    }
3875}