Skip to main content

hanzo_client/apis/
integrations_api.rs

1/*
2 * Hanzo Cloud API
3 *
4 * The Hanzo Cloud API as a customer calls it: every operation under /v1/ except the operator's admin product, relay routes, legacy spellings and capabilities still reached by flag. Tagged by product: the first path segment after /v1/.
5 *
6 * The version of the OpenAPI document: v1
7 * 
8 * Generated by: https://openapi-generator.tech
9 */
10
11
12use reqwest;
13use serde::{Deserialize, Serialize, de::Error as _};
14use crate::{apis::ResponseContent, models};
15use super::{Error, configuration, ContentType};
16
17
18/// struct for typed errors of method [`delete_integrations_connectors_by_id`]
19#[derive(Debug, Clone, Serialize, Deserialize)]
20#[serde(untagged)]
21pub enum DeleteIntegrationsConnectorsByIdError {
22    UnknownValue(serde_json::Value),
23}
24
25/// struct for typed errors of method [`delete_integrations_github_repos_by_repo_pages`]
26#[derive(Debug, Clone, Serialize, Deserialize)]
27#[serde(untagged)]
28pub enum DeleteIntegrationsGithubReposByRepoPagesError {
29    UnknownValue(serde_json::Value),
30}
31
32/// struct for typed errors of method [`get_integrations`]
33#[derive(Debug, Clone, Serialize, Deserialize)]
34#[serde(untagged)]
35pub enum GetIntegrationsError {
36    UnknownValue(serde_json::Value),
37}
38
39/// struct for typed errors of method [`get_integrations_by_provider`]
40#[derive(Debug, Clone, Serialize, Deserialize)]
41#[serde(untagged)]
42pub enum GetIntegrationsByProviderError {
43    UnknownValue(serde_json::Value),
44}
45
46/// struct for typed errors of method [`get_integrations_by_provider_callback`]
47#[derive(Debug, Clone, Serialize, Deserialize)]
48#[serde(untagged)]
49pub enum GetIntegrationsByProviderCallbackError {
50    UnknownValue(serde_json::Value),
51}
52
53/// struct for typed errors of method [`get_integrations_connectors`]
54#[derive(Debug, Clone, Serialize, Deserialize)]
55#[serde(untagged)]
56pub enum GetIntegrationsConnectorsError {
57    UnknownValue(serde_json::Value),
58}
59
60/// struct for typed errors of method [`get_integrations_connectors_by_id_token`]
61#[derive(Debug, Clone, Serialize, Deserialize)]
62#[serde(untagged)]
63pub enum GetIntegrationsConnectorsByIdTokenError {
64    UnknownValue(serde_json::Value),
65}
66
67/// struct for typed errors of method [`get_integrations_connectors_providers`]
68#[derive(Debug, Clone, Serialize, Deserialize)]
69#[serde(untagged)]
70pub enum GetIntegrationsConnectorsProvidersError {
71    UnknownValue(serde_json::Value),
72}
73
74/// struct for typed errors of method [`get_integrations_discord_link`]
75#[derive(Debug, Clone, Serialize, Deserialize)]
76#[serde(untagged)]
77pub enum GetIntegrationsDiscordLinkError {
78    UnknownValue(serde_json::Value),
79}
80
81/// struct for typed errors of method [`get_integrations_discord_link_callback`]
82#[derive(Debug, Clone, Serialize, Deserialize)]
83#[serde(untagged)]
84pub enum GetIntegrationsDiscordLinkCallbackError {
85    UnknownValue(serde_json::Value),
86}
87
88/// struct for typed errors of method [`get_integrations_discord_link_discord`]
89#[derive(Debug, Clone, Serialize, Deserialize)]
90#[serde(untagged)]
91pub enum GetIntegrationsDiscordLinkDiscordError {
92    UnknownValue(serde_json::Value),
93}
94
95/// struct for typed errors of method [`get_integrations_github_installations`]
96#[derive(Debug, Clone, Serialize, Deserialize)]
97#[serde(untagged)]
98pub enum GetIntegrationsGithubInstallationsError {
99    UnknownValue(serde_json::Value),
100}
101
102/// struct for typed errors of method [`get_integrations_github_repos`]
103#[derive(Debug, Clone, Serialize, Deserialize)]
104#[serde(untagged)]
105pub enum GetIntegrationsGithubReposError {
106    UnknownValue(serde_json::Value),
107}
108
109/// struct for typed errors of method [`get_integrations_github_repos_by_repo_pages`]
110#[derive(Debug, Clone, Serialize, Deserialize)]
111#[serde(untagged)]
112pub enum GetIntegrationsGithubReposByRepoPagesError {
113    UnknownValue(serde_json::Value),
114}
115
116/// struct for typed errors of method [`get_integrations_gitlab_projects`]
117#[derive(Debug, Clone, Serialize, Deserialize)]
118#[serde(untagged)]
119pub enum GetIntegrationsGitlabProjectsError {
120    UnknownValue(serde_json::Value),
121}
122
123/// struct for typed errors of method [`get_integrations_slack_install`]
124#[derive(Debug, Clone, Serialize, Deserialize)]
125#[serde(untagged)]
126pub enum GetIntegrationsSlackInstallError {
127    UnknownValue(serde_json::Value),
128}
129
130/// struct for typed errors of method [`get_integrations_slack_link`]
131#[derive(Debug, Clone, Serialize, Deserialize)]
132#[serde(untagged)]
133pub enum GetIntegrationsSlackLinkError {
134    UnknownValue(serde_json::Value),
135}
136
137/// struct for typed errors of method [`get_integrations_slack_link_callback`]
138#[derive(Debug, Clone, Serialize, Deserialize)]
139#[serde(untagged)]
140pub enum GetIntegrationsSlackLinkCallbackError {
141    UnknownValue(serde_json::Value),
142}
143
144/// struct for typed errors of method [`get_integrations_slack_link_slack`]
145#[derive(Debug, Clone, Serialize, Deserialize)]
146#[serde(untagged)]
147pub enum GetIntegrationsSlackLinkSlackError {
148    UnknownValue(serde_json::Value),
149}
150
151/// struct for typed errors of method [`get_integrations_teams_link`]
152#[derive(Debug, Clone, Serialize, Deserialize)]
153#[serde(untagged)]
154pub enum GetIntegrationsTeamsLinkError {
155    UnknownValue(serde_json::Value),
156}
157
158/// struct for typed errors of method [`get_integrations_teams_link_aad`]
159#[derive(Debug, Clone, Serialize, Deserialize)]
160#[serde(untagged)]
161pub enum GetIntegrationsTeamsLinkAadError {
162    UnknownValue(serde_json::Value),
163}
164
165/// struct for typed errors of method [`get_integrations_teams_link_callback`]
166#[derive(Debug, Clone, Serialize, Deserialize)]
167#[serde(untagged)]
168pub enum GetIntegrationsTeamsLinkCallbackError {
169    UnknownValue(serde_json::Value),
170}
171
172/// struct for typed errors of method [`get_integrations_telegram_link`]
173#[derive(Debug, Clone, Serialize, Deserialize)]
174#[serde(untagged)]
175pub enum GetIntegrationsTelegramLinkError {
176    UnknownValue(serde_json::Value),
177}
178
179/// struct for typed errors of method [`get_integrations_telegram_link_auth`]
180#[derive(Debug, Clone, Serialize, Deserialize)]
181#[serde(untagged)]
182pub enum GetIntegrationsTelegramLinkAuthError {
183    UnknownValue(serde_json::Value),
184}
185
186/// struct for typed errors of method [`get_integrations_telegram_link_callback`]
187#[derive(Debug, Clone, Serialize, Deserialize)]
188#[serde(untagged)]
189pub enum GetIntegrationsTelegramLinkCallbackError {
190    UnknownValue(serde_json::Value),
191}
192
193/// struct for typed errors of method [`get_integrations_whatsapp_webhook`]
194#[derive(Debug, Clone, Serialize, Deserialize)]
195#[serde(untagged)]
196pub enum GetIntegrationsWhatsappWebhookError {
197    UnknownValue(serde_json::Value),
198}
199
200/// struct for typed errors of method [`post_integrations_by_provider_connect`]
201#[derive(Debug, Clone, Serialize, Deserialize)]
202#[serde(untagged)]
203pub enum PostIntegrationsByProviderConnectError {
204    UnknownValue(serde_json::Value),
205}
206
207/// struct for typed errors of method [`post_integrations_by_provider_disconnect`]
208#[derive(Debug, Clone, Serialize, Deserialize)]
209#[serde(untagged)]
210pub enum PostIntegrationsByProviderDisconnectError {
211    UnknownValue(serde_json::Value),
212}
213
214/// struct for typed errors of method [`post_integrations_by_provider_verify`]
215#[derive(Debug, Clone, Serialize, Deserialize)]
216#[serde(untagged)]
217pub enum PostIntegrationsByProviderVerifyError {
218    UnknownValue(serde_json::Value),
219}
220
221/// struct for typed errors of method [`post_integrations_connectors_by_id_refresh`]
222#[derive(Debug, Clone, Serialize, Deserialize)]
223#[serde(untagged)]
224pub enum PostIntegrationsConnectorsByIdRefreshError {
225    UnknownValue(serde_json::Value),
226}
227
228/// struct for typed errors of method [`post_integrations_connectors_by_provider_credential`]
229#[derive(Debug, Clone, Serialize, Deserialize)]
230#[serde(untagged)]
231pub enum PostIntegrationsConnectorsByProviderCredentialError {
232    UnknownValue(serde_json::Value),
233}
234
235/// struct for typed errors of method [`post_integrations_connectors_by_provider_device`]
236#[derive(Debug, Clone, Serialize, Deserialize)]
237#[serde(untagged)]
238pub enum PostIntegrationsConnectorsByProviderDeviceError {
239    UnknownValue(serde_json::Value),
240}
241
242/// struct for typed errors of method [`post_integrations_connectors_by_provider_device_by_flow_poll`]
243#[derive(Debug, Clone, Serialize, Deserialize)]
244#[serde(untagged)]
245pub enum PostIntegrationsConnectorsByProviderDeviceByFlowPollError {
246    UnknownValue(serde_json::Value),
247}
248
249/// struct for typed errors of method [`post_integrations_discord_interactions`]
250#[derive(Debug, Clone, Serialize, Deserialize)]
251#[serde(untagged)]
252pub enum PostIntegrationsDiscordInteractionsError {
253    UnknownValue(serde_json::Value),
254}
255
256/// struct for typed errors of method [`post_integrations_github_claim`]
257#[derive(Debug, Clone, Serialize, Deserialize)]
258#[serde(untagged)]
259pub enum PostIntegrationsGithubClaimError {
260    UnknownValue(serde_json::Value),
261}
262
263/// struct for typed errors of method [`post_integrations_github_fork`]
264#[derive(Debug, Clone, Serialize, Deserialize)]
265#[serde(untagged)]
266pub enum PostIntegrationsGithubForkError {
267    UnknownValue(serde_json::Value),
268}
269
270/// struct for typed errors of method [`post_integrations_github_issues_backfill`]
271#[derive(Debug, Clone, Serialize, Deserialize)]
272#[serde(untagged)]
273pub enum PostIntegrationsGithubIssuesBackfillError {
274    UnknownValue(serde_json::Value),
275}
276
277/// struct for typed errors of method [`post_integrations_github_repos_by_repo_pages`]
278#[derive(Debug, Clone, Serialize, Deserialize)]
279#[serde(untagged)]
280pub enum PostIntegrationsGithubReposByRepoPagesError {
281    UnknownValue(serde_json::Value),
282}
283
284/// struct for typed errors of method [`post_integrations_github_repos_by_repo_pages_builds`]
285#[derive(Debug, Clone, Serialize, Deserialize)]
286#[serde(untagged)]
287pub enum PostIntegrationsGithubReposByRepoPagesBuildsError {
288    UnknownValue(serde_json::Value),
289}
290
291/// struct for typed errors of method [`post_integrations_github_repos_import`]
292#[derive(Debug, Clone, Serialize, Deserialize)]
293#[serde(untagged)]
294pub enum PostIntegrationsGithubReposImportError {
295    UnknownValue(serde_json::Value),
296}
297
298/// struct for typed errors of method [`post_integrations_github_search`]
299#[derive(Debug, Clone, Serialize, Deserialize)]
300#[serde(untagged)]
301pub enum PostIntegrationsGithubSearchError {
302    UnknownValue(serde_json::Value),
303}
304
305/// struct for typed errors of method [`post_integrations_github_webhook`]
306#[derive(Debug, Clone, Serialize, Deserialize)]
307#[serde(untagged)]
308pub enum PostIntegrationsGithubWebhookError {
309    UnknownValue(serde_json::Value),
310}
311
312/// struct for typed errors of method [`post_integrations_openrouter_webhook`]
313#[derive(Debug, Clone, Serialize, Deserialize)]
314#[serde(untagged)]
315pub enum PostIntegrationsOpenrouterWebhookError {
316    UnknownValue(serde_json::Value),
317}
318
319/// struct for typed errors of method [`post_integrations_slack_commands`]
320#[derive(Debug, Clone, Serialize, Deserialize)]
321#[serde(untagged)]
322pub enum PostIntegrationsSlackCommandsError {
323    UnknownValue(serde_json::Value),
324}
325
326/// struct for typed errors of method [`post_integrations_slack_events`]
327#[derive(Debug, Clone, Serialize, Deserialize)]
328#[serde(untagged)]
329pub enum PostIntegrationsSlackEventsError {
330    UnknownValue(serde_json::Value),
331}
332
333/// struct for typed errors of method [`post_integrations_teams_events`]
334#[derive(Debug, Clone, Serialize, Deserialize)]
335#[serde(untagged)]
336pub enum PostIntegrationsTeamsEventsError {
337    UnknownValue(serde_json::Value),
338}
339
340/// struct for typed errors of method [`post_integrations_telegram_connect`]
341#[derive(Debug, Clone, Serialize, Deserialize)]
342#[serde(untagged)]
343pub enum PostIntegrationsTelegramConnectError {
344    UnknownValue(serde_json::Value),
345}
346
347/// struct for typed errors of method [`post_integrations_telegram_webhook`]
348#[derive(Debug, Clone, Serialize, Deserialize)]
349#[serde(untagged)]
350pub enum PostIntegrationsTelegramWebhookError {
351    UnknownValue(serde_json::Value),
352}
353
354/// struct for typed errors of method [`post_integrations_whatsapp_webhook`]
355#[derive(Debug, Clone, Serialize, Deserialize)]
356#[serde(untagged)]
357pub enum PostIntegrationsWhatsappWebhookError {
358    UnknownValue(serde_json::Value),
359}
360
361/// struct for typed errors of method [`put_integrations_github_repos_by_repo_pages`]
362#[derive(Debug, Clone, Serialize, Deserialize)]
363#[serde(untagged)]
364pub enum PutIntegrationsGithubReposByRepoPagesError {
365    UnknownValue(serde_json::Value),
366}
367
368
369/// Forgets a connector: every custodied secret, then the row. Idempotent — dropping a never-connected id still answers {disconnected:true} (disconnect() parity). No provider Revoke: none of the user-plane providers exposes a revoke endpoint.
370pub async fn delete_integrations_connectors_by_id(configuration: &configuration::Configuration, id: &str) -> Result<models::DisconnectOut, Error<DeleteIntegrationsConnectorsByIdError>> {
371    // add a prefix to parameters to efficiently prevent name collisions
372    let p_id = id;
373
374    let uri_str = format!("{}/v1/integrations/connectors/{id}", configuration.base_path, id=crate::apis::urlencode(p_id));
375    let mut req_builder = configuration.client.request(reqwest::Method::DELETE, &uri_str);
376
377    if let Some(ref user_agent) = configuration.user_agent {
378        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
379    }
380    if let Some(ref token) = configuration.bearer_access_token {
381        req_builder = req_builder.bearer_auth(token.to_owned());
382    };
383
384    let req = req_builder.build()?;
385    let resp = configuration.client.execute(req).await?;
386
387    let status = resp.status();
388    let content_type = resp
389        .headers()
390        .get("content-type")
391        .and_then(|v| v.to_str().ok())
392        .unwrap_or("application/octet-stream");
393    let content_type = super::ContentType::from(content_type);
394
395    if !status.is_client_error() && !status.is_server_error() {
396        let content = resp.text().await?;
397        match content_type {
398            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
399            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::DisconnectOut`"))),
400            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::DisconnectOut`")))),
401        }
402    } else {
403        let content = resp.text().await?;
404        let entity: Option<DeleteIntegrationsConnectorsByIdError> = serde_json::from_str(&content).ok();
405        Err(Error::ResponseError(ResponseContent { status, content, entity }))
406    }
407}
408
409/// Deletes the repo's Pages site. 404 when there is none, so a caller can tell \"turned it off\" from \"there was nothing on\".
410pub async fn delete_integrations_github_repos_by_repo_pages(configuration: &configuration::Configuration, repo: &str) -> Result<models::GithubPagesDisabledOut, Error<DeleteIntegrationsGithubReposByRepoPagesError>> {
411    // add a prefix to parameters to efficiently prevent name collisions
412    let p_repo = repo;
413
414    let uri_str = format!("{}/v1/integrations/github/repos/{repo}/pages", configuration.base_path, repo=crate::apis::urlencode(p_repo));
415    let mut req_builder = configuration.client.request(reqwest::Method::DELETE, &uri_str);
416
417    if let Some(ref user_agent) = configuration.user_agent {
418        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
419    }
420    if let Some(ref token) = configuration.bearer_access_token {
421        req_builder = req_builder.bearer_auth(token.to_owned());
422    };
423
424    let req = req_builder.build()?;
425    let resp = configuration.client.execute(req).await?;
426
427    let status = resp.status();
428    let content_type = resp
429        .headers()
430        .get("content-type")
431        .and_then(|v| v.to_str().ok())
432        .unwrap_or("application/octet-stream");
433    let content_type = super::ContentType::from(content_type);
434
435    if !status.is_client_error() && !status.is_server_error() {
436        let content = resp.text().await?;
437        match content_type {
438            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
439            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::GithubPagesDisabledOut`"))),
440            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::GithubPagesDisabledOut`")))),
441        }
442    } else {
443        let content = resp.text().await?;
444        let entity: Option<DeleteIntegrationsGithubReposByRepoPagesError> = serde_json::from_str(&content).ok();
445        Err(Error::ResponseError(ResponseContent { status, content, entity }))
446    }
447}
448
449/// Returns every registered integration provider together with THIS org's connection status for it — the catalog the console's Integrations page renders. Org-authed: a caller with no validated principal is 403, because the status is per-org and there is no org-less answer. User-plane providers (the /v1/integrations/connectors surface) are omitted; the two planes are disjoint.
450pub async fn get_integrations(configuration: &configuration::Configuration, ) -> Result<models::ListOut, Error<GetIntegrationsError>> {
451
452    let uri_str = format!("{}/v1/integrations", configuration.base_path);
453    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
454
455    if let Some(ref user_agent) = configuration.user_agent {
456        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
457    }
458    if let Some(ref token) = configuration.bearer_access_token {
459        req_builder = req_builder.bearer_auth(token.to_owned());
460    };
461
462    let req = req_builder.build()?;
463    let resp = configuration.client.execute(req).await?;
464
465    let status = resp.status();
466    let content_type = resp
467        .headers()
468        .get("content-type")
469        .and_then(|v| v.to_str().ok())
470        .unwrap_or("application/octet-stream");
471    let content_type = super::ContentType::from(content_type);
472
473    if !status.is_client_error() && !status.is_server_error() {
474        let content = resp.text().await?;
475        match content_type {
476            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
477            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::ListOut`"))),
478            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::ListOut`")))),
479        }
480    } else {
481        let content = resp.text().await?;
482        let entity: Option<GetIntegrationsError> = serde_json::from_str(&content).ok();
483        Err(Error::ResponseError(ResponseContent { status, content, entity }))
484    }
485}
486
487/// Returns ONE provider with this org's connection status — the same view list carries, for a single id. An unknown id is 404, and so is a user-plane provider: the org surface never resolves one.
488pub async fn get_integrations_by_provider(configuration: &configuration::Configuration, provider: &str) -> Result<models::ProviderView, Error<GetIntegrationsByProviderError>> {
489    // add a prefix to parameters to efficiently prevent name collisions
490    let p_provider = provider;
491
492    let uri_str = format!("{}/v1/integrations/{provider}", configuration.base_path, provider=crate::apis::urlencode(p_provider));
493    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
494
495    if let Some(ref user_agent) = configuration.user_agent {
496        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
497    }
498    if let Some(ref token) = configuration.bearer_access_token {
499        req_builder = req_builder.bearer_auth(token.to_owned());
500    };
501
502    let req = req_builder.build()?;
503    let resp = configuration.client.execute(req).await?;
504
505    let status = resp.status();
506    let content_type = resp
507        .headers()
508        .get("content-type")
509        .and_then(|v| v.to_str().ok())
510        .unwrap_or("application/octet-stream");
511    let content_type = super::ContentType::from(content_type);
512
513    if !status.is_client_error() && !status.is_server_error() {
514        let content = resp.text().await?;
515        match content_type {
516            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
517            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::ProviderView`"))),
518            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::ProviderView`")))),
519        }
520    } else {
521        let content = resp.text().await?;
522        let entity: Option<GetIntegrationsByProviderError> = serde_json::from_str(&content).ok();
523        Err(Error::ResponseError(ResponseContent { status, content, entity }))
524    }
525}
526
527/// The single address every connector's OAuth flow returns to. It exchanges the authorization the provider granted, records the connection, and ALWAYS redirects the browser back to the console — on success and on every labeled failure alike, so a user never lands on a raw JSON dead end.  It is public and carries no principal, so the org is taken ONLY from the signed state minted when the flow began; no header is trusted here. That state is single-use and is burned BEFORE the exchange, so one authorization is one attempt and a replayed return fails instead of exchanging twice.  Tokens are sealed into the org's KMS namespace BEFORE the connection row is written, so a failure of the secret store leaves no half-connected integration advertising a credential that was never stored. Token values never appear in the redirect, in a log line or in an error.  One generalization is worth knowing: a GitHub App installation returns an installation identifier instead of an OAuth code, and it is accepted in the code's place so the App model needs no second address.
528pub async fn get_integrations_by_provider_callback(configuration: &configuration::Configuration, provider: &str) -> Result<(), Error<GetIntegrationsByProviderCallbackError>> {
529    // add a prefix to parameters to efficiently prevent name collisions
530    let p_provider = provider;
531
532    let uri_str = format!("{}/v1/integrations/{provider}/callback", configuration.base_path, provider=crate::apis::urlencode(p_provider));
533    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
534
535    if let Some(ref user_agent) = configuration.user_agent {
536        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
537    }
538    if let Some(ref token) = configuration.bearer_access_token {
539        req_builder = req_builder.bearer_auth(token.to_owned());
540    };
541
542    let req = req_builder.build()?;
543    let resp = configuration.client.execute(req).await?;
544
545    let status = resp.status();
546
547    if !status.is_client_error() && !status.is_server_error() {
548        Ok(())
549    } else {
550        let content = resp.text().await?;
551        let entity: Option<GetIntegrationsByProviderCallbackError> = serde_json::from_str(&content).ok();
552        Err(Error::ResponseError(ResponseContent { status, content, entity }))
553    }
554}
555
556/// Lists the caller's OWN connectors across every provider — the set `hanzo connector ls` prints. Rows are keyed (org,user), so this can never surface another user's connector, and no secret is in the view.
557pub async fn get_integrations_connectors(configuration: &configuration::Configuration, ) -> Result<models::ConnectorsOut, Error<GetIntegrationsConnectorsError>> {
558
559    let uri_str = format!("{}/v1/integrations/connectors", configuration.base_path);
560    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
561
562    if let Some(ref user_agent) = configuration.user_agent {
563        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
564    }
565    if let Some(ref token) = configuration.bearer_access_token {
566        req_builder = req_builder.bearer_auth(token.to_owned());
567    };
568
569    let req = req_builder.build()?;
570    let resp = configuration.client.execute(req).await?;
571
572    let status = resp.status();
573    let content_type = resp
574        .headers()
575        .get("content-type")
576        .and_then(|v| v.to_str().ok())
577        .unwrap_or("application/octet-stream");
578    let content_type = super::ContentType::from(content_type);
579
580    if !status.is_client_error() && !status.is_server_error() {
581        let content = resp.text().await?;
582        match content_type {
583            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
584            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::ConnectorsOut`"))),
585            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::ConnectorsOut`")))),
586        }
587    } else {
588        let content = resp.text().await?;
589        let entity: Option<GetIntegrationsConnectorsError> = serde_json::from_str(&content).ok();
590        Err(Error::ResponseError(ResponseContent { status, content, entity }))
591    }
592}
593
594/// Hands the custodied access token to its owner — the ONE place custody exits. The (org,user)-keyed row IS the same-user gate: another user's id is simply \"no row\" → 404. fresh() auto-rotates within the refreshSkew window; static providers degenerate to a plain kmsGet of Secrets[0]. Refresh tokens are NEVER returned — custody keeps the sink. The token is never logged.
595pub async fn get_integrations_connectors_by_id_token(configuration: &configuration::Configuration, id: &str) -> Result<models::ConnectorTokenOut, Error<GetIntegrationsConnectorsByIdTokenError>> {
596    // add a prefix to parameters to efficiently prevent name collisions
597    let p_id = id;
598
599    let uri_str = format!("{}/v1/integrations/connectors/{id}/token", configuration.base_path, id=crate::apis::urlencode(p_id));
600    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
601
602    if let Some(ref user_agent) = configuration.user_agent {
603        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
604    }
605    if let Some(ref token) = configuration.bearer_access_token {
606        req_builder = req_builder.bearer_auth(token.to_owned());
607    };
608
609    let req = req_builder.build()?;
610    let resp = configuration.client.execute(req).await?;
611
612    let status = resp.status();
613    let content_type = resp
614        .headers()
615        .get("content-type")
616        .and_then(|v| v.to_str().ok())
617        .unwrap_or("application/octet-stream");
618    let content_type = super::ContentType::from(content_type);
619
620    if !status.is_client_error() && !status.is_server_error() {
621        let content = resp.text().await?;
622        match content_type {
623            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
624            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::ConnectorTokenOut`"))),
625            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::ConnectorTokenOut`")))),
626        }
627    } else {
628        let content = resp.text().await?;
629        let entity: Option<GetIntegrationsConnectorsByIdTokenError> = serde_json::from_str(&content).ok();
630        Err(Error::ResponseError(ResponseContent { status, content, entity }))
631    }
632}
633
634/// Lists the user-scoped provider cards — the catalog of what a user can connect, and how. Methods derive from capabilities (Device/Adopt/Verify — Mount asserts at least one), never from a parallel kind enum.
635pub async fn get_integrations_connectors_providers(configuration: &configuration::Configuration, ) -> Result<models::ConnectorProvidersOut, Error<GetIntegrationsConnectorsProvidersError>> {
636
637    let uri_str = format!("{}/v1/integrations/connectors/providers", configuration.base_path);
638    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
639
640    if let Some(ref user_agent) = configuration.user_agent {
641        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
642    }
643    if let Some(ref token) = configuration.bearer_access_token {
644        req_builder = req_builder.bearer_auth(token.to_owned());
645    };
646
647    let req = req_builder.build()?;
648    let resp = configuration.client.execute(req).await?;
649
650    let status = resp.status();
651    let content_type = resp
652        .headers()
653        .get("content-type")
654        .and_then(|v| v.to_str().ok())
655        .unwrap_or("application/octet-stream");
656    let content_type = super::ContentType::from(content_type);
657
658    if !status.is_client_error() && !status.is_server_error() {
659        let content = resp.text().await?;
660        match content_type {
661            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
662            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::ConnectorProvidersOut`"))),
663            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::ConnectorProvidersOut`")))),
664        }
665    } else {
666        let content = resp.text().await?;
667        let entity: Option<GetIntegrationsConnectorsProvidersError> = serde_json::from_str(&content).ok();
668        Err(Error::ResponseError(ResponseContent { status, content, entity }))
669    }
670}
671
672/// The entry point behind the connect prompt Hanzo shows in a Discord server. It starts a link session and redirects to Discord's OAuth `identify` consent — the narrowest scope that establishes which Discord user is asking, and nothing more.  This is one leg of a three-leg flow, and the legs are not interchangeable: a browser is expected to arrive here only from the leg before it. The link URL's state proves the prompt was server-minted and carries the CHAT it started from — it is provenance only, and it never decides which account gets linked. The account identity always comes from the platform's own verified sign-in and a host-bound cookie, so forwarding a link to someone else cannot bind their account, and a session lifted into another browser is refused rather than completed. Each link is single-use, and a deployment without linking configured answers 503.
673pub async fn get_integrations_discord_link(configuration: &configuration::Configuration, ) -> Result<(), Error<GetIntegrationsDiscordLinkError>> {
674
675    let uri_str = format!("{}/v1/integrations/discord/link", configuration.base_path);
676    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
677
678    if let Some(ref user_agent) = configuration.user_agent {
679        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
680    }
681    if let Some(ref token) = configuration.bearer_access_token {
682        req_builder = req_builder.bearer_auth(token.to_owned());
683    };
684
685    let req = req_builder.build()?;
686    let resp = configuration.client.execute(req).await?;
687
688    let status = resp.status();
689
690    if !status.is_client_error() && !status.is_server_error() {
691        Ok(())
692    } else {
693        let content = resp.text().await?;
694        let entity: Option<GetIntegrationsDiscordLinkError> = serde_json::from_str(&content).ok();
695        Err(Error::ResponseError(ResponseContent { status, content, entity }))
696    }
697}
698
699/// The final leg: it binds the verified Discord user to the Hanzo account that just signed in, and answers a short confirmation page telling them to return to Discord. The Hanzo credential is sealed into the connected org's KMS namespace rather than stored beside the link.  This is one leg of a three-leg flow, and the legs are not interchangeable: a browser is expected to arrive here only from the leg before it. The link URL's state proves the prompt was server-minted and carries the CHAT it started from — it is provenance only, and it never decides which account gets linked. The account identity always comes from the platform's own verified sign-in and a host-bound cookie, so forwarding a link to someone else cannot bind their account, and a session lifted into another browser is refused rather than completed. Each link is single-use, and a deployment without linking configured answers 503.
700pub async fn get_integrations_discord_link_callback(configuration: &configuration::Configuration, ) -> Result<(), Error<GetIntegrationsDiscordLinkCallbackError>> {
701
702    let uri_str = format!("{}/v1/integrations/discord/link/callback", configuration.base_path);
703    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
704
705    if let Some(ref user_agent) = configuration.user_agent {
706        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
707    }
708    if let Some(ref token) = configuration.bearer_access_token {
709        req_builder = req_builder.bearer_auth(token.to_owned());
710    };
711
712    let req = req_builder.build()?;
713    let resp = configuration.client.execute(req).await?;
714
715    let status = resp.status();
716
717    if !status.is_client_error() && !status.is_server_error() {
718        Ok(())
719    } else {
720        let content = resp.text().await?;
721        let entity: Option<GetIntegrationsDiscordLinkCallbackError> = serde_json::from_str(&content).ok();
722        Err(Error::ResponseError(ResponseContent { status, content, entity }))
723    }
724}
725
726/// Where Discord returns the user after the identify consent. It resolves the verified Discord user, confirms the server is connected to an org, and hands the browser to the Hanzo sign-in that completes the link.  This is one leg of a three-leg flow, and the legs are not interchangeable: a browser is expected to arrive here only from the leg before it. The link URL's state proves the prompt was server-minted and carries the CHAT it started from — it is provenance only, and it never decides which account gets linked. The account identity always comes from the platform's own verified sign-in and a host-bound cookie, so forwarding a link to someone else cannot bind their account, and a session lifted into another browser is refused rather than completed. Each link is single-use, and a deployment without linking configured answers 503.
727pub async fn get_integrations_discord_link_discord(configuration: &configuration::Configuration, ) -> Result<(), Error<GetIntegrationsDiscordLinkDiscordError>> {
728
729    let uri_str = format!("{}/v1/integrations/discord/link/discord", configuration.base_path);
730    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
731
732    if let Some(ref user_agent) = configuration.user_agent {
733        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
734    }
735    if let Some(ref token) = configuration.bearer_access_token {
736        req_builder = req_builder.bearer_auth(token.to_owned());
737    };
738
739    let req = req_builder.build()?;
740    let resp = configuration.client.execute(req).await?;
741
742    let status = resp.status();
743
744    if !status.is_client_error() && !status.is_server_error() {
745        Ok(())
746    } else {
747        let content = resp.text().await?;
748        let entity: Option<GetIntegrationsDiscordLinkDiscordError> = serde_json::from_str(&content).ok();
749        Err(Error::ResponseError(ResponseContent { status, content, entity }))
750    }
751}
752
753/// Lists the GitHub accounts the caller may see the App installed on, each confirmed against the App's own list, plus where to add another.  The confirmation is the point. A connection row holds an installation id, and an id whose installation was since removed on GitHub is a row that mints nothing — every list and import against it fails with a token error, which reads as \"our git integration is broken\" rather than \"that install is gone\". Checking the App's view turns that into a fact the caller can act on.  ORG-SCOPED for a tenant, deliberately. The App is installed across every customer, so the raw list is the customer list; a tenant sees only accounts its own org has bound. It discovers a NEW account by installing it (InstallURL), which is GitHub's own consent screen — not by reading ours.  A SUPER ADMIN sees the App's whole install list, because that list is the platform's own inventory rather than any one tenant's data, and platform sudo is the single cross-tenant scope this house has. Without it an App installed out-of-band — granted straight from GitHub, so no connect flow ever ran and no connection row exists — is invisible to everyone: the console card reads \"not connected\" and an operator asked \"which GitHub orgs do you see\" can only answer for accounts already bound, which is precisely the accounts that were never the question.
754pub async fn get_integrations_github_installations(configuration: &configuration::Configuration, ) -> Result<models::GithubInstallationsOut, Error<GetIntegrationsGithubInstallationsError>> {
755
756    let uri_str = format!("{}/v1/integrations/github/installations", configuration.base_path);
757    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
758
759    if let Some(ref user_agent) = configuration.user_agent {
760        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
761    }
762    if let Some(ref token) = configuration.bearer_access_token {
763        req_builder = req_builder.bearer_auth(token.to_owned());
764    };
765
766    let req = req_builder.build()?;
767    let resp = configuration.client.execute(req).await?;
768
769    let status = resp.status();
770    let content_type = resp
771        .headers()
772        .get("content-type")
773        .and_then(|v| v.to_str().ok())
774        .unwrap_or("application/octet-stream");
775    let content_type = super::ContentType::from(content_type);
776
777    if !status.is_client_error() && !status.is_server_error() {
778        let content = resp.text().await?;
779        match content_type {
780            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
781            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::GithubInstallationsOut`"))),
782            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::GithubInstallationsOut`")))),
783        }
784    } else {
785        let content = resp.text().await?;
786        let entity: Option<GetIntegrationsGithubInstallationsError> = serde_json::from_str(&content).ok();
787        Err(Error::ResponseError(ResponseContent { status, content, entity }))
788    }
789}
790
791/// Lists the org's granted GitHub repositories, each annotated with its native import + sync status from the git object plane. Org-authed: the org comes from the validated principal, and the granted set is bounded to THAT org's installation token — an org can never enumerate another org's repos. The console polls it to watch an import flip a repo to imported.
792pub async fn get_integrations_github_repos(configuration: &configuration::Configuration, ) -> Result<models::GithubReposOut, Error<GetIntegrationsGithubReposError>> {
793
794    let uri_str = format!("{}/v1/integrations/github/repos", configuration.base_path);
795    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
796
797    if let Some(ref user_agent) = configuration.user_agent {
798        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
799    }
800    if let Some(ref token) = configuration.bearer_access_token {
801        req_builder = req_builder.bearer_auth(token.to_owned());
802    };
803
804    let req = req_builder.build()?;
805    let resp = configuration.client.execute(req).await?;
806
807    let status = resp.status();
808    let content_type = resp
809        .headers()
810        .get("content-type")
811        .and_then(|v| v.to_str().ok())
812        .unwrap_or("application/octet-stream");
813    let content_type = super::ContentType::from(content_type);
814
815    if !status.is_client_error() && !status.is_server_error() {
816        let content = resp.text().await?;
817        match content_type {
818            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
819            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::GithubReposOut`"))),
820            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::GithubReposOut`")))),
821        }
822    } else {
823        let content = resp.text().await?;
824        let entity: Option<GetIntegrationsGithubReposError> = serde_json::from_str(&content).ok();
825        Err(Error::ResponseError(ResponseContent { status, content, entity }))
826    }
827}
828
829/// Returns the repo's Pages status, live URL, custom domain and build source. The repo is resolved against the org installation's GRANTED set, so a caller can never address a repo the App was not granted; 404 when the repo has no Pages site.
830pub async fn get_integrations_github_repos_by_repo_pages(configuration: &configuration::Configuration, repo: &str) -> Result<models::GithubPagesView, Error<GetIntegrationsGithubReposByRepoPagesError>> {
831    // add a prefix to parameters to efficiently prevent name collisions
832    let p_repo = repo;
833
834    let uri_str = format!("{}/v1/integrations/github/repos/{repo}/pages", configuration.base_path, repo=crate::apis::urlencode(p_repo));
835    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
836
837    if let Some(ref user_agent) = configuration.user_agent {
838        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
839    }
840    if let Some(ref token) = configuration.bearer_access_token {
841        req_builder = req_builder.bearer_auth(token.to_owned());
842    };
843
844    let req = req_builder.build()?;
845    let resp = configuration.client.execute(req).await?;
846
847    let status = resp.status();
848    let content_type = resp
849        .headers()
850        .get("content-type")
851        .and_then(|v| v.to_str().ok())
852        .unwrap_or("application/octet-stream");
853    let content_type = super::ContentType::from(content_type);
854
855    if !status.is_client_error() && !status.is_server_error() {
856        let content = resp.text().await?;
857        match content_type {
858            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
859            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::GithubPagesView`"))),
860            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::GithubPagesView`")))),
861        }
862    } else {
863        let content = resp.text().await?;
864        let entity: Option<GetIntegrationsGithubReposByRepoPagesError> = serde_json::from_str(&content).ok();
865        Err(Error::ResponseError(ResponseContent { status, content, entity }))
866    }
867}
868
869/// Lists the projects the org's GitLab connection can reach — membership projects, most recently active first.
870pub async fn get_integrations_gitlab_projects(configuration: &configuration::Configuration, ) -> Result<models::GitlabProjectsOut, Error<GetIntegrationsGitlabProjectsError>> {
871
872    let uri_str = format!("{}/v1/integrations/gitlab/projects", configuration.base_path);
873    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
874
875    if let Some(ref user_agent) = configuration.user_agent {
876        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
877    }
878    if let Some(ref token) = configuration.bearer_access_token {
879        req_builder = req_builder.bearer_auth(token.to_owned());
880    };
881
882    let req = req_builder.build()?;
883    let resp = configuration.client.execute(req).await?;
884
885    let status = resp.status();
886    let content_type = resp
887        .headers()
888        .get("content-type")
889        .and_then(|v| v.to_str().ok())
890        .unwrap_or("application/octet-stream");
891    let content_type = super::ContentType::from(content_type);
892
893    if !status.is_client_error() && !status.is_server_error() {
894        let content = resp.text().await?;
895        match content_type {
896            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
897            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::GitlabProjectsOut`"))),
898            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::GitlabProjectsOut`")))),
899        }
900    } else {
901        let content = resp.text().await?;
902        let entity: Option<GetIntegrationsGitlabProjectsError> = serde_json::from_str(&content).ok();
903        Err(Error::ResponseError(ResponseContent { status, content, entity }))
904    }
905}
906
907/// The address behind Slack's \"Add to Slack\" and Marketplace Install buttons. It answers a 302 to Slack's own consent screen and does nothing else — it is a redirector by design.  It exists because Slack refuses a slack.com URL in that field and requires one of ours that redirects there, which makes the field an ATTRIBUTION hook: routing the click through our own address is what lets an install be counted, and always answering the redirect is what keeps the counter from becoming a detour that never reaches consent. The destination is the same consent URL every time, built from the same scopes the console's Connect button asks for, so a workspace is asked to grant one thing however the install began.  It is PUBLIC and carries no principal, because whoever clicks Install in Slack's directory has no Hanzo session yet. It binds no org either, and that is deliberate rather than missing: the org is resolved at the shared provider callback, from the signed state a console connect minted or from the workspace's existing connection. Minting an org for an anonymous click is the one thing that would break tenant isolation, so an install begun here finishes under exactly the rules every other install obeys.  Where the app is not configured it answers 503, rather than a consent URL carrying an empty client_id that Slack would render as its own dead-end error page.
908pub async fn get_integrations_slack_install(configuration: &configuration::Configuration, ) -> Result<(), Error<GetIntegrationsSlackInstallError>> {
909
910    let uri_str = format!("{}/v1/integrations/slack/install", configuration.base_path);
911    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
912
913    if let Some(ref user_agent) = configuration.user_agent {
914        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
915    }
916    if let Some(ref token) = configuration.bearer_access_token {
917        req_builder = req_builder.bearer_auth(token.to_owned());
918    };
919
920    let req = req_builder.build()?;
921    let resp = configuration.client.execute(req).await?;
922
923    let status = resp.status();
924
925    if !status.is_client_error() && !status.is_server_error() {
926        Ok(())
927    } else {
928        let content = resp.text().await?;
929        let entity: Option<GetIntegrationsSlackInstallError> = serde_json::from_str(&content).ok();
930        Err(Error::ResponseError(ResponseContent { status, content, entity }))
931    }
932}
933
934/// The entry point behind the connect prompt Hanzo posts in Slack. It starts a link session in the browser and redirects to Slack's own sign-in, which is what proves which Slack user is asking.  This is one leg of a three-leg flow, and the legs are not interchangeable: a browser is expected to arrive here only from the leg before it. The link URL's state proves the prompt was server-minted and carries the CHAT it started from — it is provenance only, and it never decides which account gets linked. The account identity always comes from the platform's own verified sign-in and a host-bound cookie, so forwarding a link to someone else cannot bind their account, and a session lifted into another browser is refused rather than completed. Each link is single-use, and a deployment without linking configured answers 503.
935pub async fn get_integrations_slack_link(configuration: &configuration::Configuration, ) -> Result<(), Error<GetIntegrationsSlackLinkError>> {
936
937    let uri_str = format!("{}/v1/integrations/slack/link", configuration.base_path);
938    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
939
940    if let Some(ref user_agent) = configuration.user_agent {
941        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
942    }
943    if let Some(ref token) = configuration.bearer_access_token {
944        req_builder = req_builder.bearer_auth(token.to_owned());
945    };
946
947    let req = req_builder.build()?;
948    let resp = configuration.client.execute(req).await?;
949
950    let status = resp.status();
951
952    if !status.is_client_error() && !status.is_server_error() {
953        Ok(())
954    } else {
955        let content = resp.text().await?;
956        let entity: Option<GetIntegrationsSlackLinkError> = serde_json::from_str(&content).ok();
957        Err(Error::ResponseError(ResponseContent { status, content, entity }))
958    }
959}
960
961/// The final leg: the user has proved both who they are in Slack and who they are in Hanzo, and this binds the two. It answers a short confirmation page telling them to return to Slack.  The Hanzo credential obtained here is sealed into the connected workspace's own KMS namespace; it is never written to a database column and never logged. A deployment whose secret store is unavailable refuses the link rather than completing it without custody of the credential.  This is one leg of a three-leg flow, and the legs are not interchangeable: a browser is expected to arrive here only from the leg before it. The link URL's state proves the prompt was server-minted and carries the CHAT it started from — it is provenance only, and it never decides which account gets linked. The account identity always comes from the platform's own verified sign-in and a host-bound cookie, so forwarding a link to someone else cannot bind their account, and a session lifted into another browser is refused rather than completed. Each link is single-use, and a deployment without linking configured answers 503.
962pub async fn get_integrations_slack_link_callback(configuration: &configuration::Configuration, ) -> Result<(), Error<GetIntegrationsSlackLinkCallbackError>> {
963
964    let uri_str = format!("{}/v1/integrations/slack/link/callback", configuration.base_path);
965    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
966
967    if let Some(ref user_agent) = configuration.user_agent {
968        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
969    }
970    if let Some(ref token) = configuration.bearer_access_token {
971        req_builder = req_builder.bearer_auth(token.to_owned());
972    };
973
974    let req = req_builder.build()?;
975    let resp = configuration.client.execute(req).await?;
976
977    let status = resp.status();
978
979    if !status.is_client_error() && !status.is_server_error() {
980        Ok(())
981    } else {
982        let content = resp.text().await?;
983        let entity: Option<GetIntegrationsSlackLinkCallbackError> = serde_json::from_str(&content).ok();
984        Err(Error::ResponseError(ResponseContent { status, content, entity }))
985    }
986}
987
988/// Where Slack returns the user after they sign in. It establishes the verified Slack workspace and user, confirms that workspace is connected to an org, and hands the browser on to the Hanzo sign-in that completes the link.  The verified pair is carried onward in a host-bound cookie rather than in the URL, so the identity being linked cannot be edited in transit.  This is one leg of a three-leg flow, and the legs are not interchangeable: a browser is expected to arrive here only from the leg before it. The link URL's state proves the prompt was server-minted and carries the CHAT it started from — it is provenance only, and it never decides which account gets linked. The account identity always comes from the platform's own verified sign-in and a host-bound cookie, so forwarding a link to someone else cannot bind their account, and a session lifted into another browser is refused rather than completed. Each link is single-use, and a deployment without linking configured answers 503.
989pub async fn get_integrations_slack_link_slack(configuration: &configuration::Configuration, ) -> Result<(), Error<GetIntegrationsSlackLinkSlackError>> {
990
991    let uri_str = format!("{}/v1/integrations/slack/link/slack", configuration.base_path);
992    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
993
994    if let Some(ref user_agent) = configuration.user_agent {
995        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
996    }
997    if let Some(ref token) = configuration.bearer_access_token {
998        req_builder = req_builder.bearer_auth(token.to_owned());
999    };
1000
1001    let req = req_builder.build()?;
1002    let resp = configuration.client.execute(req).await?;
1003
1004    let status = resp.status();
1005
1006    if !status.is_client_error() && !status.is_server_error() {
1007        Ok(())
1008    } else {
1009        let content = resp.text().await?;
1010        let entity: Option<GetIntegrationsSlackLinkSlackError> = serde_json::from_str(&content).ok();
1011        Err(Error::ResponseError(ResponseContent { status, content, entity }))
1012    }
1013}
1014
1015/// The entry point behind the connect prompt Hanzo shows in Teams. It starts a link session and redirects to Microsoft sign-in addressed to the CHAT'S OWN tenant, not the common endpoint, so only a member of that tenant can complete it.  This is one leg of a three-leg flow, and the legs are not interchangeable: a browser is expected to arrive here only from the leg before it. The link URL's state proves the prompt was server-minted and carries the CHAT it started from — it is provenance only, and it never decides which account gets linked. The account identity always comes from the platform's own verified sign-in and a host-bound cookie, so forwarding a link to someone else cannot bind their account, and a session lifted into another browser is refused rather than completed. Each link is single-use, and a deployment without linking configured answers 503.
1016pub async fn get_integrations_teams_link(configuration: &configuration::Configuration, ) -> Result<(), Error<GetIntegrationsTeamsLinkError>> {
1017
1018    let uri_str = format!("{}/v1/integrations/teams/link", configuration.base_path);
1019    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
1020
1021    if let Some(ref user_agent) = configuration.user_agent {
1022        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
1023    }
1024    if let Some(ref token) = configuration.bearer_access_token {
1025        req_builder = req_builder.bearer_auth(token.to_owned());
1026    };
1027
1028    let req = req_builder.build()?;
1029    let resp = configuration.client.execute(req).await?;
1030
1031    let status = resp.status();
1032
1033    if !status.is_client_error() && !status.is_server_error() {
1034        Ok(())
1035    } else {
1036        let content = resp.text().await?;
1037        let entity: Option<GetIntegrationsTeamsLinkError> = serde_json::from_str(&content).ok();
1038        Err(Error::ResponseError(ResponseContent { status, content, entity }))
1039    }
1040}
1041
1042/// Where Microsoft returns the user after sign-in. It resolves the verified directory identity and then re-checks the tenant: the signed-in user's tenant must equal the tenant of the chat the link started from, so a valid Microsoft sign-in from a different organization is refused here rather than accepted.  This is the leg Teams has and the other platforms do not, which is why the Teams flow has an extra address.  This is one leg of a three-leg flow, and the legs are not interchangeable: a browser is expected to arrive here only from the leg before it. The link URL's state proves the prompt was server-minted and carries the CHAT it started from — it is provenance only, and it never decides which account gets linked. The account identity always comes from the platform's own verified sign-in and a host-bound cookie, so forwarding a link to someone else cannot bind their account, and a session lifted into another browser is refused rather than completed. Each link is single-use, and a deployment without linking configured answers 503.
1043pub async fn get_integrations_teams_link_aad(configuration: &configuration::Configuration, ) -> Result<(), Error<GetIntegrationsTeamsLinkAadError>> {
1044
1045    let uri_str = format!("{}/v1/integrations/teams/link/aad", configuration.base_path);
1046    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
1047
1048    if let Some(ref user_agent) = configuration.user_agent {
1049        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
1050    }
1051    if let Some(ref token) = configuration.bearer_access_token {
1052        req_builder = req_builder.bearer_auth(token.to_owned());
1053    };
1054
1055    let req = req_builder.build()?;
1056    let resp = configuration.client.execute(req).await?;
1057
1058    let status = resp.status();
1059
1060    if !status.is_client_error() && !status.is_server_error() {
1061        Ok(())
1062    } else {
1063        let content = resp.text().await?;
1064        let entity: Option<GetIntegrationsTeamsLinkAadError> = serde_json::from_str(&content).ok();
1065        Err(Error::ResponseError(ResponseContent { status, content, entity }))
1066    }
1067}
1068
1069/// The final leg: it binds the verified directory identity to the Hanzo account that just signed in, and answers a short confirmation page telling them to return to Teams. The Hanzo credential is sealed into the connected org's KMS namespace.  This is one leg of a three-leg flow, and the legs are not interchangeable: a browser is expected to arrive here only from the leg before it. The link URL's state proves the prompt was server-minted and carries the CHAT it started from — it is provenance only, and it never decides which account gets linked. The account identity always comes from the platform's own verified sign-in and a host-bound cookie, so forwarding a link to someone else cannot bind their account, and a session lifted into another browser is refused rather than completed. Each link is single-use, and a deployment without linking configured answers 503.
1070pub async fn get_integrations_teams_link_callback(configuration: &configuration::Configuration, ) -> Result<(), Error<GetIntegrationsTeamsLinkCallbackError>> {
1071
1072    let uri_str = format!("{}/v1/integrations/teams/link/callback", configuration.base_path);
1073    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
1074
1075    if let Some(ref user_agent) = configuration.user_agent {
1076        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
1077    }
1078    if let Some(ref token) = configuration.bearer_access_token {
1079        req_builder = req_builder.bearer_auth(token.to_owned());
1080    };
1081
1082    let req = req_builder.build()?;
1083    let resp = configuration.client.execute(req).await?;
1084
1085    let status = resp.status();
1086
1087    if !status.is_client_error() && !status.is_server_error() {
1088        Ok(())
1089    } else {
1090        let content = resp.text().await?;
1091        let entity: Option<GetIntegrationsTeamsLinkCallbackError> = serde_json::from_str(&content).ok();
1092        Err(Error::ResponseError(ResponseContent { status, content, entity }))
1093    }
1094}
1095
1096/// The entry point behind the connect prompt Hanzo sends in Telegram. Unlike the other platforms it answers an HTML PAGE rather than a redirect: Telegram has no OAuth flow, so the page hosts Telegram's Login Widget, and the browser is sent onward only after the user signs in through it.  The widget only appears on the domain registered for the bot, so a deployment whose bot domain is unset renders a page with nothing on it.  This is one leg of a three-leg flow, and the legs are not interchangeable: a browser is expected to arrive here only from the leg before it. The link URL's state proves the prompt was server-minted and carries the CHAT it started from — it is provenance only, and it never decides which account gets linked. The account identity always comes from the platform's own verified sign-in and a host-bound cookie, so forwarding a link to someone else cannot bind their account, and a session lifted into another browser is refused rather than completed. Each link is single-use, and a deployment without linking configured answers 503.
1097pub async fn get_integrations_telegram_link(configuration: &configuration::Configuration, ) -> Result<(), Error<GetIntegrationsTelegramLinkError>> {
1098
1099    let uri_str = format!("{}/v1/integrations/telegram/link", configuration.base_path);
1100    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
1101
1102    if let Some(ref user_agent) = configuration.user_agent {
1103        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
1104    }
1105    if let Some(ref token) = configuration.bearer_access_token {
1106        req_builder = req_builder.bearer_auth(token.to_owned());
1107    };
1108
1109    let req = req_builder.build()?;
1110    let resp = configuration.client.execute(req).await?;
1111
1112    let status = resp.status();
1113
1114    if !status.is_client_error() && !status.is_server_error() {
1115        Ok(())
1116    } else {
1117        let content = resp.text().await?;
1118        let entity: Option<GetIntegrationsTelegramLinkError> = serde_json::from_str(&content).ok();
1119        Err(Error::ResponseError(ResponseContent { status, content, entity }))
1120    }
1121}
1122
1123/// Where Telegram's Login Widget sends the user with its signed authentication data. That data is verified against the bot token — this is the identity source, and it is the widget's signature rather than a code exchange — and the chat is confirmed to be bound to an org before the browser is handed to the Hanzo sign-in.  Widget data is only accepted while it is fresh, so a captured sign-in blob cannot be replayed later even though its signature stays valid.  This is one leg of a three-leg flow, and the legs are not interchangeable: a browser is expected to arrive here only from the leg before it. The link URL's state proves the prompt was server-minted and carries the CHAT it started from — it is provenance only, and it never decides which account gets linked. The account identity always comes from the platform's own verified sign-in and a host-bound cookie, so forwarding a link to someone else cannot bind their account, and a session lifted into another browser is refused rather than completed. Each link is single-use, and a deployment without linking configured answers 503.
1124pub async fn get_integrations_telegram_link_auth(configuration: &configuration::Configuration, ) -> Result<(), Error<GetIntegrationsTelegramLinkAuthError>> {
1125
1126    let uri_str = format!("{}/v1/integrations/telegram/link/auth", configuration.base_path);
1127    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
1128
1129    if let Some(ref user_agent) = configuration.user_agent {
1130        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
1131    }
1132    if let Some(ref token) = configuration.bearer_access_token {
1133        req_builder = req_builder.bearer_auth(token.to_owned());
1134    };
1135
1136    let req = req_builder.build()?;
1137    let resp = configuration.client.execute(req).await?;
1138
1139    let status = resp.status();
1140
1141    if !status.is_client_error() && !status.is_server_error() {
1142        Ok(())
1143    } else {
1144        let content = resp.text().await?;
1145        let entity: Option<GetIntegrationsTelegramLinkAuthError> = serde_json::from_str(&content).ok();
1146        Err(Error::ResponseError(ResponseContent { status, content, entity }))
1147    }
1148}
1149
1150/// The final leg: it binds the verified Telegram user to the Hanzo account that just signed in, and answers a short confirmation page telling them to return to Telegram. The Hanzo credential is sealed into the connected org's KMS namespace.  This is one leg of a three-leg flow, and the legs are not interchangeable: a browser is expected to arrive here only from the leg before it. The link URL's state proves the prompt was server-minted and carries the CHAT it started from — it is provenance only, and it never decides which account gets linked. The account identity always comes from the platform's own verified sign-in and a host-bound cookie, so forwarding a link to someone else cannot bind their account, and a session lifted into another browser is refused rather than completed. Each link is single-use, and a deployment without linking configured answers 503.
1151pub async fn get_integrations_telegram_link_callback(configuration: &configuration::Configuration, ) -> Result<(), Error<GetIntegrationsTelegramLinkCallbackError>> {
1152
1153    let uri_str = format!("{}/v1/integrations/telegram/link/callback", configuration.base_path);
1154    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
1155
1156    if let Some(ref user_agent) = configuration.user_agent {
1157        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
1158    }
1159    if let Some(ref token) = configuration.bearer_access_token {
1160        req_builder = req_builder.bearer_auth(token.to_owned());
1161    };
1162
1163    let req = req_builder.build()?;
1164    let resp = configuration.client.execute(req).await?;
1165
1166    let status = resp.status();
1167
1168    if !status.is_client_error() && !status.is_server_error() {
1169        Ok(())
1170    } else {
1171        let content = resp.text().await?;
1172        let entity: Option<GetIntegrationsTelegramLinkCallbackError> = serde_json::from_str(&content).ok();
1173        Err(Error::ResponseError(ResponseContent { status, content, entity }))
1174    }
1175}
1176
1177/// Meta calls this once when the webhook is subscribed, carrying the verify token this deployment was configured with and a challenge to echo. The token is compared in constant time before the echo — answering the challenge without checking it would let anyone point their own app at this address and have it confirm the subscription.
1178pub async fn get_integrations_whatsapp_webhook(configuration: &configuration::Configuration, ) -> Result<(), Error<GetIntegrationsWhatsappWebhookError>> {
1179
1180    let uri_str = format!("{}/v1/integrations/whatsapp/webhook", configuration.base_path);
1181    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
1182
1183    if let Some(ref user_agent) = configuration.user_agent {
1184        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
1185    }
1186    if let Some(ref token) = configuration.bearer_access_token {
1187        req_builder = req_builder.bearer_auth(token.to_owned());
1188    };
1189
1190    let req = req_builder.build()?;
1191    let resp = configuration.client.execute(req).await?;
1192
1193    let status = resp.status();
1194
1195    if !status.is_client_error() && !status.is_server_error() {
1196        Ok(())
1197    } else {
1198        let content = resp.text().await?;
1199        let entity: Option<GetIntegrationsWhatsappWebhookError> = serde_json::from_str(&content).ok();
1200        Err(Error::ResponseError(ResponseContent { status, content, entity }))
1201    }
1202}
1203
1204/// Acquires the org's credential for one provider. It has TWO paths and the REQUEST picks which: a \"token\" key in the body seals that credential directly (verify-before-store), and its absence begins the 3-legged OAuth flow — minting a single-use nonce plus an HMAC-signed state that binds this org to this provider, and answering with the provider's authorize URL for the caller to redirect to.  Fail-closed order, unchanged: no principal → 403; unknown provider → 404; an AdminOnly connector without the caller's own-org admin bit → 403; not configured → 503; KMS not ready → 503 (the flow WILL need to seal a token, so refuse now rather than dead-end at the callback).
1205pub async fn post_integrations_by_provider_connect(configuration: &configuration::Configuration, provider: &str, connect_in: models::ConnectIn) -> Result<models::ConnectOut, Error<PostIntegrationsByProviderConnectError>> {
1206    // add a prefix to parameters to efficiently prevent name collisions
1207    let p_provider = provider;
1208    let p_connect_in = connect_in;
1209
1210    let uri_str = format!("{}/v1/integrations/{provider}/connect", configuration.base_path, provider=crate::apis::urlencode(p_provider));
1211    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
1212
1213    if let Some(ref user_agent) = configuration.user_agent {
1214        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
1215    }
1216    if let Some(ref token) = configuration.bearer_access_token {
1217        req_builder = req_builder.bearer_auth(token.to_owned());
1218    };
1219    req_builder = req_builder.json(&p_connect_in);
1220
1221    let req = req_builder.build()?;
1222    let resp = configuration.client.execute(req).await?;
1223
1224    let status = resp.status();
1225    let content_type = resp
1226        .headers()
1227        .get("content-type")
1228        .and_then(|v| v.to_str().ok())
1229        .unwrap_or("application/octet-stream");
1230    let content_type = super::ContentType::from(content_type);
1231
1232    if !status.is_client_error() && !status.is_server_error() {
1233        let content = resp.text().await?;
1234        match content_type {
1235            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
1236            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::ConnectOut`"))),
1237            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::ConnectOut`")))),
1238        }
1239    } else {
1240        let content = resp.text().await?;
1241        let entity: Option<PostIntegrationsByProviderConnectError> = serde_json::from_str(&content).ok();
1242        Err(Error::ResponseError(ResponseContent { status, content, entity }))
1243    }
1244}
1245
1246/// Revokes (best-effort) and forgets an org's connection: it deletes every custodied KMS secret and the connection row. Idempotent — disconnecting a provider that was never connected still returns {disconnected:true}. Symmetric with connect: an AdminOnly connector needs the caller's own-org admin bit.
1247pub async fn post_integrations_by_provider_disconnect(configuration: &configuration::Configuration, provider: &str) -> Result<models::DisconnectOut, Error<PostIntegrationsByProviderDisconnectError>> {
1248    // add a prefix to parameters to efficiently prevent name collisions
1249    let p_provider = provider;
1250
1251    let uri_str = format!("{}/v1/integrations/{provider}/disconnect", configuration.base_path, provider=crate::apis::urlencode(p_provider));
1252    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
1253
1254    if let Some(ref user_agent) = configuration.user_agent {
1255        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
1256    }
1257    if let Some(ref token) = configuration.bearer_access_token {
1258        req_builder = req_builder.bearer_auth(token.to_owned());
1259    };
1260
1261    let req = req_builder.build()?;
1262    let resp = configuration.client.execute(req).await?;
1263
1264    let status = resp.status();
1265    let content_type = resp
1266        .headers()
1267        .get("content-type")
1268        .and_then(|v| v.to_str().ok())
1269        .unwrap_or("application/octet-stream");
1270    let content_type = super::ContentType::from(content_type);
1271
1272    if !status.is_client_error() && !status.is_server_error() {
1273        let content = resp.text().await?;
1274        match content_type {
1275            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
1276            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::DisconnectOut`"))),
1277            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::DisconnectOut`")))),
1278        }
1279    } else {
1280        let content = resp.text().await?;
1281        let entity: Option<PostIntegrationsByProviderDisconnectError> = serde_json::from_str(&content).ok();
1282        Err(Error::ResponseError(ResponseContent { status, content, entity }))
1283    }
1284}
1285
1286/// Re-checks a CONNECTED apikey connector's stored credential against the provider, live (`hanzo connector verify`). Org-scoped (any member may check status); the credential is read from KMS, verified, and NEVER returned or logged. A verification failure is reported as {active:false}, not an error — the console/ CLI renders it. Only apikey providers support verify (OAuth tokens are checked at use, not re-verified here).
1287pub async fn post_integrations_by_provider_verify(configuration: &configuration::Configuration, provider: &str) -> Result<models::VerifyOut, Error<PostIntegrationsByProviderVerifyError>> {
1288    // add a prefix to parameters to efficiently prevent name collisions
1289    let p_provider = provider;
1290
1291    let uri_str = format!("{}/v1/integrations/{provider}/verify", configuration.base_path, provider=crate::apis::urlencode(p_provider));
1292    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
1293
1294    if let Some(ref user_agent) = configuration.user_agent {
1295        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
1296    }
1297    if let Some(ref token) = configuration.bearer_access_token {
1298        req_builder = req_builder.bearer_auth(token.to_owned());
1299    };
1300
1301    let req = req_builder.build()?;
1302    let resp = configuration.client.execute(req).await?;
1303
1304    let status = resp.status();
1305    let content_type = resp
1306        .headers()
1307        .get("content-type")
1308        .and_then(|v| v.to_str().ok())
1309        .unwrap_or("application/octet-stream");
1310    let content_type = super::ContentType::from(content_type);
1311
1312    if !status.is_client_error() && !status.is_server_error() {
1313        let content = resp.text().await?;
1314        match content_type {
1315            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
1316            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::VerifyOut`"))),
1317            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::VerifyOut`")))),
1318        }
1319    } else {
1320        let content = resp.text().await?;
1321        let entity: Option<PostIntegrationsByProviderVerifyError> = serde_json::from_str(&content).ok();
1322        Err(Error::ResponseError(ResponseContent { status, content, entity }))
1323    }
1324}
1325
1326/// Forces a token rotation for a connected connector, ahead of the automatic rotation a token read would do inside the expiry window. Only providers that declare a Refresh support it.
1327pub async fn post_integrations_connectors_by_id_refresh(configuration: &configuration::Configuration, id: &str) -> Result<models::RefreshOut, Error<PostIntegrationsConnectorsByIdRefreshError>> {
1328    // add a prefix to parameters to efficiently prevent name collisions
1329    let p_id = id;
1330
1331    let uri_str = format!("{}/v1/integrations/connectors/{id}/refresh", configuration.base_path, id=crate::apis::urlencode(p_id));
1332    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
1333
1334    if let Some(ref user_agent) = configuration.user_agent {
1335        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
1336    }
1337    if let Some(ref token) = configuration.bearer_access_token {
1338        req_builder = req_builder.bearer_auth(token.to_owned());
1339    };
1340
1341    let req = req_builder.build()?;
1342    let resp = configuration.client.execute(req).await?;
1343
1344    let status = resp.status();
1345    let content_type = resp
1346        .headers()
1347        .get("content-type")
1348        .and_then(|v| v.to_str().ok())
1349        .unwrap_or("application/octet-stream");
1350    let content_type = super::ContentType::from(content_type);
1351
1352    if !status.is_client_error() && !status.is_server_error() {
1353        let content = resp.text().await?;
1354        match content_type {
1355            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
1356            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::RefreshOut`"))),
1357            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::RefreshOut`")))),
1358        }
1359    } else {
1360        let content = resp.text().await?;
1361        let entity: Option<PostIntegrationsConnectorsByIdRefreshError> = serde_json::from_str(&content).ok();
1362        Err(Error::ResponseError(ResponseContent { status, content, entity }))
1363    }
1364}
1365
1366/// Is the direct intake path: a customer-held token/setup-token (Verify) or an externally obtained OAuth bundle from the CLI's local PKCE (Adopt). ALWAYS verify-before-store: a bad credential is refused and NOTHING is persisted (connectByCredential's fail-closed order).
1367pub async fn post_integrations_connectors_by_provider_credential(configuration: &configuration::Configuration, provider: &str, credential_in: models::CredentialIn) -> Result<models::CredentialOut, Error<PostIntegrationsConnectorsByProviderCredentialError>> {
1368    // add a prefix to parameters to efficiently prevent name collisions
1369    let p_provider = provider;
1370    let p_credential_in = credential_in;
1371
1372    let uri_str = format!("{}/v1/integrations/connectors/{provider}/credential", configuration.base_path, provider=crate::apis::urlencode(p_provider));
1373    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
1374
1375    if let Some(ref user_agent) = configuration.user_agent {
1376        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
1377    }
1378    if let Some(ref token) = configuration.bearer_access_token {
1379        req_builder = req_builder.bearer_auth(token.to_owned());
1380    };
1381    req_builder = req_builder.json(&p_credential_in);
1382
1383    let req = req_builder.build()?;
1384    let resp = configuration.client.execute(req).await?;
1385
1386    let status = resp.status();
1387    let content_type = resp
1388        .headers()
1389        .get("content-type")
1390        .and_then(|v| v.to_str().ok())
1391        .unwrap_or("application/octet-stream");
1392    let content_type = super::ContentType::from(content_type);
1393
1394    if !status.is_client_error() && !status.is_server_error() {
1395        let content = resp.text().await?;
1396        match content_type {
1397            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
1398            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::CredentialOut`"))),
1399            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::CredentialOut`")))),
1400        }
1401    } else {
1402        let content = resp.text().await?;
1403        let entity: Option<PostIntegrationsConnectorsByProviderCredentialError> = serde_json::from_str(&content).ok();
1404        Err(Error::ResponseError(ResponseContent { status, content, entity }))
1405    }
1406}
1407
1408/// Begins a device sign-in and returns the code to show the user plus how to poll for completion. KMS readiness is checked NOW rather than dead-ending the user at poll-done (connect() parity), and the per-provider connector cap is checked before the provider is called. The provider's device code is persisted only in the encrypted grants table and is NEVER returned.
1409pub async fn post_integrations_connectors_by_provider_device(configuration: &configuration::Configuration, provider: &str, device_start_in: models::DeviceStartIn) -> Result<models::DeviceStartOut, Error<PostIntegrationsConnectorsByProviderDeviceError>> {
1410    // add a prefix to parameters to efficiently prevent name collisions
1411    let p_provider = provider;
1412    let p_device_start_in = device_start_in;
1413
1414    let uri_str = format!("{}/v1/integrations/connectors/{provider}/device", configuration.base_path, provider=crate::apis::urlencode(p_provider));
1415    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
1416
1417    if let Some(ref user_agent) = configuration.user_agent {
1418        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
1419    }
1420    if let Some(ref token) = configuration.bearer_access_token {
1421        req_builder = req_builder.bearer_auth(token.to_owned());
1422    };
1423    req_builder = req_builder.json(&p_device_start_in);
1424
1425    let req = req_builder.build()?;
1426    let resp = configuration.client.execute(req).await?;
1427
1428    let status = resp.status();
1429    let content_type = resp
1430        .headers()
1431        .get("content-type")
1432        .and_then(|v| v.to_str().ok())
1433        .unwrap_or("application/octet-stream");
1434    let content_type = super::ContentType::from(content_type);
1435
1436    if !status.is_client_error() && !status.is_server_error() {
1437        let content = resp.text().await?;
1438        match content_type {
1439            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
1440            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::DeviceStartOut`"))),
1441            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::DeviceStartOut`")))),
1442        }
1443    } else {
1444        let content = resp.text().await?;
1445        let entity: Option<PostIntegrationsConnectorsByProviderDeviceError> = serde_json::from_str(&content).ok();
1446        Err(Error::ResponseError(ResponseContent { status, content, entity }))
1447    }
1448}
1449
1450/// Advances a device sign-in. Terminal outcomes are DATA, not errors (verifyConn {active:false} discipline) — the status set is closed: pending|connected|denied|expired. pollSlow collapses to \"pending\" on the wire; the raised cadence rides interval.
1451pub async fn post_integrations_connectors_by_provider_device_by_flow_poll(configuration: &configuration::Configuration, provider: &str, flow: &str) -> Result<models::DevicePollOut, Error<PostIntegrationsConnectorsByProviderDeviceByFlowPollError>> {
1452    // add a prefix to parameters to efficiently prevent name collisions
1453    let p_provider = provider;
1454    let p_flow = flow;
1455
1456    let uri_str = format!("{}/v1/integrations/connectors/{provider}/device/{flow}/poll", configuration.base_path, provider=crate::apis::urlencode(p_provider), flow=crate::apis::urlencode(p_flow));
1457    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
1458
1459    if let Some(ref user_agent) = configuration.user_agent {
1460        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
1461    }
1462    if let Some(ref token) = configuration.bearer_access_token {
1463        req_builder = req_builder.bearer_auth(token.to_owned());
1464    };
1465
1466    let req = req_builder.build()?;
1467    let resp = configuration.client.execute(req).await?;
1468
1469    let status = resp.status();
1470    let content_type = resp
1471        .headers()
1472        .get("content-type")
1473        .and_then(|v| v.to_str().ok())
1474        .unwrap_or("application/octet-stream");
1475    let content_type = super::ContentType::from(content_type);
1476
1477    if !status.is_client_error() && !status.is_server_error() {
1478        let content = resp.text().await?;
1479        match content_type {
1480            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
1481            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::DevicePollOut`"))),
1482            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::DevicePollOut`")))),
1483        }
1484    } else {
1485        let content = resp.text().await?;
1486        let entity: Option<PostIntegrationsConnectorsByProviderDeviceByFlowPollError> = serde_json::from_str(&content).ok();
1487        Err(Error::ResponseError(ResponseContent { status, content, entity }))
1488    }
1489}
1490
1491/// The Interactions Endpoint URL for the Discord app. It answers Discord's PING with a PONG, and handles the `/hanzo` slash command by acknowledging with a deferred ephemeral reply and editing that reply with the answer once the agent has run. Any other interaction is acknowledged and ignored.  Requests are verified by ED25519 SIGNATURE over the timestamp and body against the app's public key — not by HMAC, unlike the Slack webhooks. Interactions work over plain HTTP, so no gateway connection and no message-content intent is involved.  Discord does not retry, so this is the one channel where being at capacity is shown to the user as an ephemeral ask-to-run-it-again rather than answered as a retriable failure — nothing is recorded either way, so the next attempt is clean.  The caller here is the PLATFORM, not a Hanzo tenant, so there is no bearer and no principal. The signature check IS the authentication, and it fails closed. The tenant is never read from the payload either: it is resolved from the verified platform identifier through the connection map, so an event from a workspace nobody connected does nothing. Refusals are written with their own status rather than being flattened to a 500, so a rejected signature reads as 401 and a malformed body as 400.
1492pub async fn post_integrations_discord_interactions(configuration: &configuration::Configuration, ) -> Result<(), Error<PostIntegrationsDiscordInteractionsError>> {
1493
1494    let uri_str = format!("{}/v1/integrations/discord/interactions", configuration.base_path);
1495    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
1496
1497    if let Some(ref user_agent) = configuration.user_agent {
1498        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
1499    }
1500    if let Some(ref token) = configuration.bearer_access_token {
1501        req_builder = req_builder.bearer_auth(token.to_owned());
1502    };
1503
1504    let req = req_builder.build()?;
1505    let resp = configuration.client.execute(req).await?;
1506
1507    let status = resp.status();
1508
1509    if !status.is_client_error() && !status.is_server_error() {
1510        Ok(())
1511    } else {
1512        let content = resp.text().await?;
1513        let entity: Option<PostIntegrationsDiscordInteractionsError> = serde_json::from_str(&content).ok();
1514        Err(Error::ResponseError(ResponseContent { status, content, entity }))
1515    }
1516}
1517
1518/// Binds installations the App ALREADY holds to the org the caller is acting in — the reconciliation for a grant that happened outside our connect flow.  An installation IS the grant: GitHub recorded the consent when the App was installed, and our connection row is bookkeeping that never got written because nobody came through our callback. This writes that row from the App's own view, so 23 accounts granted straight from GitHub stop reading as nothing.  The org is taken from the VALIDATED PRINCIPAL and never from the body, because it is the one part GitHub cannot tell us. An installation carries an account login, a type and a repository selection — nothing that names a Hanzo org. So the binding cannot be DERIVED, only asserted, and the only unforgeable assertion available is the org the caller is already acting in. Inferring one from the account name would be a guess the store cannot catch: its key is (org,provider,owner), so a wrong org is a valid row, and a valid row is a mirror pointed at the wrong tenant.  SUPER ADMIN only, for that same reason. A tenant's proof that an account is theirs is GitHub's own consent screen — the connect flow — and without it any org could claim any account the App holds. Platform sudo is already the scope that reads the whole install list, so it is the scope that may bind from it; giving a tenant this verb would hand it every other tenant's repositories.  Idempotent: the row is keyed (org,provider,owner) and connected_at survives an upsert, so claiming twice rebinds the same account to the same org and reports it under `already`. Re-claiming also REFRESHES the installation id, so an account reinstalled on GitHub — new id, same login — self-heals instead of minting tokens against a dead installation.  Claiming an account another org holds ADDS this org's row and leaves theirs standing, so no org loses an integration it is using.
1519pub async fn post_integrations_github_claim(configuration: &configuration::Configuration, github_claim_in: models::GithubClaimIn) -> Result<models::GithubClaimOut, Error<PostIntegrationsGithubClaimError>> {
1520    // add a prefix to parameters to efficiently prevent name collisions
1521    let p_github_claim_in = github_claim_in;
1522
1523    let uri_str = format!("{}/v1/integrations/github/claim", configuration.base_path);
1524    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
1525
1526    if let Some(ref user_agent) = configuration.user_agent {
1527        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
1528    }
1529    if let Some(ref token) = configuration.bearer_access_token {
1530        req_builder = req_builder.bearer_auth(token.to_owned());
1531    };
1532    req_builder = req_builder.json(&p_github_claim_in);
1533
1534    let req = req_builder.build()?;
1535    let resp = configuration.client.execute(req).await?;
1536
1537    let status = resp.status();
1538    let content_type = resp
1539        .headers()
1540        .get("content-type")
1541        .and_then(|v| v.to_str().ok())
1542        .unwrap_or("application/octet-stream");
1543    let content_type = super::ContentType::from(content_type);
1544
1545    if !status.is_client_error() && !status.is_server_error() {
1546        let content = resp.text().await?;
1547        match content_type {
1548            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
1549            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::GithubClaimOut`"))),
1550            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::GithubClaimOut`")))),
1551        }
1552    } else {
1553        let content = resp.text().await?;
1554        let entity: Option<PostIntegrationsGithubClaimError> = serde_json::from_str(&content).ok();
1555        Err(Error::ResponseError(ResponseContent { status, content, entity }))
1556    }
1557}
1558
1559/// Forks a granted repository.  GitHub's fork is ASYNCHRONOUS: it answers 202 with the target repo and populates it in the background, and it answers the same 202 when the fork already exists. So this reports what GitHub said rather than waiting — a call that blocked until the clone finished would time out on a large repository and tell the caller nothing it does not already know.
1560pub async fn post_integrations_github_fork(configuration: &configuration::Configuration, github_fork_req: models::GithubForkReq) -> Result<models::GithubForkOut, Error<PostIntegrationsGithubForkError>> {
1561    // add a prefix to parameters to efficiently prevent name collisions
1562    let p_github_fork_req = github_fork_req;
1563
1564    let uri_str = format!("{}/v1/integrations/github/fork", configuration.base_path);
1565    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
1566
1567    if let Some(ref user_agent) = configuration.user_agent {
1568        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
1569    }
1570    if let Some(ref token) = configuration.bearer_access_token {
1571        req_builder = req_builder.bearer_auth(token.to_owned());
1572    };
1573    req_builder = req_builder.json(&p_github_fork_req);
1574
1575    let req = req_builder.build()?;
1576    let resp = configuration.client.execute(req).await?;
1577
1578    let status = resp.status();
1579    let content_type = resp
1580        .headers()
1581        .get("content-type")
1582        .and_then(|v| v.to_str().ok())
1583        .unwrap_or("application/octet-stream");
1584    let content_type = super::ContentType::from(content_type);
1585
1586    if !status.is_client_error() && !status.is_server_error() {
1587        let content = resp.text().await?;
1588        match content_type {
1589            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
1590            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::GithubForkOut`"))),
1591            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::GithubForkOut`")))),
1592        }
1593    } else {
1594        let content = resp.text().await?;
1595        let entity: Option<PostIntegrationsGithubForkError> = serde_json::from_str(&content).ok();
1596        Err(Error::ResponseError(ResponseContent { status, content, entity }))
1597    }
1598}
1599
1600/// Seeds the native todo with the EXISTING issues across the org's granted repos (default state=open); the webhook keeps them live thereafter. Org-scoped by the validated principal — a caller only ever backfills its OWN org. Synchronous + bounded (a total time budget and an issue cap) so it returns the counts directly; idempotent by ExtRef, so a re-run continues where a truncated pass left off and never duplicates.
1601pub async fn post_integrations_github_issues_backfill(configuration: &configuration::Configuration, github_backfill_in: models::GithubBackfillIn) -> Result<models::GithubBackfillResult, Error<PostIntegrationsGithubIssuesBackfillError>> {
1602    // add a prefix to parameters to efficiently prevent name collisions
1603    let p_github_backfill_in = github_backfill_in;
1604
1605    let uri_str = format!("{}/v1/integrations/github/issues/backfill", configuration.base_path);
1606    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
1607
1608    if let Some(ref user_agent) = configuration.user_agent {
1609        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
1610    }
1611    if let Some(ref token) = configuration.bearer_access_token {
1612        req_builder = req_builder.bearer_auth(token.to_owned());
1613    };
1614    req_builder = req_builder.json(&p_github_backfill_in);
1615
1616    let req = req_builder.build()?;
1617    let resp = configuration.client.execute(req).await?;
1618
1619    let status = resp.status();
1620    let content_type = resp
1621        .headers()
1622        .get("content-type")
1623        .and_then(|v| v.to_str().ok())
1624        .unwrap_or("application/octet-stream");
1625    let content_type = super::ContentType::from(content_type);
1626
1627    if !status.is_client_error() && !status.is_server_error() {
1628        let content = resp.text().await?;
1629        match content_type {
1630            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
1631            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::GithubBackfillResult`"))),
1632            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::GithubBackfillResult`")))),
1633        }
1634    } else {
1635        let content = resp.text().await?;
1636        let entity: Option<PostIntegrationsGithubIssuesBackfillError> = serde_json::from_str(&content).ok();
1637        Err(Error::ResponseError(ResponseContent { status, content, entity }))
1638    }
1639}
1640
1641/// Creates the repo's Pages site and answers 201 Created with it. With buildType \"workflow\" the site builds via GitHub Actions; otherwise it builds from a branch source, defaulting to the repo's own default branch when none is given. Only \"/\" and \"/docs\" are legal source paths (GitHub's rule).
1642pub async fn post_integrations_github_repos_by_repo_pages(configuration: &configuration::Configuration, repo: &str, github_pages_enable_req: models::GithubPagesEnableReq) -> Result<models::GithubPagesView, Error<PostIntegrationsGithubReposByRepoPagesError>> {
1643    // add a prefix to parameters to efficiently prevent name collisions
1644    let p_repo = repo;
1645    let p_github_pages_enable_req = github_pages_enable_req;
1646
1647    let uri_str = format!("{}/v1/integrations/github/repos/{repo}/pages", configuration.base_path, repo=crate::apis::urlencode(p_repo));
1648    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
1649
1650    if let Some(ref user_agent) = configuration.user_agent {
1651        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
1652    }
1653    if let Some(ref token) = configuration.bearer_access_token {
1654        req_builder = req_builder.bearer_auth(token.to_owned());
1655    };
1656    req_builder = req_builder.json(&p_github_pages_enable_req);
1657
1658    let req = req_builder.build()?;
1659    let resp = configuration.client.execute(req).await?;
1660
1661    let status = resp.status();
1662    let content_type = resp
1663        .headers()
1664        .get("content-type")
1665        .and_then(|v| v.to_str().ok())
1666        .unwrap_or("application/octet-stream");
1667    let content_type = super::ContentType::from(content_type);
1668
1669    if !status.is_client_error() && !status.is_server_error() {
1670        let content = resp.text().await?;
1671        match content_type {
1672            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
1673            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::GithubPagesView`"))),
1674            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::GithubPagesView`")))),
1675        }
1676    } else {
1677        let content = resp.text().await?;
1678        let entity: Option<PostIntegrationsGithubReposByRepoPagesError> = serde_json::from_str(&content).ok();
1679        Err(Error::ResponseError(ResponseContent { status, content, entity }))
1680    }
1681}
1682
1683/// Requests a Pages rebuild and returns the queued build's status. The build is queued AT GITHUB, not completed here, so the answer is 202 Accepted and its status is the one GitHub reported at queue time. 404 when the repository has no Pages site, or when the org's installation was not granted it.
1684pub async fn post_integrations_github_repos_by_repo_pages_builds(configuration: &configuration::Configuration, repo: &str) -> Result<models::GithubPagesBuildOut, Error<PostIntegrationsGithubReposByRepoPagesBuildsError>> {
1685    // add a prefix to parameters to efficiently prevent name collisions
1686    let p_repo = repo;
1687
1688    let uri_str = format!("{}/v1/integrations/github/repos/{repo}/pages/builds", configuration.base_path, repo=crate::apis::urlencode(p_repo));
1689    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
1690
1691    if let Some(ref user_agent) = configuration.user_agent {
1692        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
1693    }
1694    if let Some(ref token) = configuration.bearer_access_token {
1695        req_builder = req_builder.bearer_auth(token.to_owned());
1696    };
1697
1698    let req = req_builder.build()?;
1699    let resp = configuration.client.execute(req).await?;
1700
1701    let status = resp.status();
1702    let content_type = resp
1703        .headers()
1704        .get("content-type")
1705        .and_then(|v| v.to_str().ok())
1706        .unwrap_or("application/octet-stream");
1707    let content_type = super::ContentType::from(content_type);
1708
1709    if !status.is_client_error() && !status.is_server_error() {
1710        let content = resp.text().await?;
1711        match content_type {
1712            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
1713            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::GithubPagesBuildOut`"))),
1714            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::GithubPagesBuildOut`")))),
1715        }
1716    } else {
1717        let content = resp.text().await?;
1718        let entity: Option<PostIntegrationsGithubReposByRepoPagesBuildsError> = serde_json::from_str(&content).ok();
1719        Err(Error::ResponseError(ResponseContent { status, content, entity }))
1720    }
1721}
1722
1723/// Imports the selected (or all) granted repos into git.hanzo.ai. The selection is intersected with the installation's GRANTED set, so a client can never import a repo the App was not granted (org isolation + a grant check). The import runs in a bounded background worker (don't block the request), so the answer is 202 Accepted; poll GET /v1/integrations/github/repos for the per-repo status to flip to imported.
1724pub async fn post_integrations_github_repos_import(configuration: &configuration::Configuration, github_import_in: models::GithubImportIn) -> Result<models::GithubImportOut, Error<PostIntegrationsGithubReposImportError>> {
1725    // add a prefix to parameters to efficiently prevent name collisions
1726    let p_github_import_in = github_import_in;
1727
1728    let uri_str = format!("{}/v1/integrations/github/repos/import", configuration.base_path);
1729    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
1730
1731    if let Some(ref user_agent) = configuration.user_agent {
1732        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
1733    }
1734    if let Some(ref token) = configuration.bearer_access_token {
1735        req_builder = req_builder.bearer_auth(token.to_owned());
1736    };
1737    req_builder = req_builder.json(&p_github_import_in);
1738
1739    let req = req_builder.build()?;
1740    let resp = configuration.client.execute(req).await?;
1741
1742    let status = resp.status();
1743    let content_type = resp
1744        .headers()
1745        .get("content-type")
1746        .and_then(|v| v.to_str().ok())
1747        .unwrap_or("application/octet-stream");
1748    let content_type = super::ContentType::from(content_type);
1749
1750    if !status.is_client_error() && !status.is_server_error() {
1751        let content = resp.text().await?;
1752        match content_type {
1753            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
1754            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::GithubImportOut`"))),
1755            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::GithubImportOut`")))),
1756        }
1757    } else {
1758        let content = resp.text().await?;
1759        let entity: Option<PostIntegrationsGithubReposImportError> = serde_json::from_str(&content).ok();
1760        Err(Error::ResponseError(ResponseContent { status, content, entity }))
1761    }
1762}
1763
1764/// Finds repositories on GitHub.  This reads the PUBLIC index and returns nothing an installation unlocks: it is how you find a repository to fork, not a way to see inside one. The org's own token is used only so the query is rate-limited against the installation rather than anonymously — the results are the same ones anyone would get.
1765pub async fn post_integrations_github_search(configuration: &configuration::Configuration, github_search_req: models::GithubSearchReq) -> Result<models::GithubSearchOut, Error<PostIntegrationsGithubSearchError>> {
1766    // add a prefix to parameters to efficiently prevent name collisions
1767    let p_github_search_req = github_search_req;
1768
1769    let uri_str = format!("{}/v1/integrations/github/search", configuration.base_path);
1770    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
1771
1772    if let Some(ref user_agent) = configuration.user_agent {
1773        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
1774    }
1775    if let Some(ref token) = configuration.bearer_access_token {
1776        req_builder = req_builder.bearer_auth(token.to_owned());
1777    };
1778    req_builder = req_builder.json(&p_github_search_req);
1779
1780    let req = req_builder.build()?;
1781    let resp = configuration.client.execute(req).await?;
1782
1783    let status = resp.status();
1784    let content_type = resp
1785        .headers()
1786        .get("content-type")
1787        .and_then(|v| v.to_str().ok())
1788        .unwrap_or("application/octet-stream");
1789    let content_type = super::ContentType::from(content_type);
1790
1791    if !status.is_client_error() && !status.is_server_error() {
1792        let content = resp.text().await?;
1793        match content_type {
1794            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
1795            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::GithubSearchOut`"))),
1796            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::GithubSearchOut`")))),
1797        }
1798    } else {
1799        let content = resp.text().await?;
1800        let entity: Option<PostIntegrationsGithubSearchError> = serde_json::from_str(&content).ok();
1801        Err(Error::ResponseError(ResponseContent { status, content, entity }))
1802    }
1803}
1804
1805/// The address the GitHub App delivers events to. A push is handed to the repository sync engine, and an issue or issue-comment event is mirrored into the native todo — idempotently, so the same issue re-syncs to one row however many times it is edited, closed or reopened. A repository event that puts a repo INTO the granted set (created, transferred, unarchived) raises one todo offering to import it; accepting means POSTing that repo to /v1/integrations/github/import. It never imports on its own.  It answers a benign 200 for everything it does not act on — the ping, other event types, an unknown installation — deliberately, so GitHub does not enter a retry storm over events that were never going to do anything. Only a bad signature and a genuine sync failure are non-200, and an oversized payload is refused outright.  Two sync rules are worth stating because neither is guessable. EVERY ref syncs, tags as well as branches, because releases are cut by tag and filtering them would stop publishing with nothing reporting a failure. And a delete is NEVER propagated: the native side is canonical, so an inbound delete never removes a native ref.  The payload is verified by HMAC against the webhook secret before it is parsed.  The caller here is the PLATFORM, not a Hanzo tenant, so there is no bearer and no principal. The signature check IS the authentication, and it fails closed. The tenant is never read from the payload either: it is resolved from the verified platform identifier through the connection map, so an event from a workspace nobody connected does nothing. Refusals are written with their own status rather than being flattened to a 500, so a rejected signature reads as 401 and a malformed body as 400.
1806pub async fn post_integrations_github_webhook(configuration: &configuration::Configuration, ) -> Result<(), Error<PostIntegrationsGithubWebhookError>> {
1807
1808    let uri_str = format!("{}/v1/integrations/github/webhook", configuration.base_path);
1809    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
1810
1811    if let Some(ref user_agent) = configuration.user_agent {
1812        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
1813    }
1814    if let Some(ref token) = configuration.bearer_access_token {
1815        req_builder = req_builder.bearer_auth(token.to_owned());
1816    };
1817
1818    let req = req_builder.build()?;
1819    let resp = configuration.client.execute(req).await?;
1820
1821    let status = resp.status();
1822
1823    if !status.is_client_error() && !status.is_server_error() {
1824        Ok(())
1825    } else {
1826        let content = resp.text().await?;
1827        let entity: Option<PostIntegrationsGithubWebhookError> = serde_json::from_str(&content).ok();
1828        Err(Error::ResponseError(ResponseContent { status, content, entity }))
1829    }
1830}
1831
1832/// OpenRouter's spend is invisible to every Hanzo money lens because those lenses read hanzo.cloud_usage and OpenRouter meters keys of its own. Point a Broadcast destination (Settings ▸ Observability ▸ Webhook) at this endpoint and each generation span becomes ONE row in that same ledger with provider `openrouter`, so one query answers what we spend everywhere. Enable the Cost and Identity field categories: cost is the money and identity carries `openrouter.api_key_name`, which is what says WHICH key spent it — it lands in `account` as openrouter/<key name>.  AUTHENTICATION IS A HANZO KEY. Broadcast signs nothing; its only authentication is the destination's Headers map, so send a key as `Authorization: Bearer pk-…` and it is admitted exactly as /v1/event admits a beacon's: a project key resolves through the project that minted it, an IAM-issued key through IAM. That key names the org every row is filed under; it can write and cannot read. No key, or a key that names no org, is 401 and nothing is stored.  The body is OTLP/JSON — `{resourceSpans:[{scopeSpans:[{spans:[…]}]}]}` — exactly as OpenTelemetry defines it; the model, tokens and cost are read from each span's `gen_ai.*` attributes and the key name from `openrouter.api_key_name`. The answer is `{stored, dropped}`: how many generations became rows, and how many spans named no model. Those are OpenRouter's trace and span parents — they carry no cost to meter. An empty payload stores nothing and answers 200, which is what makes Test Connection pass. A warehouse that cannot take the rows answers 503 so the delivery shows red and can be replayed: a row is keyed by its span id, so a redelivery collapses rather than double-counting.
1833pub async fn post_integrations_openrouter_webhook(configuration: &configuration::Configuration, request_body: Option<std::collections::HashMap<String, serde_json::Value>>) -> Result<std::collections::HashMap<String, serde_json::Value>, Error<PostIntegrationsOpenrouterWebhookError>> {
1834    // add a prefix to parameters to efficiently prevent name collisions
1835    let p_request_body = request_body;
1836
1837    let uri_str = format!("{}/v1/integrations/openrouter/webhook", configuration.base_path);
1838    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
1839
1840    if let Some(ref user_agent) = configuration.user_agent {
1841        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
1842    }
1843    if let Some(ref token) = configuration.bearer_access_token {
1844        req_builder = req_builder.bearer_auth(token.to_owned());
1845    };
1846    req_builder = req_builder.json(&p_request_body);
1847
1848    let req = req_builder.build()?;
1849    let resp = configuration.client.execute(req).await?;
1850
1851    let status = resp.status();
1852    let content_type = resp
1853        .headers()
1854        .get("content-type")
1855        .and_then(|v| v.to_str().ok())
1856        .unwrap_or("application/octet-stream");
1857    let content_type = super::ContentType::from(content_type);
1858
1859    if !status.is_client_error() && !status.is_server_error() {
1860        let content = resp.text().await?;
1861        match content_type {
1862            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
1863            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `std::collections::HashMap&lt;String, serde_json::Value&gt;`"))),
1864            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `std::collections::HashMap&lt;String, serde_json::Value&gt;`")))),
1865        }
1866    } else {
1867        let content = resp.text().await?;
1868        let entity: Option<PostIntegrationsOpenrouterWebhookError> = serde_json::from_str(&content).ok();
1869        Err(Error::ResponseError(ResponseContent { status, content, entity }))
1870    }
1871}
1872
1873/// The address Slack posts a slash command to, form-encoded. It acknowledges inside Slack's three-second budget and posts the answer afterwards to the command's own response URL, which is why the immediate reply is empty.  The body is verified against the same app signing secret as the events webhook, and a repeat of the same command invocation is absorbed rather than answered twice.  The caller here is the PLATFORM, not a Hanzo tenant, so there is no bearer and no principal. The signature check IS the authentication, and it fails closed. The tenant is never read from the payload either: it is resolved from the verified platform identifier through the connection map, so an event from a workspace nobody connected does nothing. Refusals are written with their own status rather than being flattened to a 500, so a rejected signature reads as 401 and a malformed body as 400.  The answer is acknowledged immediately and the work happens afterwards, because every one of these platforms times out a slow webhook. Duplicate deliveries are absorbed durably, so a platform retry of an event that already ran never runs it a second time or bills for it twice. When the agent pool is full nothing at all is recorded and the delivery is refused as retriable, so the message is re-delivered later rather than being lost or half-processed.
1874pub async fn post_integrations_slack_commands(configuration: &configuration::Configuration, ) -> Result<(), Error<PostIntegrationsSlackCommandsError>> {
1875
1876    let uri_str = format!("{}/v1/integrations/slack/commands", configuration.base_path);
1877    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
1878
1879    if let Some(ref user_agent) = configuration.user_agent {
1880        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
1881    }
1882    if let Some(ref token) = configuration.bearer_access_token {
1883        req_builder = req_builder.bearer_auth(token.to_owned());
1884    };
1885
1886    let req = req_builder.build()?;
1887    let resp = configuration.client.execute(req).await?;
1888
1889    let status = resp.status();
1890
1891    if !status.is_client_error() && !status.is_server_error() {
1892        Ok(())
1893    } else {
1894        let content = resp.text().await?;
1895        let entity: Option<PostIntegrationsSlackCommandsError> = serde_json::from_str(&content).ok();
1896        Err(Error::ResponseError(ResponseContent { status, content, entity }))
1897    }
1898}
1899
1900/// The address a Slack app posts workspace events to. It answers Slack's url_verification handshake with the challenge, and routes an @mention or a direct message to an agent turn that replies in the same thread. The turn holds the product's own tools, so a request to change code starts a sandbox run because the model chose to — there is no prefix and no second path.  The raw body and its timestamp are verified against the app's signing secret before anything is read from them. Hanzo's own bot messages are dropped, so a reply cannot trigger another reply.  The caller here is the PLATFORM, not a Hanzo tenant, so there is no bearer and no principal. The signature check IS the authentication, and it fails closed. The tenant is never read from the payload either: it is resolved from the verified platform identifier through the connection map, so an event from a workspace nobody connected does nothing. Refusals are written with their own status rather than being flattened to a 500, so a rejected signature reads as 401 and a malformed body as 400.  The answer is acknowledged immediately and the work happens afterwards, because every one of these platforms times out a slow webhook. Duplicate deliveries are absorbed durably, so a platform retry of an event that already ran never runs it a second time or bills for it twice. When the agent pool is full nothing at all is recorded and the delivery is refused as retriable, so the message is re-delivered later rather than being lost or half-processed.
1901pub async fn post_integrations_slack_events(configuration: &configuration::Configuration, ) -> Result<(), Error<PostIntegrationsSlackEventsError>> {
1902
1903    let uri_str = format!("{}/v1/integrations/slack/events", configuration.base_path);
1904    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
1905
1906    if let Some(ref user_agent) = configuration.user_agent {
1907        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
1908    }
1909    if let Some(ref token) = configuration.bearer_access_token {
1910        req_builder = req_builder.bearer_auth(token.to_owned());
1911    };
1912
1913    let req = req_builder.build()?;
1914    let resp = configuration.client.execute(req).await?;
1915
1916    let status = resp.status();
1917
1918    if !status.is_client_error() && !status.is_server_error() {
1919        Ok(())
1920    } else {
1921        let content = resp.text().await?;
1922        let entity: Option<PostIntegrationsSlackEventsError> = serde_json::from_str(&content).ok();
1923        Err(Error::ResponseError(ResponseContent { status, content, entity }))
1924    }
1925}
1926
1927/// The messaging endpoint for the Teams bot. A message activity is routed to an agent turn and answered proactively through the Bot Connection; anything that is not a message with text is acknowledged and ignored.  Authentication is the Bot Framework's RS256 JWT, verified against its published keys and bound BOTH to this deployment's app id and to the activity's own service URL. The service-URL binding is the part that matters: without it a token valid for one activity could point the outbound reply somewhere else.  The caller here is the PLATFORM, not a Hanzo tenant, so there is no bearer and no principal. The signature check IS the authentication, and it fails closed. The tenant is never read from the payload either: it is resolved from the verified platform identifier through the connection map, so an event from a workspace nobody connected does nothing. Refusals are written with their own status rather than being flattened to a 500, so a rejected signature reads as 401 and a malformed body as 400.  The answer is acknowledged immediately and the work happens afterwards, because every one of these platforms times out a slow webhook. Duplicate deliveries are absorbed durably, so a platform retry of an event that already ran never runs it a second time or bills for it twice. When the agent pool is full nothing at all is recorded and the delivery is refused as retriable, so the message is re-delivered later rather than being lost or half-processed.
1928pub async fn post_integrations_teams_events(configuration: &configuration::Configuration, ) -> Result<(), Error<PostIntegrationsTeamsEventsError>> {
1929
1930    let uri_str = format!("{}/v1/integrations/teams/events", configuration.base_path);
1931    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
1932
1933    if let Some(ref user_agent) = configuration.user_agent {
1934        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
1935    }
1936    if let Some(ref token) = configuration.bearer_access_token {
1937        req_builder = req_builder.bearer_auth(token.to_owned());
1938    };
1939
1940    let req = req_builder.build()?;
1941    let resp = configuration.client.execute(req).await?;
1942
1943    let status = resp.status();
1944
1945    if !status.is_client_error() && !status.is_server_error() {
1946        Ok(())
1947    } else {
1948        let content = resp.text().await?;
1949        let entity: Option<PostIntegrationsTeamsEventsError> = serde_json::from_str(&content).ok();
1950        Err(Error::ResponseError(ResponseContent { status, content, entity }))
1951    }
1952}
1953
1954/// Mints a short, single-use deep-link code bound to the caller's org and returns the t.me link the console navigates to. Org-authed: a caller with no validated principal is 403 (same gate as the framework connect). The code is stored as an oauth_nonce (org,telegram); the webhook's /start handler claims it to bind chat→org. It is short (128-bit hex) so it fits Telegram's 64-char `start` payload limit.
1955pub async fn post_integrations_telegram_connect(configuration: &configuration::Configuration, ) -> Result<models::AuthorizeOut, Error<PostIntegrationsTelegramConnectError>> {
1956
1957    let uri_str = format!("{}/v1/integrations/telegram/connect", configuration.base_path);
1958    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
1959
1960    if let Some(ref user_agent) = configuration.user_agent {
1961        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
1962    }
1963    if let Some(ref token) = configuration.bearer_access_token {
1964        req_builder = req_builder.bearer_auth(token.to_owned());
1965    };
1966
1967    let req = req_builder.build()?;
1968    let resp = configuration.client.execute(req).await?;
1969
1970    let status = resp.status();
1971    let content_type = resp
1972        .headers()
1973        .get("content-type")
1974        .and_then(|v| v.to_str().ok())
1975        .unwrap_or("application/octet-stream");
1976    let content_type = super::ContentType::from(content_type);
1977
1978    if !status.is_client_error() && !status.is_server_error() {
1979        let content = resp.text().await?;
1980        match content_type {
1981            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
1982            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::AuthorizeOut`"))),
1983            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::AuthorizeOut`")))),
1984        }
1985    } else {
1986        let content = resp.text().await?;
1987        let entity: Option<PostIntegrationsTelegramConnectError> = serde_json::from_str(&content).ok();
1988        Err(Error::ResponseError(ResponseContent { status, content, entity }))
1989    }
1990}
1991
1992/// The update webhook for the Telegram bot. It does two jobs: `/start <code>` or `/connect <code>` binds the chat it was sent from to an org, idempotently; anything else is treated as a possible agent trigger.  What counts as a trigger differs by chat type, and it is easy to get wrong: in a private chat every message is a trigger, while in a group the message must mention the bot or use the `/hanzo` command. Non-triggers and non-message updates are acknowledged and dropped.  Authentication is the secret token Telegram echoes on every update, compared in constant time. A message in a chat that has never been bound is dropped, which is why the bind command exists.  The caller here is the PLATFORM, not a Hanzo tenant, so there is no bearer and no principal. The signature check IS the authentication, and it fails closed. The tenant is never read from the payload either: it is resolved from the verified platform identifier through the connection map, so an event from a workspace nobody connected does nothing. Refusals are written with their own status rather than being flattened to a 500, so a rejected signature reads as 401 and a malformed body as 400.  The answer is acknowledged immediately and the work happens afterwards, because every one of these platforms times out a slow webhook. Duplicate deliveries are absorbed durably, so a platform retry of an event that already ran never runs it a second time or bills for it twice. When the agent pool is full nothing at all is recorded and the delivery is refused as retriable, so the message is re-delivered later rather than being lost or half-processed.
1993pub async fn post_integrations_telegram_webhook(configuration: &configuration::Configuration, ) -> Result<(), Error<PostIntegrationsTelegramWebhookError>> {
1994
1995    let uri_str = format!("{}/v1/integrations/telegram/webhook", configuration.base_path);
1996    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
1997
1998    if let Some(ref user_agent) = configuration.user_agent {
1999        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
2000    }
2001    if let Some(ref token) = configuration.bearer_access_token {
2002        req_builder = req_builder.bearer_auth(token.to_owned());
2003    };
2004
2005    let req = req_builder.build()?;
2006    let resp = configuration.client.execute(req).await?;
2007
2008    let status = resp.status();
2009
2010    if !status.is_client_error() && !status.is_server_error() {
2011        Ok(())
2012    } else {
2013        let content = resp.text().await?;
2014        let entity: Option<PostIntegrationsTelegramWebhookError> = serde_json::from_str(&content).ok();
2015        Err(Error::ResponseError(ResponseContent { status, content, entity }))
2016    }
2017}
2018
2019/// One delivery from Meta. Authenticity is the X-Hub-Signature-256 HMAC over the raw body, and it is the whole of it: a message accepted here creates the reply route that authorises this org to answer, so an unsigned delivery would let anyone hand an org a conversation to answer under its own number.  Meta batches (entry × changes × messages) and sends status callbacks — sent/delivered/read — through this same address with no message at all. Those are acknowledged and dropped rather than refused, because a non-2xx is retried with backoff and eventually disables the subscription: the only refusals here are an unconfigured endpoint and a bad signature, which are ours to fix and not Meta's to retry.  The answer is acknowledged immediately and the work happens afterwards, because every one of these platforms times out a slow webhook. Duplicate deliveries are absorbed durably, so a platform retry of an event that already ran never runs it a second time or bills for it twice. When the agent pool is full nothing at all is recorded and the delivery is refused as retriable, so the message is re-delivered later rather than being lost or half-processed.
2020pub async fn post_integrations_whatsapp_webhook(configuration: &configuration::Configuration, ) -> Result<(), Error<PostIntegrationsWhatsappWebhookError>> {
2021
2022    let uri_str = format!("{}/v1/integrations/whatsapp/webhook", configuration.base_path);
2023    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
2024
2025    if let Some(ref user_agent) = configuration.user_agent {
2026        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
2027    }
2028    if let Some(ref token) = configuration.bearer_access_token {
2029        req_builder = req_builder.bearer_auth(token.to_owned());
2030    };
2031
2032    let req = req_builder.build()?;
2033    let resp = configuration.client.execute(req).await?;
2034
2035    let status = resp.status();
2036
2037    if !status.is_client_error() && !status.is_server_error() {
2038        Ok(())
2039    } else {
2040        let content = resp.text().await?;
2041        let entity: Option<PostIntegrationsWhatsappWebhookError> = serde_json::from_str(&content).ok();
2042        Err(Error::ResponseError(ResponseContent { status, content, entity }))
2043    }
2044}
2045
2046/// Sets or clears the custom domain (cname) and updates HTTPS enforcement, build type, or source. ONLY the provided fields are sent to GitHub, so an update never resets a setting the caller did not mention.
2047pub async fn put_integrations_github_repos_by_repo_pages(configuration: &configuration::Configuration, repo: &str, github_pages_update_req: models::GithubPagesUpdateReq) -> Result<models::GithubPagesUpdatedOut, Error<PutIntegrationsGithubReposByRepoPagesError>> {
2048    // add a prefix to parameters to efficiently prevent name collisions
2049    let p_repo = repo;
2050    let p_github_pages_update_req = github_pages_update_req;
2051
2052    let uri_str = format!("{}/v1/integrations/github/repos/{repo}/pages", configuration.base_path, repo=crate::apis::urlencode(p_repo));
2053    let mut req_builder = configuration.client.request(reqwest::Method::PUT, &uri_str);
2054
2055    if let Some(ref user_agent) = configuration.user_agent {
2056        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
2057    }
2058    if let Some(ref token) = configuration.bearer_access_token {
2059        req_builder = req_builder.bearer_auth(token.to_owned());
2060    };
2061    req_builder = req_builder.json(&p_github_pages_update_req);
2062
2063    let req = req_builder.build()?;
2064    let resp = configuration.client.execute(req).await?;
2065
2066    let status = resp.status();
2067    let content_type = resp
2068        .headers()
2069        .get("content-type")
2070        .and_then(|v| v.to_str().ok())
2071        .unwrap_or("application/octet-stream");
2072    let content_type = super::ContentType::from(content_type);
2073
2074    if !status.is_client_error() && !status.is_server_error() {
2075        let content = resp.text().await?;
2076        match content_type {
2077            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
2078            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::GithubPagesUpdatedOut`"))),
2079            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::GithubPagesUpdatedOut`")))),
2080        }
2081    } else {
2082        let content = resp.text().await?;
2083        let entity: Option<PutIntegrationsGithubReposByRepoPagesError> = serde_json::from_str(&content).ok();
2084        Err(Error::ResponseError(ResponseContent { status, content, entity }))
2085    }
2086}
2087