Skip to main content

hanzo_client/apis/
domain_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 [`get_domain_availability`]
19#[derive(Debug, Clone, Serialize, Deserialize)]
20#[serde(untagged)]
21pub enum GetDomainAvailabilityError {
22    UnknownValue(serde_json::Value),
23}
24
25/// struct for typed errors of method [`get_domain_domains`]
26#[derive(Debug, Clone, Serialize, Deserialize)]
27#[serde(untagged)]
28pub enum GetDomainDomainsError {
29    UnknownValue(serde_json::Value),
30}
31
32/// struct for typed errors of method [`get_domain_health`]
33#[derive(Debug, Clone, Serialize, Deserialize)]
34#[serde(untagged)]
35pub enum GetDomainHealthError {
36    Status503(models::Reachability),
37    UnknownValue(serde_json::Value),
38}
39
40/// struct for typed errors of method [`get_domain_search`]
41#[derive(Debug, Clone, Serialize, Deserialize)]
42#[serde(untagged)]
43pub enum GetDomainSearchError {
44    UnknownValue(serde_json::Value),
45}
46
47/// struct for typed errors of method [`post_domain_register`]
48#[derive(Debug, Clone, Serialize, Deserialize)]
49#[serde(untagged)]
50pub enum PostDomainRegisterError {
51    UnknownValue(serde_json::Value),
52}
53
54/// struct for typed errors of method [`post_domain_renew`]
55#[derive(Debug, Clone, Serialize, Deserialize)]
56#[serde(untagged)]
57pub enum PostDomainRenewError {
58    UnknownValue(serde_json::Value),
59}
60
61/// struct for typed errors of method [`post_domain_transfer`]
62#[derive(Debug, Clone, Serialize, Deserialize)]
63#[serde(untagged)]
64pub enum PostDomainTransferError {
65    UnknownValue(serde_json::Value),
66}
67
68
69/// Checks exact names rather than searching for them, and answers the same quote shape search does — purchasable, premium, first-term and renewal price in cents.  It requires a validated principal; 403 without one. Nothing is charged and nothing is held. A deployment with no registrar credentials answers 503.
70pub async fn get_domain_availability(configuration: &configuration::Configuration, domain: &str) -> Result<models::QuoteList, Error<GetDomainAvailabilityError>> {
71    // add a prefix to parameters to efficiently prevent name collisions
72    let p_domain = domain;
73
74    let uri_str = format!("{}/v1/domain/availability", configuration.base_path);
75    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
76
77    req_builder = req_builder.query(&[("domain", &p_domain.to_string())]);
78    if let Some(ref user_agent) = configuration.user_agent {
79        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
80    }
81    if let Some(ref token) = configuration.bearer_access_token {
82        req_builder = req_builder.bearer_auth(token.to_owned());
83    };
84
85    let req = req_builder.build()?;
86    let resp = configuration.client.execute(req).await?;
87
88    let status = resp.status();
89    let content_type = resp
90        .headers()
91        .get("content-type")
92        .and_then(|v| v.to_str().ok())
93        .unwrap_or("application/octet-stream");
94    let content_type = super::ContentType::from(content_type);
95
96    if !status.is_client_error() && !status.is_server_error() {
97        let content = resp.text().await?;
98        match content_type {
99            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
100            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::QuoteList`"))),
101            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::QuoteList`")))),
102        }
103    } else {
104        let content = resp.text().await?;
105        let entity: Option<GetDomainAvailabilityError> = serde_json::from_str(&content).ok();
106        Err(Error::ResponseError(ResponseContent { status, content, entity }))
107    }
108}
109
110/// Is the domains your org has bought here, newest registration first, each carrying the name, when it was registered, when it expires, what the org paid, the registrar order id and the nameservers it points at.  Scoped to the validated principal's org — 403 without one, and there is no parameter that reaches another org's holdings.  This is the deployment's OWN ownership record, not a query to the registrar: it lists what was bought THROUGH this surface, so a domain the org holds elsewhere is not here. The default store is in-process, so a deployment that has not swapped in a durable store answers from what this process registered.
111pub async fn get_domain_domains(configuration: &configuration::Configuration, ) -> Result<models::Holdings, Error<GetDomainDomainsError>> {
112
113    let uri_str = format!("{}/v1/domain/domains", configuration.base_path);
114    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
115
116    if let Some(ref user_agent) = configuration.user_agent {
117        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
118    }
119    if let Some(ref token) = configuration.bearer_access_token {
120        req_builder = req_builder.bearer_auth(token.to_owned());
121    };
122
123    let req = req_builder.build()?;
124    let resp = configuration.client.execute(req).await?;
125
126    let status = resp.status();
127    let content_type = resp
128        .headers()
129        .get("content-type")
130        .and_then(|v| v.to_str().ok())
131        .unwrap_or("application/octet-stream");
132    let content_type = super::ContentType::from(content_type);
133
134    if !status.is_client_error() && !status.is_server_error() {
135        let content = resp.text().await?;
136        match content_type {
137            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
138            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::Holdings`"))),
139            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::Holdings`")))),
140        }
141    } else {
142        let content = resp.text().await?;
143        let entity: Option<GetDomainDomainsError> = serde_json::from_str(&content).ok();
144        Err(Error::ResponseError(ResponseContent { status, content, entity }))
145    }
146}
147
148/// Reports registrar reachability honestly: ok only when the wholesale credentials are present AND name.com accepted them on a live call made while you waited.  Missing credentials or an unreachable registrar is 503 carrying configured, reachable and the reason, so an operator reads the blocker instead of guessing at it. It takes no principal, like every subsystem health probe.
149pub async fn get_domain_health(configuration: &configuration::Configuration, ) -> Result<models::Reachability, Error<GetDomainHealthError>> {
150
151    let uri_str = format!("{}/v1/domain/health", configuration.base_path);
152    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
153
154    if let Some(ref user_agent) = configuration.user_agent {
155        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
156    }
157    if let Some(ref token) = configuration.bearer_access_token {
158        req_builder = req_builder.bearer_auth(token.to_owned());
159    };
160
161    let req = req_builder.build()?;
162    let resp = configuration.client.execute(req).await?;
163
164    let status = resp.status();
165    let content_type = resp
166        .headers()
167        .get("content-type")
168        .and_then(|v| v.to_str().ok())
169        .unwrap_or("application/octet-stream");
170    let content_type = super::ContentType::from(content_type);
171
172    if !status.is_client_error() && !status.is_server_error() {
173        let content = resp.text().await?;
174        match content_type {
175            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
176            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::Reachability`"))),
177            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::Reachability`")))),
178        }
179    } else {
180        let content = resp.text().await?;
181        let entity: Option<GetDomainHealthError> = serde_json::from_str(&content).ok();
182        Err(Error::ResponseError(ResponseContent { status, content, entity }))
183    }
184}
185
186/// Finds names built from the keyword q, plus the registrar's alternate-TLD suggestions, and answers a quote for each: the name, whether it is purchasable, whether it is premium, the first-term and renewal price in cents, and the TLD.  Prices are RETAIL — this deployment's markup is already applied and the wholesale cost is never on the wire.  It requires a validated principal; 403 without one. Nothing is charged and nothing is held — a quote is not a reservation, and the price is re-quoted at purchase, so a name quoted here can be gone or dearer by the time you buy it. A deployment with no registrar credentials answers 503.
187pub async fn get_domain_search(configuration: &configuration::Configuration, q: &str, tld: Option<&str>) -> Result<models::QuoteList, Error<GetDomainSearchError>> {
188    // add a prefix to parameters to efficiently prevent name collisions
189    let p_q = q;
190    let p_tld = tld;
191
192    let uri_str = format!("{}/v1/domain/search", configuration.base_path);
193    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
194
195    req_builder = req_builder.query(&[("q", &p_q.to_string())]);
196    if let Some(ref param_value) = p_tld {
197        req_builder = req_builder.query(&[("tld", &param_value.to_string())]);
198    }
199    if let Some(ref user_agent) = configuration.user_agent {
200        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
201    }
202    if let Some(ref token) = configuration.bearer_access_token {
203        req_builder = req_builder.bearer_auth(token.to_owned());
204    };
205
206    let req = req_builder.build()?;
207    let resp = configuration.client.execute(req).await?;
208
209    let status = resp.status();
210    let content_type = resp
211        .headers()
212        .get("content-type")
213        .and_then(|v| v.to_str().ok())
214        .unwrap_or("application/octet-stream");
215    let content_type = super::ContentType::from(content_type);
216
217    if !status.is_client_error() && !status.is_server_error() {
218        let content = resp.text().await?;
219        match content_type {
220            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
221            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::QuoteList`"))),
222            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::QuoteList`")))),
223        }
224    } else {
225        let content = resp.text().await?;
226        let entity: Option<GetDomainSearchError> = serde_json::from_str(&content).ok();
227        Err(Error::ResponseError(ResponseContent { status, content, entity }))
228    }
229}
230
231/// Buys a domain for your org and answers the ownership record together with the quote it was bought at.  The order of operations is the product guarantee: quote, refuse anything unpurchasable or unpriced, AUTHORIZE the org's prepaid balance, provision the authoritative zone in Hanzo DNS, register at the registrar already pointing at Hanzo's nameservers, and only then CAPTURE the charge and record ownership. A registrar failure therefore leaves the balance untouched — the org is never billed for a domain it did not get.  It requires a validated principal; that principal's org owns the domain and is the ledger the charge lands on. Re-buying a name the org already holds is 409, not a second purchase.  Refusals are distinct on purpose: 402 when the prepaid balance cannot cover the quoted price, 409 when the name is not available, 503 when the deployment has no registrar credentials, and the registrar's own message with its own 4xx — or 502 for its 5xx — when it rejects the purchase. Zone provisioning is best-effort: if the zone service is down the domain is still registered against Hanzo's nameservers and the zone reconciles afterwards, rather than the purchase failing.
232pub async fn post_domain_register(configuration: &configuration::Configuration, order: models::Order) -> Result<models::RegisterResult, Error<PostDomainRegisterError>> {
233    // add a prefix to parameters to efficiently prevent name collisions
234    let p_order = order;
235
236    let uri_str = format!("{}/v1/domain/register", configuration.base_path);
237    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
238
239    if let Some(ref user_agent) = configuration.user_agent {
240        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
241    }
242    if let Some(ref token) = configuration.bearer_access_token {
243        req_builder = req_builder.bearer_auth(token.to_owned());
244    };
245    req_builder = req_builder.json(&p_order);
246
247    let req = req_builder.build()?;
248    let resp = configuration.client.execute(req).await?;
249
250    let status = resp.status();
251    let content_type = resp
252        .headers()
253        .get("content-type")
254        .and_then(|v| v.to_str().ok())
255        .unwrap_or("application/octet-stream");
256    let content_type = super::ContentType::from(content_type);
257
258    if !status.is_client_error() && !status.is_server_error() {
259        let content = resp.text().await?;
260        match content_type {
261            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
262            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::RegisterResult`"))),
263            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::RegisterResult`")))),
264        }
265    } else {
266        let content = resp.text().await?;
267        let entity: Option<PostDomainRegisterError> = serde_json::from_str(&content).ok();
268        Err(Error::ResponseError(ResponseContent { status, content, entity }))
269    }
270}
271
272/// Extends a domain your org already owns and answers the updated record with its new expiry alongside what was paid.  Ownership is the gate: a name the caller's org does not hold is 404, so a renewal can never reach another tenant's domain.  The price is re-quoted at the CURRENT renewal rate rather than the one paid at purchase. If the registrar returns no renewal price the org's original price is charged instead, so a renewal is never accidentally free. The balance is authorized before the registrar is called and captured after it confirms — 402 when the prepaid balance cannot cover it, 503 when the deployment has no registrar credentials. Requires a validated principal.
273pub async fn post_domain_renew(configuration: &configuration::Configuration, renew_req: models::RenewReq) -> Result<models::RenewResult, Error<PostDomainRenewError>> {
274    // add a prefix to parameters to efficiently prevent name collisions
275    let p_renew_req = renew_req;
276
277    let uri_str = format!("{}/v1/domain/renew", configuration.base_path);
278    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
279
280    if let Some(ref user_agent) = configuration.user_agent {
281        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
282    }
283    if let Some(ref token) = configuration.bearer_access_token {
284        req_builder = req_builder.bearer_auth(token.to_owned());
285    };
286    req_builder = req_builder.json(&p_renew_req);
287
288    let req = req_builder.build()?;
289    let resp = configuration.client.execute(req).await?;
290
291    let status = resp.status();
292    let content_type = resp
293        .headers()
294        .get("content-type")
295        .and_then(|v| v.to_str().ok())
296        .unwrap_or("application/octet-stream");
297    let content_type = super::ContentType::from(content_type);
298
299    if !status.is_client_error() && !status.is_server_error() {
300        let content = resp.text().await?;
301        match content_type {
302            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
303            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::RenewResult`"))),
304            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::RenewResult`")))),
305        }
306    } else {
307        let content = resp.text().await?;
308        let entity: Option<PostDomainRenewError> = serde_json::from_str(&content).ok();
309        Err(Error::ResponseError(ResponseContent { status, content, entity }))
310    }
311}
312
313/// Moves a domain you own at another registrar onto your org here, using its authCode, and answers the same record-plus-quote a purchase does.  It is priced and charged exactly like a registration: authorize the org's prepaid balance, ask the registrar for the transfer, capture only after the registrar accepts. A name the registrar will not price is 409, an insufficient balance is 402, and a deployment with no registrar credentials is 503.  It requires a validated principal; the ownership record is written under that org as soon as the registrar ACCEPTS the request, which is not the same instant the transfer completes at the losing registrar. Unlike a registration this does not provision a zone, so the record carries this deployment's configured nameservers.
314pub async fn post_domain_transfer(configuration: &configuration::Configuration, transfer_req: models::TransferReq) -> Result<models::RegisterResult, Error<PostDomainTransferError>> {
315    // add a prefix to parameters to efficiently prevent name collisions
316    let p_transfer_req = transfer_req;
317
318    let uri_str = format!("{}/v1/domain/transfer", configuration.base_path);
319    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
320
321    if let Some(ref user_agent) = configuration.user_agent {
322        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
323    }
324    if let Some(ref token) = configuration.bearer_access_token {
325        req_builder = req_builder.bearer_auth(token.to_owned());
326    };
327    req_builder = req_builder.json(&p_transfer_req);
328
329    let req = req_builder.build()?;
330    let resp = configuration.client.execute(req).await?;
331
332    let status = resp.status();
333    let content_type = resp
334        .headers()
335        .get("content-type")
336        .and_then(|v| v.to_str().ok())
337        .unwrap_or("application/octet-stream");
338    let content_type = super::ContentType::from(content_type);
339
340    if !status.is_client_error() && !status.is_server_error() {
341        let content = resp.text().await?;
342        match content_type {
343            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
344            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::RegisterResult`"))),
345            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::RegisterResult`")))),
346        }
347    } else {
348        let content = resp.text().await?;
349        let entity: Option<PostDomainTransferError> = serde_json::from_str(&content).ok();
350        Err(Error::ResponseError(ResponseContent { status, content, entity }))
351    }
352}
353