Skip to main content

late/apis/
phone_numbers_api.rs

1/*
2 * Zernio API
3 *
4 * API reference for Zernio. Authenticate with a Bearer API key. Base URL: https://zernio.com/api
5 *
6 * The version of the OpenAPI document: 1.0.4
7 * Contact: support@zernio.com
8 * Generated by: https://openapi-generator.tech
9 */
10
11use super::{configuration, ContentType, Error};
12use crate::{apis::ResponseContent, models};
13use reqwest;
14use serde::{de::Error as _, Deserialize, Serialize};
15use tokio::fs::File as TokioFile;
16use tokio_util::codec::{BytesCodec, FramedRead};
17
18/// struct for typed errors of method [`cancel_phone_number_port_in`]
19#[derive(Debug, Clone, Serialize, Deserialize)]
20#[serde(untagged)]
21pub enum CancelPhoneNumberPortInError {
22    Status401(models::InlineObject),
23    Status404(),
24    Status409(),
25    UnknownValue(serde_json::Value),
26}
27
28/// struct for typed errors of method [`check_phone_number_availability`]
29#[derive(Debug, Clone, Serialize, Deserialize)]
30#[serde(untagged)]
31pub enum CheckPhoneNumberAvailabilityError {
32    Status400(),
33    Status401(models::InlineObject),
34    UnknownValue(serde_json::Value),
35}
36
37/// struct for typed errors of method [`check_phone_number_portability`]
38#[derive(Debug, Clone, Serialize, Deserialize)]
39#[serde(untagged)]
40pub enum CheckPhoneNumberPortabilityError {
41    Status401(models::InlineObject),
42    UnknownValue(serde_json::Value),
43}
44
45/// struct for typed errors of method [`create_phone_number_kyc_link`]
46#[derive(Debug, Clone, Serialize, Deserialize)]
47#[serde(untagged)]
48pub enum CreatePhoneNumberKycLinkError {
49    Status400(),
50    Status401(models::InlineObject),
51    UnknownValue(serde_json::Value),
52}
53
54/// struct for typed errors of method [`create_phone_number_port_in`]
55#[derive(Debug, Clone, Serialize, Deserialize)]
56#[serde(untagged)]
57pub enum CreatePhoneNumberPortInError {
58    Status401(models::InlineObject),
59    Status409(),
60    Status422(),
61    UnknownValue(serde_json::Value),
62}
63
64/// struct for typed errors of method [`get_phone_number`]
65#[derive(Debug, Clone, Serialize, Deserialize)]
66#[serde(untagged)]
67pub enum GetPhoneNumberError {
68    Status401(models::InlineObject),
69    Status404(models::InlineObject1),
70    UnknownValue(serde_json::Value),
71}
72
73/// struct for typed errors of method [`get_phone_number_kyc_form`]
74#[derive(Debug, Clone, Serialize, Deserialize)]
75#[serde(untagged)]
76pub enum GetPhoneNumberKycFormError {
77    Status400(),
78    Status401(models::InlineObject),
79    UnknownValue(serde_json::Value),
80}
81
82/// struct for typed errors of method [`get_phone_number_remediation`]
83#[derive(Debug, Clone, Serialize, Deserialize)]
84#[serde(untagged)]
85pub enum GetPhoneNumberRemediationError {
86    Status400(),
87    Status401(models::InlineObject),
88    Status404(),
89    UnknownValue(serde_json::Value),
90}
91
92/// struct for typed errors of method [`list_phone_number_countries`]
93#[derive(Debug, Clone, Serialize, Deserialize)]
94#[serde(untagged)]
95pub enum ListPhoneNumberCountriesError {
96    Status401(models::InlineObject),
97    UnknownValue(serde_json::Value),
98}
99
100/// struct for typed errors of method [`list_phone_number_port_ins`]
101#[derive(Debug, Clone, Serialize, Deserialize)]
102#[serde(untagged)]
103pub enum ListPhoneNumberPortInsError {
104    Status401(models::InlineObject),
105    UnknownValue(serde_json::Value),
106}
107
108/// struct for typed errors of method [`list_phone_numbers`]
109#[derive(Debug, Clone, Serialize, Deserialize)]
110#[serde(untagged)]
111pub enum ListPhoneNumbersError {
112    Status401(models::InlineObject),
113    UnknownValue(serde_json::Value),
114}
115
116/// struct for typed errors of method [`purchase_phone_number`]
117#[derive(Debug, Clone, Serialize, Deserialize)]
118#[serde(untagged)]
119pub enum PurchasePhoneNumberError {
120    Status400(),
121    Status401(models::InlineObject),
122    Status403(),
123    Status409(models::PurchasePhoneNumber409Response),
124    Status402(),
125    Status422(),
126    UnknownValue(serde_json::Value),
127}
128
129/// struct for typed errors of method [`release_phone_number`]
130#[derive(Debug, Clone, Serialize, Deserialize)]
131#[serde(untagged)]
132pub enum ReleasePhoneNumberError {
133    Status400(),
134    Status401(models::InlineObject),
135    Status404(models::InlineObject1),
136    UnknownValue(serde_json::Value),
137}
138
139/// struct for typed errors of method [`remediate_phone_number`]
140#[derive(Debug, Clone, Serialize, Deserialize)]
141#[serde(untagged)]
142pub enum RemediatePhoneNumberError {
143    Status400(),
144    Status401(models::InlineObject),
145    Status404(),
146    UnknownValue(serde_json::Value),
147}
148
149/// struct for typed errors of method [`review_phone_number_kyc_packet`]
150#[derive(Debug, Clone, Serialize, Deserialize)]
151#[serde(untagged)]
152pub enum ReviewPhoneNumberKycPacketError {
153    Status401(models::InlineObject),
154    UnknownValue(serde_json::Value),
155}
156
157/// struct for typed errors of method [`search_available_phone_numbers`]
158#[derive(Debug, Clone, Serialize, Deserialize)]
159#[serde(untagged)]
160pub enum SearchAvailablePhoneNumbersError {
161    Status400(),
162    Status401(models::InlineObject),
163    UnknownValue(serde_json::Value),
164}
165
166/// struct for typed errors of method [`submit_phone_number_kyc`]
167#[derive(Debug, Clone, Serialize, Deserialize)]
168#[serde(untagged)]
169pub enum SubmitPhoneNumberKycError {
170    Status400(),
171    Status409(),
172    Status401(models::InlineObject),
173    UnknownValue(serde_json::Value),
174}
175
176/// struct for typed errors of method [`upload_phone_number_kyc_document`]
177#[derive(Debug, Clone, Serialize, Deserialize)]
178#[serde(untagged)]
179pub enum UploadPhoneNumberKycDocumentError {
180    Status400(),
181    Status401(models::InlineObject),
182    UnknownValue(serde_json::Value),
183}
184
185/// struct for typed errors of method [`upload_phone_number_port_in_document`]
186#[derive(Debug, Clone, Serialize, Deserialize)]
187#[serde(untagged)]
188pub enum UploadPhoneNumberPortInDocumentError {
189    Status400(),
190    Status401(models::InlineObject),
191    UnknownValue(serde_json::Value),
192}
193
194/// struct for typed errors of method [`validate_phone_number_kyc_address`]
195#[derive(Debug, Clone, Serialize, Deserialize)]
196#[serde(untagged)]
197pub enum ValidatePhoneNumberKycAddressError {
198    Status400(models::ValidatePhoneNumberKycAddress400Response),
199    Status401(models::InlineObject),
200    UnknownValue(serde_json::Value),
201}
202
203/// Cancel an in-flight port (wrong number, staying with the old carrier). Only orders that haven't ported can be cancelled; a completed port is a normal number release instead. The carrier may report `cancel-pending` briefly while the losing carrier acknowledges; it settles to `cancelled`.
204pub async fn cancel_phone_number_port_in(
205    configuration: &configuration::Configuration,
206    id: &str,
207) -> Result<models::CancelPhoneNumberPortIn200Response, Error<CancelPhoneNumberPortInError>> {
208    // add a prefix to parameters to efficiently prevent name collisions
209    let p_path_id = id;
210
211    let uri_str = format!(
212        "{}/v1/phone-numbers/port-in/{id}",
213        configuration.base_path,
214        id = crate::apis::urlencode(p_path_id)
215    );
216    let mut req_builder = configuration
217        .client
218        .request(reqwest::Method::DELETE, &uri_str);
219
220    if let Some(ref user_agent) = configuration.user_agent {
221        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
222    }
223    if let Some(ref token) = configuration.bearer_access_token {
224        req_builder = req_builder.bearer_auth(token.to_owned());
225    };
226
227    let req = req_builder.build()?;
228    let resp = configuration.client.execute(req).await?;
229
230    let status = resp.status();
231    let content_type = resp
232        .headers()
233        .get("content-type")
234        .and_then(|v| v.to_str().ok())
235        .unwrap_or("application/octet-stream");
236    let content_type = super::ContentType::from(content_type);
237
238    if !status.is_client_error() && !status.is_server_error() {
239        let content = resp.text().await?;
240        match content_type {
241            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
242            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::CancelPhoneNumberPortIn200Response`"))),
243            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::CancelPhoneNumberPortIn200Response`")))),
244        }
245    } else {
246        let content = resp.text().await?;
247        let entity: Option<CancelPhoneNumberPortInError> = serde_json::from_str(&content).ok();
248        Err(Error::ResponseError(ResponseContent {
249            status,
250            content,
251            entity,
252        }))
253    }
254}
255
256/// Pre-purchase check, so you can warn BEFORE a customer invests in KYC (regulated review is async, 1-3 days). Tells you whether we have deliverable inventory, and what address the customer needs:   - `addressConstraint: geo`  → the registered address MUST be in one of     the returned `areas` (the only place we have stock). A different-area     address passes pre-approval but the number can never be assigned.   - `addressConstraint: country` → any in-country address works.   - `addressConstraint: none` → field-only / instant country, no address. Call this before starting the KYC form for regulated countries.
257pub async fn check_phone_number_availability(
258    configuration: &configuration::Configuration,
259    country: &str,
260) -> Result<models::CheckPhoneNumberAvailability200Response, Error<CheckPhoneNumberAvailabilityError>>
261{
262    // add a prefix to parameters to efficiently prevent name collisions
263    let p_query_country = country;
264
265    let uri_str = format!("{}/v1/phone-numbers/availability", configuration.base_path);
266    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
267
268    req_builder = req_builder.query(&[("country", &p_query_country.to_string())]);
269    if let Some(ref user_agent) = configuration.user_agent {
270        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
271    }
272    if let Some(ref token) = configuration.bearer_access_token {
273        req_builder = req_builder.bearer_auth(token.to_owned());
274    };
275
276    let req = req_builder.build()?;
277    let resp = configuration.client.execute(req).await?;
278
279    let status = resp.status();
280    let content_type = resp
281        .headers()
282        .get("content-type")
283        .and_then(|v| v.to_str().ok())
284        .unwrap_or("application/octet-stream");
285    let content_type = super::ContentType::from(content_type);
286
287    if !status.is_client_error() && !status.is_server_error() {
288        let content = resp.text().await?;
289        match content_type {
290            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
291            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::CheckPhoneNumberAvailability200Response`"))),
292            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::CheckPhoneNumberAvailability200Response`")))),
293        }
294    } else {
295        let content = resp.text().await?;
296        let entity: Option<CheckPhoneNumberAvailabilityError> = serde_json::from_str(&content).ok();
297        Err(Error::ResponseError(ResponseContent {
298            status,
299            content,
300            entity,
301        }))
302    }
303}
304
305/// Pre-flight portability check: whether each number can be ported in and whether it qualifies for FastPort, BEFORE the user commits to a port order (LOA, invoice, service address). Read-only; creates no order and bills nothing.
306pub async fn check_phone_number_portability(
307    configuration: &configuration::Configuration,
308    check_phone_number_portability_request: models::CheckPhoneNumberPortabilityRequest,
309) -> Result<models::CheckPhoneNumberPortability200Response, Error<CheckPhoneNumberPortabilityError>>
310{
311    // add a prefix to parameters to efficiently prevent name collisions
312    let p_body_check_phone_number_portability_request = check_phone_number_portability_request;
313
314    let uri_str = format!("{}/v1/phone-numbers/port-in/check", configuration.base_path);
315    let mut req_builder = configuration
316        .client
317        .request(reqwest::Method::POST, &uri_str);
318
319    if let Some(ref user_agent) = configuration.user_agent {
320        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
321    }
322    if let Some(ref token) = configuration.bearer_access_token {
323        req_builder = req_builder.bearer_auth(token.to_owned());
324    };
325    req_builder = req_builder.json(&p_body_check_phone_number_portability_request);
326
327    let req = req_builder.build()?;
328    let resp = configuration.client.execute(req).await?;
329
330    let status = resp.status();
331    let content_type = resp
332        .headers()
333        .get("content-type")
334        .and_then(|v| v.to_str().ok())
335        .unwrap_or("application/octet-stream");
336    let content_type = super::ContentType::from(content_type);
337
338    if !status.is_client_error() && !status.is_server_error() {
339        let content = resp.text().await?;
340        match content_type {
341            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
342            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::CheckPhoneNumberPortability200Response`"))),
343            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::CheckPhoneNumberPortability200Response`")))),
344        }
345    } else {
346        let content = resp.text().await?;
347        let entity: Option<CheckPhoneNumberPortabilityError> = serde_json::from_str(&content).ok();
348        Err(Error::ResponseError(ResponseContent {
349            status,
350            content,
351            entity,
352        }))
353    }
354}
355
356/// Create a single-use, 7-day hosted KYC link that your end customer completes WITHOUT a Zernio login — useful when the person who holds the ID and address is not your team. They fill the regulated verification on a Zernio-hosted page; the number provisions under YOUR account once they submit. Only regulated (KYC) countries are valid: a country that does not require KYC returns 400.  White-label the page with `branding` (your company name, logo, brand color). Supply `redirect_url` to send the end customer back to your own site after a successful submit (completion params are appended — see below). Listen for the `whatsapp.number.kyc_submitted` webhook to react when the form is completed.
357pub async fn create_phone_number_kyc_link(
358    configuration: &configuration::Configuration,
359    create_phone_number_kyc_link_request: models::CreatePhoneNumberKycLinkRequest,
360) -> Result<models::CreatePhoneNumberKycLink200Response, Error<CreatePhoneNumberKycLinkError>> {
361    // add a prefix to parameters to efficiently prevent name collisions
362    let p_body_create_phone_number_kyc_link_request = create_phone_number_kyc_link_request;
363
364    let uri_str = format!("{}/v1/phone-numbers/kyc/share", configuration.base_path);
365    let mut req_builder = configuration
366        .client
367        .request(reqwest::Method::POST, &uri_str);
368
369    if let Some(ref user_agent) = configuration.user_agent {
370        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
371    }
372    if let Some(ref token) = configuration.bearer_access_token {
373        req_builder = req_builder.bearer_auth(token.to_owned());
374    };
375    req_builder = req_builder.json(&p_body_create_phone_number_kyc_link_request);
376
377    let req = req_builder.build()?;
378    let resp = configuration.client.execute(req).await?;
379
380    let status = resp.status();
381    let content_type = resp
382        .headers()
383        .get("content-type")
384        .and_then(|v| v.to_str().ok())
385        .unwrap_or("application/octet-stream");
386    let content_type = super::ContentType::from(content_type);
387
388    if !status.is_client_error() && !status.is_server_error() {
389        let content = resp.text().await?;
390        match content_type {
391            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
392            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::CreatePhoneNumberKycLink200Response`"))),
393            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::CreatePhoneNumberKycLink200Response`")))),
394        }
395    } else {
396        let content = resp.text().await?;
397        let entity: Option<CreatePhoneNumberKycLinkError> = serde_json::from_str(&content).ok();
398        Err(Error::ResponseError(ResponseContent {
399            status,
400            content,
401            entity,
402        }))
403    }
404}
405
406/// Submit a port-in for one or more existing numbers from another carrier. Creates the carrier order(s), attaches the end-user (current account) info plus the LOA and invoice documents, and submits to the losing carrier. The transfer PIN is forwarded to the carrier and never stored. Ported numbers arrive voice-ready (and SMS-ready where the order supports messaging).  Run the portability check (POST /v1/phone-numbers/port-in/check) and upload the two documents (POST /v1/phone-numbers/port-in/documents) first. The carrier may split the numbers into several orders (by country, number type, losing carrier); `orders` carries per-order results, and a partial failure still returns 201 with the failed orders' `error` set (they stay as cancellable drafts).
407pub async fn create_phone_number_port_in(
408    configuration: &configuration::Configuration,
409    create_phone_number_port_in_request: models::CreatePhoneNumberPortInRequest,
410) -> Result<models::CreatePhoneNumberPortIn201Response, Error<CreatePhoneNumberPortInError>> {
411    // add a prefix to parameters to efficiently prevent name collisions
412    let p_body_create_phone_number_port_in_request = create_phone_number_port_in_request;
413
414    let uri_str = format!("{}/v1/phone-numbers/port-in", configuration.base_path);
415    let mut req_builder = configuration
416        .client
417        .request(reqwest::Method::POST, &uri_str);
418
419    if let Some(ref user_agent) = configuration.user_agent {
420        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
421    }
422    if let Some(ref token) = configuration.bearer_access_token {
423        req_builder = req_builder.bearer_auth(token.to_owned());
424    };
425    req_builder = req_builder.json(&p_body_create_phone_number_port_in_request);
426
427    let req = req_builder.build()?;
428    let resp = configuration.client.execute(req).await?;
429
430    let status = resp.status();
431    let content_type = resp
432        .headers()
433        .get("content-type")
434        .and_then(|v| v.to_str().ok())
435        .unwrap_or("application/octet-stream");
436    let content_type = super::ContentType::from(content_type);
437
438    if !status.is_client_error() && !status.is_server_error() {
439        let content = resp.text().await?;
440        match content_type {
441            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
442            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::CreatePhoneNumberPortIn201Response`"))),
443            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::CreatePhoneNumberPortIn201Response`")))),
444        }
445    } else {
446        let content = resp.text().await?;
447        let entity: Option<CreatePhoneNumberPortInError> = serde_json::from_str(&content).ok();
448        Err(Error::ResponseError(ResponseContent {
449            status,
450            content,
451            entity,
452        }))
453    }
454}
455
456/// Retrieve the current status of a purchased phone number. Poll this to track Meta pre-verification (US sync path) and, for regulated (Tier 3/4) numbers, the async lifecycle: pending_regulatory → active (or regulatory_declined). When a regulated number has an Onfido ID step, `onfidoVerificationUrl` appears here once the order is placed — forward it to the end user. (Or subscribe to the whatsapp.number.* webhooks instead of polling.)
457pub async fn get_phone_number(
458    configuration: &configuration::Configuration,
459    id: &str,
460) -> Result<models::GetPhoneNumber200Response, Error<GetPhoneNumberError>> {
461    // add a prefix to parameters to efficiently prevent name collisions
462    let p_path_id = id;
463
464    let uri_str = format!(
465        "{}/v1/phone-numbers/{id}",
466        configuration.base_path,
467        id = crate::apis::urlencode(p_path_id)
468    );
469    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
470
471    if let Some(ref user_agent) = configuration.user_agent {
472        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
473    }
474    if let Some(ref token) = configuration.bearer_access_token {
475        req_builder = req_builder.bearer_auth(token.to_owned());
476    };
477
478    let req = req_builder.build()?;
479    let resp = configuration.client.execute(req).await?;
480
481    let status = resp.status();
482    let content_type = resp
483        .headers()
484        .get("content-type")
485        .and_then(|v| v.to_str().ok())
486        .unwrap_or("application/octet-stream");
487    let content_type = super::ContentType::from(content_type);
488
489    if !status.is_client_error() && !status.is_server_error() {
490        let content = resp.text().await?;
491        match content_type {
492            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
493            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::GetPhoneNumber200Response`"))),
494            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::GetPhoneNumber200Response`")))),
495        }
496    } else {
497        let content = resp.text().await?;
498        let entity: Option<GetPhoneNumberError> = serde_json::from_str(&content).ok();
499        Err(Error::ResponseError(ResponseContent {
500            status,
501            content,
502            entity,
503        }))
504    }
505}
506
507/// For a Tier 3/4 country, the fields the end customer must provide (Telnyx regulatory requirements) before a number can be ordered: text, date, address, or file (document) per requirement.
508pub async fn get_phone_number_kyc_form(
509    configuration: &configuration::Configuration,
510    country: &str,
511) -> Result<models::GetPhoneNumberKycForm200Response, Error<GetPhoneNumberKycFormError>> {
512    // add a prefix to parameters to efficiently prevent name collisions
513    let p_query_country = country;
514
515    let uri_str = format!("{}/v1/phone-numbers/kyc", configuration.base_path);
516    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
517
518    req_builder = req_builder.query(&[("country", &p_query_country.to_string())]);
519    if let Some(ref user_agent) = configuration.user_agent {
520        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
521    }
522    if let Some(ref token) = configuration.bearer_access_token {
523        req_builder = req_builder.bearer_auth(token.to_owned());
524    };
525
526    let req = req_builder.build()?;
527    let resp = configuration.client.execute(req).await?;
528
529    let status = resp.status();
530    let content_type = resp
531        .headers()
532        .get("content-type")
533        .and_then(|v| v.to_str().ok())
534        .unwrap_or("application/octet-stream");
535    let content_type = super::ContentType::from(content_type);
536
537    if !status.is_client_error() && !status.is_server_error() {
538        let content = resp.text().await?;
539        match content_type {
540            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
541            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::GetPhoneNumberKycForm200Response`"))),
542            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::GetPhoneNumberKycForm200Response`")))),
543        }
544    } else {
545        let content = resp.text().await?;
546        let entity: Option<GetPhoneNumberKycFormError> = serde_json::from_str(&content).ok();
547        Err(Error::ResponseError(ResponseContent {
548            status,
549            content,
550            entity,
551        }))
552    }
553}
554
555/// For a number in `regulatory_declined`, returns ONLY the requirements the reviewer flagged declined, as a form spec (same shape as the KYC form GET). The customer fixes just those — Telnyx supports correcting a declined requirement group and re-submitting it (no new number/group). Falls back to the full spec if the provider exposes no per-requirement flags.
556pub async fn get_phone_number_remediation(
557    configuration: &configuration::Configuration,
558    id: &str,
559) -> Result<models::GetPhoneNumberRemediation200Response, Error<GetPhoneNumberRemediationError>> {
560    // add a prefix to parameters to efficiently prevent name collisions
561    let p_path_id = id;
562
563    let uri_str = format!(
564        "{}/v1/phone-numbers/{id}/remediate",
565        configuration.base_path,
566        id = crate::apis::urlencode(p_path_id)
567    );
568    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
569
570    if let Some(ref user_agent) = configuration.user_agent {
571        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
572    }
573    if let Some(ref token) = configuration.bearer_access_token {
574        req_builder = req_builder.bearer_auth(token.to_owned());
575    };
576
577    let req = req_builder.build()?;
578    let resp = configuration.client.execute(req).await?;
579
580    let status = resp.status();
581    let content_type = resp
582        .headers()
583        .get("content-type")
584        .and_then(|v| v.to_str().ok())
585        .unwrap_or("application/octet-stream");
586    let content_type = super::ContentType::from(content_type);
587
588    if !status.is_client_error() && !status.is_server_error() {
589        let content = resp.text().await?;
590        match content_type {
591            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
592            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::GetPhoneNumberRemediation200Response`"))),
593            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::GetPhoneNumberRemediation200Response`")))),
594        }
595    } else {
596        let content = resp.text().await?;
597        let entity: Option<GetPhoneNumberRemediationError> = serde_json::from_str(&content).ok();
598        Err(Error::ResponseError(ResponseContent {
599            status,
600            content,
601            entity,
602        }))
603    }
604}
605
606/// The phone number countries available to purchase, each with its flat monthly price (cents), regulatory tier, whether it needs end-user KYC (Tier 3/4), and per-feature availability (PSTN calls, WhatsApp, SMS, and WhatsApp Business Calling outbound). Drives the country picker. Tier-4 countries appear only when enabled.
607pub async fn list_phone_number_countries(
608    configuration: &configuration::Configuration,
609) -> Result<models::ListPhoneNumberCountries200Response, Error<ListPhoneNumberCountriesError>> {
610    let uri_str = format!("{}/v1/phone-numbers/countries", configuration.base_path);
611    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
612
613    if let Some(ref user_agent) = configuration.user_agent {
614        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
615    }
616    if let Some(ref token) = configuration.bearer_access_token {
617        req_builder = req_builder.bearer_auth(token.to_owned());
618    };
619
620    let req = req_builder.build()?;
621    let resp = configuration.client.execute(req).await?;
622
623    let status = resp.status();
624    let content_type = resp
625        .headers()
626        .get("content-type")
627        .and_then(|v| v.to_str().ok())
628        .unwrap_or("application/octet-stream");
629    let content_type = super::ContentType::from(content_type);
630
631    if !status.is_client_error() && !status.is_server_error() {
632        let content = resp.text().await?;
633        match content_type {
634            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
635            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::ListPhoneNumberCountries200Response`"))),
636            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::ListPhoneNumberCountries200Response`")))),
637        }
638    } else {
639        let content = resp.text().await?;
640        let entity: Option<ListPhoneNumberCountriesError> = serde_json::from_str(&content).ok();
641        Err(Error::ResponseError(ResponseContent {
642            status,
643            content,
644            entity,
645        }))
646    }
647}
648
649/// Your porting orders, newest first (max 50). Poll this for port progress: pending, confirmed FOC date, exception reason, or ported.
650pub async fn list_phone_number_port_ins(
651    configuration: &configuration::Configuration,
652) -> Result<models::ListPhoneNumberPortIns200Response, Error<ListPhoneNumberPortInsError>> {
653    let uri_str = format!("{}/v1/phone-numbers/port-in", configuration.base_path);
654    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
655
656    if let Some(ref user_agent) = configuration.user_agent {
657        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
658    }
659    if let Some(ref token) = configuration.bearer_access_token {
660        req_builder = req_builder.bearer_auth(token.to_owned());
661    };
662
663    let req = req_builder.build()?;
664    let resp = configuration.client.execute(req).await?;
665
666    let status = resp.status();
667    let content_type = resp
668        .headers()
669        .get("content-type")
670        .and_then(|v| v.to_str().ok())
671        .unwrap_or("application/octet-stream");
672    let content_type = super::ContentType::from(content_type);
673
674    if !status.is_client_error() && !status.is_server_error() {
675        let content = resp.text().await?;
676        match content_type {
677            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
678            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::ListPhoneNumberPortIns200Response`"))),
679            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::ListPhoneNumberPortIns200Response`")))),
680        }
681    } else {
682        let content = resp.text().await?;
683        let entity: Option<ListPhoneNumberPortInsError> = serde_json::from_str(&content).ok();
684        Err(Error::ResponseError(ResponseContent {
685            status,
686            content,
687            entity,
688        }))
689    }
690}
691
692/// List all phone numbers purchased by the authenticated user. By default, released numbers are excluded. Connected (bring-your-own) WhatsApp numbers are returned in the separate `connected` array; they are not billed and have no provisioning lifecycle.
693pub async fn list_phone_numbers(
694    configuration: &configuration::Configuration,
695    status: Option<&str>,
696    profile_id: Option<&str>,
697) -> Result<models::ListPhoneNumbers200Response, Error<ListPhoneNumbersError>> {
698    // add a prefix to parameters to efficiently prevent name collisions
699    let p_query_status = status;
700    let p_query_profile_id = profile_id;
701
702    let uri_str = format!("{}/v1/phone-numbers", configuration.base_path);
703    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
704
705    if let Some(ref param_value) = p_query_status {
706        req_builder = req_builder.query(&[("status", &param_value.to_string())]);
707    }
708    if let Some(ref param_value) = p_query_profile_id {
709        req_builder = req_builder.query(&[("profileId", &param_value.to_string())]);
710    }
711    if let Some(ref user_agent) = configuration.user_agent {
712        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
713    }
714    if let Some(ref token) = configuration.bearer_access_token {
715        req_builder = req_builder.bearer_auth(token.to_owned());
716    };
717
718    let req = req_builder.build()?;
719    let resp = configuration.client.execute(req).await?;
720
721    let status = resp.status();
722    let content_type = resp
723        .headers()
724        .get("content-type")
725        .and_then(|v| v.to_str().ok())
726        .unwrap_or("application/octet-stream");
727    let content_type = super::ContentType::from(content_type);
728
729    if !status.is_client_error() && !status.is_server_error() {
730        let content = resp.text().await?;
731        match content_type {
732            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
733            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::ListPhoneNumbers200Response`"))),
734            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::ListPhoneNumbers200Response`")))),
735        }
736    } else {
737        let content = resp.text().await?;
738        let entity: Option<ListPhoneNumbersError> = serde_json::from_str(&content).ok();
739        Err(Error::ResponseError(ResponseContent {
740            status,
741            content,
742            entity,
743        }))
744    }
745}
746
747/// Initiate purchasing a phone number. Payment-first flow: the user does not pick a specific number. The system either creates a Stripe Checkout Session (first number) or increments the existing subscription quantity and provisions inline (subsequent numbers).  Requires a paid plan. The maximum number of phone numbers is determined by the user's plan.
748pub async fn purchase_phone_number(
749    configuration: &configuration::Configuration,
750    purchase_phone_number_request: models::PurchasePhoneNumberRequest,
751) -> Result<models::PurchasePhoneNumber200Response, Error<PurchasePhoneNumberError>> {
752    // add a prefix to parameters to efficiently prevent name collisions
753    let p_body_purchase_phone_number_request = purchase_phone_number_request;
754
755    let uri_str = format!("{}/v1/phone-numbers/purchase", configuration.base_path);
756    let mut req_builder = configuration
757        .client
758        .request(reqwest::Method::POST, &uri_str);
759
760    if let Some(ref user_agent) = configuration.user_agent {
761        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
762    }
763    if let Some(ref token) = configuration.bearer_access_token {
764        req_builder = req_builder.bearer_auth(token.to_owned());
765    };
766    req_builder = req_builder.json(&p_body_purchase_phone_number_request);
767
768    let req = req_builder.build()?;
769    let resp = configuration.client.execute(req).await?;
770
771    let status = resp.status();
772    let content_type = resp
773        .headers()
774        .get("content-type")
775        .and_then(|v| v.to_str().ok())
776        .unwrap_or("application/octet-stream");
777    let content_type = super::ContentType::from(content_type);
778
779    if !status.is_client_error() && !status.is_server_error() {
780        let content = resp.text().await?;
781        match content_type {
782            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
783            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::PurchasePhoneNumber200Response`"))),
784            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::PurchasePhoneNumber200Response`")))),
785        }
786    } else {
787        let content = resp.text().await?;
788        let entity: Option<PurchasePhoneNumberError> = serde_json::from_str(&content).ok();
789        Err(Error::ResponseError(ResponseContent {
790            status,
791            content,
792            entity,
793        }))
794    }
795}
796
797/// Release a purchased phone number. This will: 1. Disconnect any linked WhatsApp social account 2. Decrement the Stripe subscription quantity (or cancel if last number) 3. Release the number from Telnyx 4. Mark the number as released
798pub async fn release_phone_number(
799    configuration: &configuration::Configuration,
800    id: &str,
801) -> Result<models::ReleasePhoneNumber200Response, Error<ReleasePhoneNumberError>> {
802    // add a prefix to parameters to efficiently prevent name collisions
803    let p_path_id = id;
804
805    let uri_str = format!(
806        "{}/v1/phone-numbers/{id}",
807        configuration.base_path,
808        id = crate::apis::urlencode(p_path_id)
809    );
810    let mut req_builder = configuration
811        .client
812        .request(reqwest::Method::DELETE, &uri_str);
813
814    if let Some(ref user_agent) = configuration.user_agent {
815        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
816    }
817    if let Some(ref token) = configuration.bearer_access_token {
818        req_builder = req_builder.bearer_auth(token.to_owned());
819    };
820
821    let req = req_builder.build()?;
822    let resp = configuration.client.execute(req).await?;
823
824    let status = resp.status();
825    let content_type = resp
826        .headers()
827        .get("content-type")
828        .and_then(|v| v.to_str().ok())
829        .unwrap_or("application/octet-stream");
830    let content_type = super::ContentType::from(content_type);
831
832    if !status.is_client_error() && !status.is_server_error() {
833        let content = resp.text().await?;
834        match content_type {
835            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
836            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::ReleasePhoneNumber200Response`"))),
837            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::ReleasePhoneNumber200Response`")))),
838        }
839    } else {
840        let content = resp.text().await?;
841        let entity: Option<ReleasePhoneNumberError> = serde_json::from_str(&content).ok();
842        Err(Error::ResponseError(ResponseContent {
843            status,
844            content,
845            entity,
846        }))
847    }
848}
849
850/// Submit corrected values/documents for the declined requirement(s). We PATCH them onto the SAME requirement group and re-submit it for approval; the number goes `regulatory_declined` → `pending_regulatory`. No new number and no new billing. Body shape matches the KYC submit (values / documents / address) — send only the corrected fields.
851pub async fn remediate_phone_number(
852    configuration: &configuration::Configuration,
853    id: &str,
854    remediate_phone_number_request: models::RemediatePhoneNumberRequest,
855) -> Result<models::RemediatePhoneNumber200Response, Error<RemediatePhoneNumberError>> {
856    // add a prefix to parameters to efficiently prevent name collisions
857    let p_path_id = id;
858    let p_body_remediate_phone_number_request = remediate_phone_number_request;
859
860    let uri_str = format!(
861        "{}/v1/phone-numbers/{id}/remediate",
862        configuration.base_path,
863        id = crate::apis::urlencode(p_path_id)
864    );
865    let mut req_builder = configuration
866        .client
867        .request(reqwest::Method::POST, &uri_str);
868
869    if let Some(ref user_agent) = configuration.user_agent {
870        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
871    }
872    if let Some(ref token) = configuration.bearer_access_token {
873        req_builder = req_builder.bearer_auth(token.to_owned());
874    };
875    req_builder = req_builder.json(&p_body_remediate_phone_number_request);
876
877    let req = req_builder.build()?;
878    let resp = configuration.client.execute(req).await?;
879
880    let status = resp.status();
881    let content_type = resp
882        .headers()
883        .get("content-type")
884        .and_then(|v| v.to_str().ok())
885        .unwrap_or("application/octet-stream");
886    let content_type = super::ContentType::from(content_type);
887
888    if !status.is_client_error() && !status.is_server_error() {
889        let content = resp.text().await?;
890        match content_type {
891            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
892            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::RemediatePhoneNumber200Response`"))),
893            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::RemediatePhoneNumber200Response`")))),
894        }
895    } else {
896        let content = resp.text().await?;
897        let entity: Option<RemediatePhoneNumberError> = serde_json::from_str(&content).ok();
898        Err(Error::ResponseError(ResponseContent {
899            status,
900            content,
901            entity,
902        }))
903    }
904}
905
906/// Advisory dry-run of a regulated-KYC packet before submitting: reviews the exact documents the regulator will see (referenced by the ids from POST /v1/phone-numbers/kyc/upload-document) against the declared values and address, and returns plain-language advisories for likely decline reasons (wrong document type, mismatched address, one-sided ID scans). Non-blocking: advisories are warnings, submitting anyway is always allowed, and any review failure degrades to an empty list.
907pub async fn review_phone_number_kyc_packet(
908    configuration: &configuration::Configuration,
909    review_phone_number_kyc_packet_request: models::ReviewPhoneNumberKycPacketRequest,
910) -> Result<models::ReviewPhoneNumberKycPacket200Response, Error<ReviewPhoneNumberKycPacketError>> {
911    // add a prefix to parameters to efficiently prevent name collisions
912    let p_body_review_phone_number_kyc_packet_request = review_phone_number_kyc_packet_request;
913
914    let uri_str = format!(
915        "{}/v1/phone-numbers/kyc/review-packet",
916        configuration.base_path
917    );
918    let mut req_builder = configuration
919        .client
920        .request(reqwest::Method::POST, &uri_str);
921
922    if let Some(ref user_agent) = configuration.user_agent {
923        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
924    }
925    if let Some(ref token) = configuration.bearer_access_token {
926        req_builder = req_builder.bearer_auth(token.to_owned());
927    };
928    req_builder = req_builder.json(&p_body_review_phone_number_kyc_packet_request);
929
930    let req = req_builder.build()?;
931    let resp = configuration.client.execute(req).await?;
932
933    let status = resp.status();
934    let content_type = resp
935        .headers()
936        .get("content-type")
937        .and_then(|v| v.to_str().ok())
938        .unwrap_or("application/octet-stream");
939    let content_type = super::ContentType::from(content_type);
940
941    if !status.is_client_error() && !status.is_server_error() {
942        let content = resp.text().await?;
943        match content_type {
944            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
945            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::ReviewPhoneNumberKycPacket200Response`"))),
946            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::ReviewPhoneNumberKycPacket200Response`")))),
947        }
948    } else {
949        let content = resp.text().await?;
950        let entity: Option<ReviewPhoneNumberKycPacketError> = serde_json::from_str(&content).ok();
951        Err(Error::ResponseError(ResponseContent {
952            status,
953            content,
954            entity,
955        }))
956    }
957}
958
959/// Search the provider's inventory for numbers available to purchase in a country (default US). Optional filters narrow the results. The country must be offerable (see GET /v1/phone-numbers/countries). Voice capability is always required; pass `sms=true` to only see numbers that can also text (SMS support is per-number, not per-country).
960pub async fn search_available_phone_numbers(
961    configuration: &configuration::Configuration,
962    country: Option<&str>,
963    r#type: Option<&str>,
964    prefix: Option<&str>,
965    locality: Option<&str>,
966    contains: Option<&str>,
967    sms: Option<bool>,
968    limit: Option<i32>,
969) -> Result<models::SearchAvailablePhoneNumbers200Response, Error<SearchAvailablePhoneNumbersError>>
970{
971    // add a prefix to parameters to efficiently prevent name collisions
972    let p_query_country = country;
973    let p_query_type = r#type;
974    let p_query_prefix = prefix;
975    let p_query_locality = locality;
976    let p_query_contains = contains;
977    let p_query_sms = sms;
978    let p_query_limit = limit;
979
980    let uri_str = format!("{}/v1/phone-numbers/available", configuration.base_path);
981    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
982
983    if let Some(ref param_value) = p_query_country {
984        req_builder = req_builder.query(&[("country", &param_value.to_string())]);
985    }
986    if let Some(ref param_value) = p_query_type {
987        req_builder = req_builder.query(&[("type", &param_value.to_string())]);
988    }
989    if let Some(ref param_value) = p_query_prefix {
990        req_builder = req_builder.query(&[("prefix", &param_value.to_string())]);
991    }
992    if let Some(ref param_value) = p_query_locality {
993        req_builder = req_builder.query(&[("locality", &param_value.to_string())]);
994    }
995    if let Some(ref param_value) = p_query_contains {
996        req_builder = req_builder.query(&[("contains", &param_value.to_string())]);
997    }
998    if let Some(ref param_value) = p_query_sms {
999        req_builder = req_builder.query(&[("sms", &param_value.to_string())]);
1000    }
1001    if let Some(ref param_value) = p_query_limit {
1002        req_builder = req_builder.query(&[("limit", &param_value.to_string())]);
1003    }
1004    if let Some(ref user_agent) = configuration.user_agent {
1005        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
1006    }
1007    if let Some(ref token) = configuration.bearer_access_token {
1008        req_builder = req_builder.bearer_auth(token.to_owned());
1009    };
1010
1011    let req = req_builder.build()?;
1012    let resp = configuration.client.execute(req).await?;
1013
1014    let status = resp.status();
1015    let content_type = resp
1016        .headers()
1017        .get("content-type")
1018        .and_then(|v| v.to_str().ok())
1019        .unwrap_or("application/octet-stream");
1020    let content_type = super::ContentType::from(content_type);
1021
1022    if !status.is_client_error() && !status.is_server_error() {
1023        let content = resp.text().await?;
1024        match content_type {
1025            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
1026            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::SearchAvailablePhoneNumbers200Response`"))),
1027            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::SearchAvailablePhoneNumbers200Response`")))),
1028        }
1029    } else {
1030        let content = resp.text().await?;
1031        let entity: Option<SearchAvailablePhoneNumbersError> = serde_json::from_str(&content).ok();
1032        Err(Error::ResponseError(ResponseContent {
1033            status,
1034            content,
1035            entity,
1036        }))
1037    }
1038}
1039
1040/// Submit the end customer's KYC (textual values, uploaded documents, address) for a Tier 3/4 country. Documents are streamed straight to the number provider and are not stored by Zernio. Builds + submits a regulatory requirement group and claims a pending_regulatory slot; the number is ordered + activated once the provider approves (asynchronous). A customer may hold several same-country numbers in review at once; a double-submit of the SAME attempt is deduped via `submissionId`.  For an ID-card document requirement, carriers commonly require BOTH sides: combine the front and back into a single file before uploading (the dashboard does this automatically). A one-sided ID is a common decline reason; fix it via POST /v1/phone-numbers/{id}/remediate.  Before submitting, call GET /v1/phone-numbers/availability to check the country has deliverable inventory and, for geographic-match countries, which area the address must be in — otherwise the submission can pass review yet never be assignable a number.
1041pub async fn submit_phone_number_kyc(
1042    configuration: &configuration::Configuration,
1043    submit_phone_number_kyc_request: models::SubmitPhoneNumberKycRequest,
1044) -> Result<models::SubmitPhoneNumberKyc200Response, Error<SubmitPhoneNumberKycError>> {
1045    // add a prefix to parameters to efficiently prevent name collisions
1046    let p_body_submit_phone_number_kyc_request = submit_phone_number_kyc_request;
1047
1048    let uri_str = format!("{}/v1/phone-numbers/kyc", configuration.base_path);
1049    let mut req_builder = configuration
1050        .client
1051        .request(reqwest::Method::POST, &uri_str);
1052
1053    if let Some(ref user_agent) = configuration.user_agent {
1054        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
1055    }
1056    if let Some(ref token) = configuration.bearer_access_token {
1057        req_builder = req_builder.bearer_auth(token.to_owned());
1058    };
1059    req_builder = req_builder.json(&p_body_submit_phone_number_kyc_request);
1060
1061    let req = req_builder.build()?;
1062    let resp = configuration.client.execute(req).await?;
1063
1064    let status = resp.status();
1065    let content_type = resp
1066        .headers()
1067        .get("content-type")
1068        .and_then(|v| v.to_str().ok())
1069        .unwrap_or("application/octet-stream");
1070    let content_type = super::ContentType::from(content_type);
1071
1072    if !status.is_client_error() && !status.is_server_error() {
1073        let content = resp.text().await?;
1074        match content_type {
1075            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
1076            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::SubmitPhoneNumberKyc200Response`"))),
1077            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::SubmitPhoneNumberKyc200Response`")))),
1078        }
1079    } else {
1080        let content = resp.text().await?;
1081        let entity: Option<SubmitPhoneNumberKycError> = serde_json::from_str(&content).ok();
1082        Err(Error::ResponseError(ResponseContent {
1083            status,
1084            content,
1085            entity,
1086        }))
1087    }
1088}
1089
1090/// Upload ONE document and get back its provider document id, to reference from POST /v1/phone-numbers/kyc via `documents[].documentId`. Send the RAW file bytes as the request body (not base64); put the filename in the `X-Filename` header. Uploading documents one-per-request keeps each request under the ~4.5MB body limit. The document streams straight to the number provider and is not stored by Zernio.
1091pub async fn upload_phone_number_kyc_document(
1092    configuration: &configuration::Configuration,
1093    x_filename: &str,
1094    body: std::path::PathBuf,
1095) -> Result<models::UploadPhoneNumberKycDocument200Response, Error<UploadPhoneNumberKycDocumentError>>
1096{
1097    // add a prefix to parameters to efficiently prevent name collisions
1098    let p_header_x_filename = x_filename;
1099    let p_body_body = body;
1100
1101    let uri_str = format!(
1102        "{}/v1/phone-numbers/kyc/upload-document",
1103        configuration.base_path
1104    );
1105    let mut req_builder = configuration
1106        .client
1107        .request(reqwest::Method::POST, &uri_str);
1108
1109    if let Some(ref user_agent) = configuration.user_agent {
1110        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
1111    }
1112    req_builder = req_builder.header("X-Filename", p_header_x_filename.to_string());
1113    if let Some(ref token) = configuration.bearer_access_token {
1114        req_builder = req_builder.bearer_auth(token.to_owned());
1115    };
1116    let file = TokioFile::open(p_body_body).await?;
1117    let stream = FramedRead::new(file, BytesCodec::new());
1118    req_builder = req_builder.body(reqwest::Body::wrap_stream(stream));
1119
1120    let req = req_builder.build()?;
1121    let resp = configuration.client.execute(req).await?;
1122
1123    let status = resp.status();
1124    let content_type = resp
1125        .headers()
1126        .get("content-type")
1127        .and_then(|v| v.to_str().ok())
1128        .unwrap_or("application/octet-stream");
1129    let content_type = super::ContentType::from(content_type);
1130
1131    if !status.is_client_error() && !status.is_server_error() {
1132        let content = resp.text().await?;
1133        match content_type {
1134            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
1135            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::UploadPhoneNumberKycDocument200Response`"))),
1136            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::UploadPhoneNumberKycDocument200Response`")))),
1137        }
1138    } else {
1139        let content = resp.text().await?;
1140        let entity: Option<UploadPhoneNumberKycDocumentError> = serde_json::from_str(&content).ok();
1141        Err(Error::ResponseError(ResponseContent {
1142            status,
1143            content,
1144            entity,
1145        }))
1146    }
1147}
1148
1149/// Upload ONE porting document (the signed LOA or a recent carrier invoice) and get back its `documentId`, which the port-in create request takes as `loaDocumentId` / `invoiceDocumentId`. PDF, JPEG, or PNG, 10MB max.
1150pub async fn upload_phone_number_port_in_document(
1151    configuration: &configuration::Configuration,
1152    file: std::path::PathBuf,
1153    kind: Option<&str>,
1154) -> Result<
1155    models::UploadPhoneNumberPortInDocument200Response,
1156    Error<UploadPhoneNumberPortInDocumentError>,
1157> {
1158    // add a prefix to parameters to efficiently prevent name collisions
1159    let p_form_file = file;
1160    let p_form_kind = kind;
1161
1162    let uri_str = format!(
1163        "{}/v1/phone-numbers/port-in/documents",
1164        configuration.base_path
1165    );
1166    let mut req_builder = configuration
1167        .client
1168        .request(reqwest::Method::POST, &uri_str);
1169
1170    if let Some(ref user_agent) = configuration.user_agent {
1171        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
1172    }
1173    if let Some(ref token) = configuration.bearer_access_token {
1174        req_builder = req_builder.bearer_auth(token.to_owned());
1175    };
1176    let mut multipart_form = reqwest::multipart::Form::new();
1177    let file = TokioFile::open(&p_form_file).await?;
1178    let stream = FramedRead::new(file, BytesCodec::new());
1179    let file_name = p_form_file
1180        .file_name()
1181        .map(|n| n.to_string_lossy().to_string())
1182        .unwrap_or_default();
1183    let file_part =
1184        reqwest::multipart::Part::stream(reqwest::Body::wrap_stream(stream)).file_name(file_name);
1185    multipart_form = multipart_form.part("file", file_part);
1186    if let Some(param_value) = p_form_kind {
1187        multipart_form = multipart_form.text("kind", param_value.to_string());
1188    }
1189    req_builder = req_builder.multipart(multipart_form);
1190
1191    let req = req_builder.build()?;
1192    let resp = configuration.client.execute(req).await?;
1193
1194    let status = resp.status();
1195    let content_type = resp
1196        .headers()
1197        .get("content-type")
1198        .and_then(|v| v.to_str().ok())
1199        .unwrap_or("application/octet-stream");
1200    let content_type = super::ContentType::from(content_type);
1201
1202    if !status.is_client_error() && !status.is_server_error() {
1203        let content = resp.text().await?;
1204        match content_type {
1205            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
1206            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::UploadPhoneNumberPortInDocument200Response`"))),
1207            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::UploadPhoneNumberPortInDocument200Response`")))),
1208        }
1209    } else {
1210        let content = resp.text().await?;
1211        let entity: Option<UploadPhoneNumberPortInDocumentError> =
1212            serde_json::from_str(&content).ok();
1213        Err(Error::ResponseError(ResponseContent {
1214            status,
1215            content,
1216            entity,
1217        }))
1218    }
1219}
1220
1221/// Optional early check for the address step of a Tier 4 (end-user identity) registration: validates a postal address for deliverability BEFORE the full KYC submit, so it can be corrected before any documents are uploaded. The full submit (POST /v1/phone-numbers/kyc) re-validates the address, so this call is purely a fast feedback path and skipping it is safe. Only the postal address is sent (no documents, no gov-ID fields). A region (`administrative_area`) is required by the validator; when it is omitted the pre-check is skipped and `{ ok: true, skipped: true }` is returned (the final submit still validates).
1222pub async fn validate_phone_number_kyc_address(
1223    configuration: &configuration::Configuration,
1224    validate_phone_number_kyc_address_request: models::ValidatePhoneNumberKycAddressRequest,
1225) -> Result<
1226    models::ValidatePhoneNumberKycAddress200Response,
1227    Error<ValidatePhoneNumberKycAddressError>,
1228> {
1229    // add a prefix to parameters to efficiently prevent name collisions
1230    let p_body_validate_phone_number_kyc_address_request =
1231        validate_phone_number_kyc_address_request;
1232
1233    let uri_str = format!(
1234        "{}/v1/phone-numbers/kyc/validate-address",
1235        configuration.base_path
1236    );
1237    let mut req_builder = configuration
1238        .client
1239        .request(reqwest::Method::POST, &uri_str);
1240
1241    if let Some(ref user_agent) = configuration.user_agent {
1242        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
1243    }
1244    if let Some(ref token) = configuration.bearer_access_token {
1245        req_builder = req_builder.bearer_auth(token.to_owned());
1246    };
1247    req_builder = req_builder.json(&p_body_validate_phone_number_kyc_address_request);
1248
1249    let req = req_builder.build()?;
1250    let resp = configuration.client.execute(req).await?;
1251
1252    let status = resp.status();
1253    let content_type = resp
1254        .headers()
1255        .get("content-type")
1256        .and_then(|v| v.to_str().ok())
1257        .unwrap_or("application/octet-stream");
1258    let content_type = super::ContentType::from(content_type);
1259
1260    if !status.is_client_error() && !status.is_server_error() {
1261        let content = resp.text().await?;
1262        match content_type {
1263            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
1264            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::ValidatePhoneNumberKycAddress200Response`"))),
1265            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::ValidatePhoneNumberKycAddress200Response`")))),
1266        }
1267    } else {
1268        let content = resp.text().await?;
1269        let entity: Option<ValidatePhoneNumberKycAddressError> =
1270            serde_json::from_str(&content).ok();
1271        Err(Error::ResponseError(ResponseContent {
1272            status,
1273            content,
1274            entity,
1275        }))
1276    }
1277}