Skip to main content

hanzo_client/apis/
account_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_account_keys`]
19#[derive(Debug, Clone, Serialize, Deserialize)]
20#[serde(untagged)]
21pub enum DeleteAccountKeysError {
22    UnknownValue(serde_json::Value),
23}
24
25/// struct for typed errors of method [`get_account_appearance`]
26#[derive(Debug, Clone, Serialize, Deserialize)]
27#[serde(untagged)]
28pub enum GetAccountAppearanceError {
29    UnknownValue(serde_json::Value),
30}
31
32/// struct for typed errors of method [`get_account_avatar_by_org_by_user_by_digest`]
33#[derive(Debug, Clone, Serialize, Deserialize)]
34#[serde(untagged)]
35pub enum GetAccountAvatarByOrgByUserByDigestError {
36    UnknownValue(serde_json::Value),
37}
38
39/// struct for typed errors of method [`get_account_csrf`]
40#[derive(Debug, Clone, Serialize, Deserialize)]
41#[serde(untagged)]
42pub enum GetAccountCsrfError {
43    UnknownValue(serde_json::Value),
44}
45
46/// struct for typed errors of method [`get_account_embed`]
47#[derive(Debug, Clone, Serialize, Deserialize)]
48#[serde(untagged)]
49pub enum GetAccountEmbedError {
50    UnknownValue(serde_json::Value),
51}
52
53/// struct for typed errors of method [`get_account_keys`]
54#[derive(Debug, Clone, Serialize, Deserialize)]
55#[serde(untagged)]
56pub enum GetAccountKeysError {
57    UnknownValue(serde_json::Value),
58}
59
60/// struct for typed errors of method [`post_account_appearance`]
61#[derive(Debug, Clone, Serialize, Deserialize)]
62#[serde(untagged)]
63pub enum PostAccountAppearanceError {
64    UnknownValue(serde_json::Value),
65}
66
67/// struct for typed errors of method [`post_account_avatar`]
68#[derive(Debug, Clone, Serialize, Deserialize)]
69#[serde(untagged)]
70pub enum PostAccountAvatarError {
71    UnknownValue(serde_json::Value),
72}
73
74/// struct for typed errors of method [`post_account_keys`]
75#[derive(Debug, Clone, Serialize, Deserialize)]
76#[serde(untagged)]
77pub enum PostAccountKeysError {
78    UnknownValue(serde_json::Value),
79}
80
81/// struct for typed errors of method [`post_account_orgs`]
82#[derive(Debug, Clone, Serialize, Deserialize)]
83#[serde(untagged)]
84pub enum PostAccountOrgsError {
85    UnknownValue(serde_json::Value),
86}
87
88
89/// Revokes the caller's own API key of the requested class. The class is the same field mint takes — `?type=publishable`, defaulting to secret — so revoking the key that ships in a browser bundle does not sign its holder out of their own API: the other key keeps working.  Revoking is how a key is replaced when it does not need replacing; minting the same class again rotates it in one step. IAM drops the credential immediately, but the gateway caches keys for a few minutes, so a request that beat the cache expiry may still be served.  For callers written against the older shape, the class is also accepted in a JSON request body, read only when `?type=` is absent.
90pub async fn delete_account_keys(configuration: &configuration::Configuration, r#type: Option<&str>) -> Result<models::RevokedKey, Error<DeleteAccountKeysError>> {
91    // add a prefix to parameters to efficiently prevent name collisions
92    let p_type = r#type;
93
94    let uri_str = format!("{}/v1/account/keys", configuration.base_path);
95    let mut req_builder = configuration.client.request(reqwest::Method::DELETE, &uri_str);
96
97    if let Some(ref param_value) = p_type {
98        req_builder = req_builder.query(&[("type", &param_value.to_string())]);
99    }
100    if let Some(ref user_agent) = configuration.user_agent {
101        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
102    }
103    if let Some(ref token) = configuration.bearer_access_token {
104        req_builder = req_builder.bearer_auth(token.to_owned());
105    };
106
107    let req = req_builder.build()?;
108    let resp = configuration.client.execute(req).await?;
109
110    let status = resp.status();
111    let content_type = resp
112        .headers()
113        .get("content-type")
114        .and_then(|v| v.to_str().ok())
115        .unwrap_or("application/octet-stream");
116    let content_type = super::ContentType::from(content_type);
117
118    if !status.is_client_error() && !status.is_server_error() {
119        let content = resp.text().await?;
120        match content_type {
121            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
122            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::RevokedKey`"))),
123            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::RevokedKey`")))),
124        }
125    } else {
126        let content = resp.text().await?;
127        let entity: Option<DeleteAccountKeysError> = serde_json::from_str(&content).ok();
128        Err(Error::ResponseError(ResponseContent { status, content, entity }))
129    }
130}
131
132/// Returns the signed-in caller's own appearance preference — text size, density and accent — read from their IAM account so it is the same on every device and every Hanzo surface. An unset preference is an empty object.  A transient IAM read failure reports the empty preference rather than a 5xx, so a surface applies its published default and never error-toasts on load — the same fail-soft the key read uses.
133pub async fn get_account_appearance(configuration: &configuration::Configuration, ) -> Result<models::Appearance, Error<GetAccountAppearanceError>> {
134
135    let uri_str = format!("{}/v1/account/appearance", configuration.base_path);
136    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
137
138    if let Some(ref user_agent) = configuration.user_agent {
139        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
140    }
141    if let Some(ref token) = configuration.bearer_access_token {
142        req_builder = req_builder.bearer_auth(token.to_owned());
143    };
144
145    let req = req_builder.build()?;
146    let resp = configuration.client.execute(req).await?;
147
148    let status = resp.status();
149    let content_type = resp
150        .headers()
151        .get("content-type")
152        .and_then(|v| v.to_str().ok())
153        .unwrap_or("application/octet-stream");
154    let content_type = super::ContentType::from(content_type);
155
156    if !status.is_client_error() && !status.is_server_error() {
157        let content = resp.text().await?;
158        match content_type {
159            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
160            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::Appearance`"))),
161            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::Appearance`")))),
162        }
163    } else {
164        let content = resp.text().await?;
165        let entity: Option<GetAccountAppearanceError> = serde_json::from_str(&content).ok();
166        Err(Error::ResponseError(ResponseContent { status, content, entity }))
167    }
168}
169
170/// Streams a profile photo's raw BYTES. This is the address stored on the user's IAM record and rendered directly by an `<img>`, so it takes no credentials — the 64-hex content digest in the path is the capability, and it can only be produced by someone who already has the image.  The Content-Type is derived from the stored bytes and the response carries nosniff, so only a real raster image is ever served and only under its true type. Anything else — a miss, a malformed path, an object that is not an image — is one 404, and a hit caches for a year because the address is the content.
171pub async fn get_account_avatar_by_org_by_user_by_digest(configuration: &configuration::Configuration, org: &str, user: &str, digest: &str) -> Result<(), Error<GetAccountAvatarByOrgByUserByDigestError>> {
172    // add a prefix to parameters to efficiently prevent name collisions
173    let p_org = org;
174    let p_user = user;
175    let p_digest = digest;
176
177    let uri_str = format!("{}/v1/account/avatar/{org}/{user}/{digest}", configuration.base_path, org=crate::apis::urlencode(p_org), user=crate::apis::urlencode(p_user), digest=crate::apis::urlencode(p_digest));
178    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
179
180    if let Some(ref user_agent) = configuration.user_agent {
181        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
182    }
183    if let Some(ref token) = configuration.bearer_access_token {
184        req_builder = req_builder.bearer_auth(token.to_owned());
185    };
186
187    let req = req_builder.build()?;
188    let resp = configuration.client.execute(req).await?;
189
190    let status = resp.status();
191
192    if !status.is_client_error() && !status.is_server_error() {
193        Ok(())
194    } else {
195        let content = resp.text().await?;
196        let entity: Option<GetAccountAvatarByOrgByUserByDigestError> = serde_json::from_str(&content).ok();
197        Err(Error::ResponseError(ResponseContent { status, content, entity }))
198    }
199}
200
201/// IssueCSRFToken mints the anti-forgery token a browser echoes as X-CSRF-Token on every change it asks for. The token is bound to the caller's validated identity and expires, so one minted for one identity cannot authorize a change as another.  It is answered no-store, so it is never cached by a shared proxy. This is the same-origin endpoint the embedded console reads — the Same-Origin Policy is what stops a cross-site page from reading the response and forging a change.
202pub async fn get_account_csrf(configuration: &configuration::Configuration, ) -> Result<models::CsrfResp, Error<GetAccountCsrfError>> {
203
204    let uri_str = format!("{}/v1/account/csrf", configuration.base_path);
205    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
206
207    if let Some(ref user_agent) = configuration.user_agent {
208        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
209    }
210    if let Some(ref token) = configuration.bearer_access_token {
211        req_builder = req_builder.bearer_auth(token.to_owned());
212    };
213
214    let req = req_builder.build()?;
215    let resp = configuration.client.execute(req).await?;
216
217    let status = resp.status();
218    let content_type = resp
219        .headers()
220        .get("content-type")
221        .and_then(|v| v.to_str().ok())
222        .unwrap_or("application/octet-stream");
223    let content_type = super::ContentType::from(content_type);
224
225    if !status.is_client_error() && !status.is_server_error() {
226        let content = resp.text().await?;
227        match content_type {
228            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
229            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::CsrfResp`"))),
230            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::CsrfResp`")))),
231        }
232    } else {
233        let content = resp.text().await?;
234        let entity: Option<GetAccountCsrfError> = serde_json::from_str(&content).ok();
235        Err(Error::ResponseError(ResponseContent { status, content, entity }))
236    }
237}
238
239/// Reports whether one of this brand's shared embedded apps (cms, erp, help) may be framed by the caller and is actually running, so a console module can choose between the embed and the provision panel.  It answers two questions the browser cannot answer for itself. ENTITLEMENT is server-authoritative: each app is a single shared per-BRAND instance, so only a member of the owning brand org — or a SuperAdmin — is given the embed URL; every other caller gets phase \"not-entitled\" and no URL. REACHABILITY is a probe of that origin, which a cross-origin page cannot read for itself.  The probed host is always <app>.<this deployment's own brand domain>: no part of it comes from the request, so this can never be steered into probing an arbitrary origin.
240pub async fn get_account_embed(configuration: &configuration::Configuration, app: Option<&str>) -> Result<models::EmbedStatusResp, Error<GetAccountEmbedError>> {
241    // add a prefix to parameters to efficiently prevent name collisions
242    let p_app = app;
243
244    let uri_str = format!("{}/v1/account/embed", configuration.base_path);
245    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
246
247    if let Some(ref param_value) = p_app {
248        req_builder = req_builder.query(&[("app", &param_value.to_string())]);
249    }
250    if let Some(ref user_agent) = configuration.user_agent {
251        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
252    }
253    if let Some(ref token) = configuration.bearer_access_token {
254        req_builder = req_builder.bearer_auth(token.to_owned());
255    };
256
257    let req = req_builder.build()?;
258    let resp = configuration.client.execute(req).await?;
259
260    let status = resp.status();
261    let content_type = resp
262        .headers()
263        .get("content-type")
264        .and_then(|v| v.to_str().ok())
265        .unwrap_or("application/octet-stream");
266    let content_type = super::ContentType::from(content_type);
267
268    if !status.is_client_error() && !status.is_server_error() {
269        let content = resp.text().await?;
270        match content_type {
271            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
272            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::EmbedStatusResp`"))),
273            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::EmbedStatusResp`")))),
274        }
275    } else {
276        let content = resp.text().await?;
277        let entity: Option<GetAccountEmbedError> = serde_json::from_str(&content).ok();
278        Err(Error::ResponseError(ResponseContent { status, content, entity }))
279    }
280}
281
282/// Returns the caller's own API keys — every type they hold, read AUTHORITATIVELY from IAM rather than from the session claim, which lags a key minted moments ago. No secret material comes back: a secret key is represented by its prefix, and only a publishable key (public by construction) carries its full value.  A transient IAM read failure reports an empty set rather than a 5xx, so the page shows the honest empty state and never a fabricated key.
283pub async fn get_account_keys(configuration: &configuration::Configuration, ) -> Result<models::ApiKeyList, Error<GetAccountKeysError>> {
284
285    let uri_str = format!("{}/v1/account/keys", configuration.base_path);
286    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
287
288    if let Some(ref user_agent) = configuration.user_agent {
289        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
290    }
291    if let Some(ref token) = configuration.bearer_access_token {
292        req_builder = req_builder.bearer_auth(token.to_owned());
293    };
294
295    let req = req_builder.build()?;
296    let resp = configuration.client.execute(req).await?;
297
298    let status = resp.status();
299    let content_type = resp
300        .headers()
301        .get("content-type")
302        .and_then(|v| v.to_str().ok())
303        .unwrap_or("application/octet-stream");
304    let content_type = super::ContentType::from(content_type);
305
306    if !status.is_client_error() && !status.is_server_error() {
307        let content = resp.text().await?;
308        match content_type {
309            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
310            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::ApiKeyList`"))),
311            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::ApiKeyList`")))),
312        }
313    } else {
314        let content = resp.text().await?;
315        let entity: Option<GetAccountKeysError> = serde_json::from_str(&content).ok();
316        Err(Error::ResponseError(ResponseContent { status, content, entity }))
317    }
318}
319
320/// Stores the caller's appearance preference on their IAM account, preserving every other field of the row. The accent is validated as a real colour token before it is stored; an unset or invalid axis is dropped rather than stored.
321pub async fn post_account_appearance(configuration: &configuration::Configuration, appearance: models::Appearance) -> Result<models::Appearance, Error<PostAccountAppearanceError>> {
322    // add a prefix to parameters to efficiently prevent name collisions
323    let p_appearance = appearance;
324
325    let uri_str = format!("{}/v1/account/appearance", configuration.base_path);
326    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
327
328    if let Some(ref user_agent) = configuration.user_agent {
329        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
330    }
331    if let Some(ref token) = configuration.bearer_access_token {
332        req_builder = req_builder.bearer_auth(token.to_owned());
333    };
334    req_builder = req_builder.json(&p_appearance);
335
336    let req = req_builder.build()?;
337    let resp = configuration.client.execute(req).await?;
338
339    let status = resp.status();
340    let content_type = resp
341        .headers()
342        .get("content-type")
343        .and_then(|v| v.to_str().ok())
344        .unwrap_or("application/octet-stream");
345    let content_type = super::ContentType::from(content_type);
346
347    if !status.is_client_error() && !status.is_server_error() {
348        let content = resp.text().await?;
349        match content_type {
350            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
351            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::Appearance`"))),
352            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::Appearance`")))),
353        }
354    } else {
355        let content = resp.text().await?;
356        let entity: Option<PostAccountAppearanceError> = serde_json::from_str(&content).ok();
357        Err(Error::ResponseError(ResponseContent { status, content, entity }))
358    }
359}
360
361/// Stores one image as the signed-in user's profile photo and answers the URL it is served from, which is also written to the user's IAM record — so every surface that already renders `avatar` picks it up with no further call.  The body is a multipart form with a `file` part. The format is decided by the BYTES, never the filename or the part's Content-Type: png, jpeg, gif and webp are accepted and everything else is refused with 415, so an SVG cannot be stored as a picture and later served as a program. Over 8 MiB is 413; empty is 400.  The photo is addressed by the sha256 of its bytes, so setting a new one yields a new URL rather than a stale cache of the old face. The caller is taken from the validated identity ONLY — there is no way to name a different subject — so this always sets your own photo, and a caller with no organization yet is refused.
362pub async fn post_account_avatar(configuration: &configuration::Configuration, ) -> Result<(), Error<PostAccountAvatarError>> {
363
364    let uri_str = format!("{}/v1/account/avatar", configuration.base_path);
365    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
366
367    if let Some(ref user_agent) = configuration.user_agent {
368        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
369    }
370    if let Some(ref token) = configuration.bearer_access_token {
371        req_builder = req_builder.bearer_auth(token.to_owned());
372    };
373
374    let req = req_builder.build()?;
375    let resp = configuration.client.execute(req).await?;
376
377    let status = resp.status();
378
379    if !status.is_client_error() && !status.is_server_error() {
380        Ok(())
381    } else {
382        let content = resp.text().await?;
383        let entity: Option<PostAccountAvatarError> = serde_json::from_str(&content).ok();
384        Err(Error::ResponseError(ResponseContent { status, content, entity }))
385    }
386}
387
388/// Creates — or rotates — the caller's API key of the requested type and returns it ONCE. A real IAM failure surfaces as 502, never a fabricated key.  Rotating is what creating means here: a user holds one key per type, so the endpoint is idempotent by (caller, type) and the superseded credential stops working. Two live secrets for one user would make \"revoke my key\" a lie.
389pub async fn post_account_keys(configuration: &configuration::Configuration, key_type_in: models::KeyTypeIn) -> Result<models::MintedKey, Error<PostAccountKeysError>> {
390    // add a prefix to parameters to efficiently prevent name collisions
391    let p_key_type_in = key_type_in;
392
393    let uri_str = format!("{}/v1/account/keys", configuration.base_path);
394    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
395
396    if let Some(ref user_agent) = configuration.user_agent {
397        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
398    }
399    if let Some(ref token) = configuration.bearer_access_token {
400        req_builder = req_builder.bearer_auth(token.to_owned());
401    };
402    req_builder = req_builder.json(&p_key_type_in);
403
404    let req = req_builder.build()?;
405    let resp = configuration.client.execute(req).await?;
406
407    let status = resp.status();
408    let content_type = resp
409        .headers()
410        .get("content-type")
411        .and_then(|v| v.to_str().ok())
412        .unwrap_or("application/octet-stream");
413    let content_type = super::ContentType::from(content_type);
414
415    if !status.is_client_error() && !status.is_server_error() {
416        let content = resp.text().await?;
417        match content_type {
418            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
419            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::MintedKey`"))),
420            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::MintedKey`")))),
421        }
422    } else {
423        let content = resp.text().await?;
424        let entity: Option<PostAccountKeysError> = serde_json::from_str(&content).ok();
425        Err(Error::ResponseError(ResponseContent { status, content, entity }))
426    }
427}
428
429/// Onboard creates the caller's organization. Two flows, keyed on whether the caller already has a home org (mirrors app/onboard/route.ts):    - FIRST-RUN (no home org): create + MOVE the user in as admin, so their next     JWT carries the new owner and the cloud scopes everything to it. This is the     path a fresh OAuth sign-up takes, from the sign-up application's org.   - ADDITIONAL (owner set): create the org but do NOT move the user — a move     changes their IAM owner (stripping a SuperAdmin's status + orphaning their     current org). They reach the new org via the OrgSwitcher, which re-scopes     X-Org-Id without touching IAM membership. A personal-org request from someone     who already has an org is meaningless → 409.
430pub async fn post_account_orgs(configuration: &configuration::Configuration, onboard_req: models::OnboardReq) -> Result<models::OnboardResp, Error<PostAccountOrgsError>> {
431    // add a prefix to parameters to efficiently prevent name collisions
432    let p_onboard_req = onboard_req;
433
434    let uri_str = format!("{}/v1/account/orgs", configuration.base_path);
435    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
436
437    if let Some(ref user_agent) = configuration.user_agent {
438        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
439    }
440    if let Some(ref token) = configuration.bearer_access_token {
441        req_builder = req_builder.bearer_auth(token.to_owned());
442    };
443    req_builder = req_builder.json(&p_onboard_req);
444
445    let req = req_builder.build()?;
446    let resp = configuration.client.execute(req).await?;
447
448    let status = resp.status();
449    let content_type = resp
450        .headers()
451        .get("content-type")
452        .and_then(|v| v.to_str().ok())
453        .unwrap_or("application/octet-stream");
454    let content_type = super::ContentType::from(content_type);
455
456    if !status.is_client_error() && !status.is_server_error() {
457        let content = resp.text().await?;
458        match content_type {
459            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
460            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::OnboardResp`"))),
461            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::OnboardResp`")))),
462        }
463    } else {
464        let content = resp.text().await?;
465        let entity: Option<PostAccountOrgsError> = serde_json::from_str(&content).ok();
466        Err(Error::ResponseError(ResponseContent { status, content, entity }))
467    }
468}
469