/*
* Zernio API
*
* API reference for Zernio. Authenticate with a Bearer API key. Base URL: https://zernio.com/api Versioning and deprecation: all endpoints are versioned in the URL path (current version: /v1). Breaking changes only ship in a new path version; existing versions keep working. Deprecated operations are marked 'deprecated: true' in this spec and announced in the changelog (https://zernio.com/changelog) before removal. Errors: every 4xx/5xx response is application/json with a machine-readable 'code' and a human-readable 'error' message (see the ErrorResponse schema). Request ids: responses carry an X-Request-Id header with the id we log the request under. Quote it when reporting a problem. A valid x-request-id you send is reused as that id.
*
* The version of the OpenAPI document: 1.415.0
* Contact: support@zernio.com
* Generated by: https://openapi-generator.tech
*/
use super::{configuration, ContentType, Error};
use crate::{apis::ResponseContent, models};
use reqwest;
use serde::{de::Error as _, Deserialize, Serialize};
/// struct for typed errors of method [`add_users_to_ad_audience`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum AddUsersToAdAudienceError {
Status400(),
Status401(models::ErrorResponse),
Status403(),
Status404(models::InlineObject1),
Status422(),
UnknownValue(serde_json::Value),
}
/// struct for typed errors of method [`create_ad_audience`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum CreateAdAudienceError {
Status400(),
Status401(models::ErrorResponse),
Status403(),
Status404(models::ErrorResponse),
Status409(models::ErrorResponse),
UnknownValue(serde_json::Value),
}
/// struct for typed errors of method [`delete_ad_audience`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum DeleteAdAudienceError {
Status401(models::ErrorResponse),
Status403(),
Status404(models::InlineObject1),
Status422(),
UnknownValue(serde_json::Value),
}
/// struct for typed errors of method [`get_ad_audience`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum GetAdAudienceError {
Status401(models::ErrorResponse),
Status403(),
Status404(models::InlineObject1),
UnknownValue(serde_json::Value),
}
/// struct for typed errors of method [`list_ad_audiences`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ListAdAudiencesError {
Status400(models::ErrorResponse),
Status401(models::ErrorResponse),
Status403(),
Status404(models::ErrorResponse),
Status409(models::ErrorResponse),
UnknownValue(serde_json::Value),
}
/// struct for typed errors of method [`remove_users_from_ad_audience`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum RemoveUsersFromAdAudienceError {
Status400(models::ErrorResponse),
Status401(models::ErrorResponse),
Status403(),
Status404(models::InlineObject1),
Status422(),
UnknownValue(serde_json::Value),
}
/// struct for typed errors of method [`replace_ad_audience_companies`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ReplaceAdAudienceCompaniesError {
Status400(),
Status401(models::ErrorResponse),
Status403(),
Status404(models::InlineObject1),
Status422(),
UnknownValue(serde_json::Value),
}
/// struct for typed errors of method [`update_ad_audience`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum UpdateAdAudienceError {
Status400(),
Status401(models::ErrorResponse),
Status403(),
Status404(models::InlineObject1),
Status422(),
Status501(),
UnknownValue(serde_json::Value),
}
/// Uploads customer emails (and phone numbers on Meta) to a customer list audience, hashed before they are sent. Data is SHA256-hashed server-side before sending to the platform. Max 10,000 users per request. ### Per-platform behavior - **All platforms**: email is used everywhere. Phone is used on Meta only (other platforms ignore it). - **TikTok and Pinterest**: the first upload also provisions the audience (deferred create). - **LinkedIn**: uploads are full-replace. - **Reddit**: see below. ### Reddit - Emails are lowercased and trimmed before hashing, duplicates are sent once, and the upload goes out in batches of 2,500. - Reddit matches by email only: rows without a valid email count in `numInvalid`, and a request where no row has one is a 400. - Reddit audiences need the `redditads` connection, not the Reddit posting account (422). ### Audience types customer_list only. A LinkedIn `company_list` audience takes company rows, not people: send those to `POST /v1/ads/audiences/{audienceId}/companies`. This endpoint 422s for every other audience type.
pub async fn add_users_to_ad_audience(
configuration: &configuration::Configuration,
audience_id: &str,
add_users_to_ad_audience_request: models::AddUsersToAdAudienceRequest,
) -> Result<models::AddUsersToAdAudience200Response, Error<AddUsersToAdAudienceError>> {
// add a prefix to parameters to efficiently prevent name collisions
let p_path_audience_id = audience_id;
let p_body_add_users_to_ad_audience_request = add_users_to_ad_audience_request;
let uri_str = format!(
"{}/v1/ads/audiences/{audienceId}/users",
configuration.base_path,
audienceId = crate::apis::urlencode(p_path_audience_id)
);
let mut req_builder = configuration
.client
.request(reqwest::Method::POST, &uri_str);
if let Some(ref user_agent) = configuration.user_agent {
req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
}
if let Some(ref token) = configuration.bearer_access_token {
req_builder = req_builder.bearer_auth(token.to_owned());
};
req_builder = req_builder.json(&p_body_add_users_to_ad_audience_request);
let req = req_builder.build()?;
let resp = configuration.client.execute(req).await?;
let status = resp.status();
let content_type = resp
.headers()
.get("content-type")
.and_then(|v| v.to_str().ok())
.unwrap_or("application/octet-stream");
let content_type = super::ContentType::from(content_type);
if !status.is_client_error() && !status.is_server_error() {
let content = resp.text().await?;
match content_type {
ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::AddUsersToAdAudience200Response`"))),
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::AddUsersToAdAudience200Response`")))),
}
} else {
let content = resp.text().await?;
let entity: Option<AddUsersToAdAudienceError> = serde_json::from_str(&content).ok();
Err(Error::ResponseError(ResponseContent {
status,
content,
entity,
}))
}
}
/// Creates a custom audience from a customer list, website visitors, a lookalike, or people who engaged with your content. ### Audience types by platform - `customer_list`: Meta, Google, X, LinkedIn, TikTok, Pinterest, and Reddit. - `website` (pixel/tag visitors): Meta, TikTok, Pinterest, Google, and Reddit. - `lookalike`: Meta, TikTok, Pinterest and Google (Reddit's API cannot create one). - `meta_engagement`: Meta-only. - `tiktok_engagement`: TikTok-only. - `pinterest_engagement`: Pinterest-only. - `company_list`, `engagement` and `website_retargeting`: LinkedIn-only. A type sent to a platform that does not support it is a 422 `FEATURE_NOT_AVAILABLE`. Reddit audience names need at least 3 characters. ### Per-platform rules for `website` - Meta: `pixelId` required, `retentionDays` 1-180, optional `urlContains` or raw `rule`. `event` is not accepted. - TikTok: `pixelId` required, `retentionDays` one of 7, 14, 30, 60, 90, 180. `event` is a TikTok pixel event (see below), optional `urlContains`. - Pinterest: `pixelId` is the Pinterest tag id, `retentionDays` 1-540, optional `event` (e.g. `checkout`, `addtocart`). Pinterest matches URLs exactly, so `urlContains` is a 400 there. - Google: no `pixelId` (the account's Google tag is used), `retentionDays` 1-540, `urlContains` defaults to `/` (all visitors). Built as a rule-based user list with prepopulation requested. - Reddit: `pixelId` is the Reddit pixel id, `retentionDays` 1-90. `event` is a Reddit conversion event (see below); any other value is sent as a custom event name. `urlContains` and `rule` are a 400. TikTok pixel events: `PAGE BROWSE` (default), `CLICK BUTTON`, `PIXEL SUBMIT FORM`, `CONTACT`, `DOWNLOAD`, `PIXEL ADD PAYMENT INFO`, `COMPLETE PAYMENT`, `INITIATE CHECKOUT`, `COMPLETE REGISTRATION`, `PRODUCT DETAIL PAGE BROWSE`, `PIXEL SEARCH`, `PIXEL ADD TO CART`, `PLACE AN ORDER`, `PIXEL ADD TO WISHLIST`, `PIXEL SUBSCRIBE`. Reddit conversion events: `PAGE_VISIT` (default), `VIEW_CONTENT`, `SEARCH`, `ADD_TO_CART`, `ADD_TO_WISHLIST`, `PURCHASE`, `LEAD`, `SIGN_UP`. ### Per-platform rules for `lookalike` - Meta: `ratio` (0.01-0.20). - Pinterest: `ratio` in whole percents (0.01-0.10) and `country` US, CA or GB. - TikTok and Google: `size` (narrow, balanced, broad) instead of `ratio`. TikTok needs a seed with at least 1,000 matched people. ### Saved targeting `saved_targeting` stores a reusable TargetingSpec (no member upload, no adAccountId) that you reference later via `savedTargetingId` on `POST /v1/ads/create`. ### How the audience gets filled - `customer_list` is created empty. Add members with `POST /v1/ads/audiences/{audienceId}/users`. On TikTok and Pinterest the audience is provisioned lazily on that first upload (until then its status is `pending`). - `company_list` is filled AT CREATION from the `companies` array below, which is required. To change the list afterwards, send the new full list to `POST /v1/ads/audiences/{audienceId}/companies` (a replace, not a merge). The `/users` endpoint rejects these audiences with a 422. - `website`, `website_retargeting`, `engagement`, `meta_engagement`, `tiktok_engagement`, `pinterest_engagement` and `lookalike` fill themselves from the pixel, engagement source or seed audience you point them at. They take no member upload at all. Create is not idempotent, never auto-retry.
pub async fn create_ad_audience(
configuration: &configuration::Configuration,
create_ad_audience_request: models::CreateAdAudienceRequest,
) -> Result<models::CreateAdAudience201Response, Error<CreateAdAudienceError>> {
// add a prefix to parameters to efficiently prevent name collisions
let p_body_create_ad_audience_request = create_ad_audience_request;
let uri_str = format!("{}/v1/ads/audiences", configuration.base_path);
let mut req_builder = configuration
.client
.request(reqwest::Method::POST, &uri_str);
if let Some(ref user_agent) = configuration.user_agent {
req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
}
if let Some(ref token) = configuration.bearer_access_token {
req_builder = req_builder.bearer_auth(token.to_owned());
};
req_builder = req_builder.json(&p_body_create_ad_audience_request);
let req = req_builder.build()?;
let resp = configuration.client.execute(req).await?;
let status = resp.status();
let content_type = resp
.headers()
.get("content-type")
.and_then(|v| v.to_str().ok())
.unwrap_or("application/octet-stream");
let content_type = super::ContentType::from(content_type);
if !status.is_client_error() && !status.is_server_error() {
let content = resp.text().await?;
match content_type {
ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::CreateAdAudience201Response`"))),
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::CreateAdAudience201Response`")))),
}
} else {
let content = resp.text().await?;
let entity: Option<CreateAdAudienceError> = serde_json::from_str(&content).ok();
Err(Error::ResponseError(ResponseContent {
status,
content,
entity,
}))
}
}
/// Removes a custom audience from its ad platform (archiving it where the platform does not delete). Removes the audience on its ad platform, then deletes the Zernio record. ### By platform - Deleted: Meta, Google, TikTok, LinkedIn list and engagement segments, X, and Reddit. - Archived (how those platforms remove them): Pinterest audiences and LinkedIn `website_retargeting` segments. - Local only: `saved_targeting` audiences exist only on Zernio, so only the local record is removed. Google Ads does not allow removing lookalike lists through its API, so those return 422 `FEATURE_NOT_AVAILABLE`. ### Failures and retries If the platform refuses, the error is returned and the Zernio record is kept, so a retry is safe. An audience the platform no longer has counts as removed.
pub async fn delete_ad_audience(
configuration: &configuration::Configuration,
audience_id: &str,
) -> Result<models::DeleteAccountGroup200Response, Error<DeleteAdAudienceError>> {
// add a prefix to parameters to efficiently prevent name collisions
let p_path_audience_id = audience_id;
let uri_str = format!(
"{}/v1/ads/audiences/{audienceId}",
configuration.base_path,
audienceId = crate::apis::urlencode(p_path_audience_id)
);
let mut req_builder = configuration
.client
.request(reqwest::Method::DELETE, &uri_str);
if let Some(ref user_agent) = configuration.user_agent {
req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
}
if let Some(ref token) = configuration.bearer_access_token {
req_builder = req_builder.bearer_auth(token.to_owned());
};
let req = req_builder.build()?;
let resp = configuration.client.execute(req).await?;
let status = resp.status();
let content_type = resp
.headers()
.get("content-type")
.and_then(|v| v.to_str().ok())
.unwrap_or("application/octet-stream");
let content_type = super::ContentType::from(content_type);
if !status.is_client_error() && !status.is_server_error() {
let content = resp.text().await?;
match content_type {
ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::DeleteAccountGroup200Response`"))),
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::DeleteAccountGroup200Response`")))),
}
} else {
let content = resp.text().await?;
let entity: Option<DeleteAdAudienceError> = serde_json::from_str(&content).ok();
Err(Error::ResponseError(ResponseContent {
status,
content,
entity,
}))
}
}
/// Shows a custom audience's details, including its latest data from the ad platform when available. Returns the local audience record and fresh data from Meta (if available).
pub async fn get_ad_audience(
configuration: &configuration::Configuration,
audience_id: &str,
) -> Result<models::GetAdAudience200Response, Error<GetAdAudienceError>> {
// add a prefix to parameters to efficiently prevent name collisions
let p_path_audience_id = audience_id;
let uri_str = format!(
"{}/v1/ads/audiences/{audienceId}",
configuration.base_path,
audienceId = crate::apis::urlencode(p_path_audience_id)
);
let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
if let Some(ref user_agent) = configuration.user_agent {
req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
}
if let Some(ref token) = configuration.bearer_access_token {
req_builder = req_builder.bearer_auth(token.to_owned());
};
let req = req_builder.build()?;
let resp = configuration.client.execute(req).await?;
let status = resp.status();
let content_type = resp
.headers()
.get("content-type")
.and_then(|v| v.to_str().ok())
.unwrap_or("application/octet-stream");
let content_type = super::ContentType::from(content_type);
if !status.is_client_error() && !status.is_server_error() {
let content = resp.text().await?;
match content_type {
ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::GetAdAudience200Response`"))),
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::GetAdAudience200Response`")))),
}
} else {
let content = resp.text().await?;
let entity: Option<GetAdAudienceError> = serde_json::from_str(&content).ok();
Err(Error::ResponseError(ResponseContent {
status,
content,
entity,
}))
}
}
/// Lists the custom audiences in an ad account so you can reuse them for targeting. Supports Meta, Google, TikTok, Pinterest, LinkedIn, X, and Reddit. On Reddit, `size` is the lower bound of Reddit's matched-users range, and `status` is `too_small` while the list has matched fewer than 1,000 people.
pub async fn list_ad_audiences(
configuration: &configuration::Configuration,
account_id: &str,
ad_account_id: &str,
platform: Option<&str>,
r#type: Option<&str>,
) -> Result<models::ListAdAudiences200Response, Error<ListAdAudiencesError>> {
// add a prefix to parameters to efficiently prevent name collisions
let p_query_account_id = account_id;
let p_query_ad_account_id = ad_account_id;
let p_query_platform = platform;
let p_query_type = r#type;
let uri_str = format!("{}/v1/ads/audiences", configuration.base_path);
let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
req_builder = req_builder.query(&[("accountId", &p_query_account_id.to_string())]);
req_builder = req_builder.query(&[("adAccountId", &p_query_ad_account_id.to_string())]);
if let Some(ref param_value) = p_query_platform {
req_builder = req_builder.query(&[("platform", ¶m_value.to_string())]);
}
if let Some(ref param_value) = p_query_type {
req_builder = req_builder.query(&[("type", ¶m_value.to_string())]);
}
if let Some(ref user_agent) = configuration.user_agent {
req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
}
if let Some(ref token) = configuration.bearer_access_token {
req_builder = req_builder.bearer_auth(token.to_owned());
};
let req = req_builder.build()?;
let resp = configuration.client.execute(req).await?;
let status = resp.status();
let content_type = resp
.headers()
.get("content-type")
.and_then(|v| v.to_str().ok())
.unwrap_or("application/octet-stream");
let content_type = super::ContentType::from(content_type);
if !status.is_client_error() && !status.is_server_error() {
let content = resp.text().await?;
match content_type {
ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::ListAdAudiences200Response`"))),
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::ListAdAudiences200Response`")))),
}
} else {
let content = resp.text().await?;
let entity: Option<ListAdAudiencesError> = serde_json::from_str(&content).ok();
Err(Error::ResponseError(ResponseContent {
status,
content,
entity,
}))
}
}
/// Removes customer emails (and phone numbers on Meta) from a Meta or Reddit customer list audience. Same body as `POST /v1/ads/audiences/{audienceId}/users`: send plaintext rows, they are normalized and SHA256-hashed server-side exactly like an upload, so a row removes the person it added. Meta and Reddit only, customer_list only. Every other platform returns 422 with code `feature_not_available`, and every other audience type returns 422. Max 10,000 users per request. The platform applies the removal asynchronously, so the audience size does not drop immediately. On Reddit `invalidEntrySamples` is always empty.
pub async fn remove_users_from_ad_audience(
configuration: &configuration::Configuration,
audience_id: &str,
remove_users_from_ad_audience_request: models::RemoveUsersFromAdAudienceRequest,
) -> Result<models::RemoveUsersFromAdAudience200Response, Error<RemoveUsersFromAdAudienceError>> {
// add a prefix to parameters to efficiently prevent name collisions
let p_path_audience_id = audience_id;
let p_body_remove_users_from_ad_audience_request = remove_users_from_ad_audience_request;
let uri_str = format!(
"{}/v1/ads/audiences/{audienceId}/users",
configuration.base_path,
audienceId = crate::apis::urlencode(p_path_audience_id)
);
let mut req_builder = configuration
.client
.request(reqwest::Method::DELETE, &uri_str);
if let Some(ref user_agent) = configuration.user_agent {
req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
}
if let Some(ref token) = configuration.bearer_access_token {
req_builder = req_builder.bearer_auth(token.to_owned());
};
req_builder = req_builder.json(&p_body_remove_users_from_ad_audience_request);
let req = req_builder.build()?;
let resp = configuration.client.execute(req).await?;
let status = resp.status();
let content_type = resp
.headers()
.get("content-type")
.and_then(|v| v.to_str().ok())
.unwrap_or("application/octet-stream");
let content_type = super::ContentType::from(content_type);
if !status.is_client_error() && !status.is_server_error() {
let content = resp.text().await?;
match content_type {
ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::RemoveUsersFromAdAudience200Response`"))),
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::RemoveUsersFromAdAudience200Response`")))),
}
} else {
let content = resp.text().await?;
let entity: Option<RemoveUsersFromAdAudienceError> = serde_json::from_str(&content).ok();
Err(Error::ResponseError(ResponseContent {
status,
content,
entity,
}))
}
}
/// Upload the company rows of a LinkedIn `company_list` audience (account-based marketing). LinkedIn-only, every other platform returns 422. The initial list is sent with `companies` on `POST /v1/ads/audiences`; this endpoint is for every change after that. ### Send the full list every time A LinkedIn audience segment holds exactly one uploaded list, so the list you send here REPLACES the segment's list instead of being appended to it. Always send the full set of companies. LinkedIn returns only the identifier of the uploaded file, never its rows, so the merge cannot be done for you. Keep the source list on your side. ### How the matching behaves - Rows are plain text (not hashed), matched against LinkedIn's own company graph. - Matching is asynchronous: LinkedIn takes up to 48h for a new audience and up to 24h for a later update, and the audience stays `processing` meanwhile. - LinkedIn does not document how quickly companies dropped from the list stop being targeted, so treat removals as eventual rather than immediate. - LinkedIn recommends at least 1,000 companies for a usable match rate, and caps a list at 300,000.
pub async fn replace_ad_audience_companies(
configuration: &configuration::Configuration,
audience_id: &str,
replace_ad_audience_companies_request: models::ReplaceAdAudienceCompaniesRequest,
) -> Result<models::ReplaceAdAudienceCompanies200Response, Error<ReplaceAdAudienceCompaniesError>> {
// add a prefix to parameters to efficiently prevent name collisions
let p_path_audience_id = audience_id;
let p_body_replace_ad_audience_companies_request = replace_ad_audience_companies_request;
let uri_str = format!(
"{}/v1/ads/audiences/{audienceId}/companies",
configuration.base_path,
audienceId = crate::apis::urlencode(p_path_audience_id)
);
let mut req_builder = configuration
.client
.request(reqwest::Method::POST, &uri_str);
if let Some(ref user_agent) = configuration.user_agent {
req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
}
if let Some(ref token) = configuration.bearer_access_token {
req_builder = req_builder.bearer_auth(token.to_owned());
};
req_builder = req_builder.json(&p_body_replace_ad_audience_companies_request);
let req = req_builder.build()?;
let resp = configuration.client.execute(req).await?;
let status = resp.status();
let content_type = resp
.headers()
.get("content-type")
.and_then(|v| v.to_str().ok())
.unwrap_or("application/octet-stream");
let content_type = super::ContentType::from(content_type);
if !status.is_client_error() && !status.is_server_error() {
let content = resp.text().await?;
match content_type {
ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::ReplaceAdAudienceCompanies200Response`"))),
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::ReplaceAdAudienceCompanies200Response`")))),
}
} else {
let content = resp.text().await?;
let entity: Option<ReplaceAdAudienceCompaniesError> = serde_json::from_str(&content).ok();
Err(Error::ResponseError(ResponseContent {
status,
content,
entity,
}))
}
}
/// Renames or redescribes an audience, or replaces a saved targeting audience's rules; platform audience rules cannot change. ### `saved_targeting` audiences They accept `name`, `description`, and `spec`. `spec` is a full replacement (no merge), Zernio-only, with no platform call. Ads already created from a saved_targeting audience are unaffected: they snapshot the targeting at creation. ### Platform audiences (uploaded/website/lookalike) - They accept `name` and `description` only, updated on the platform first and then mirrored locally. - Their rules are immutable, so `spec` returns 400 for them. - Platform audience updates are Meta-only for now (other platforms return 501).
pub async fn update_ad_audience(
configuration: &configuration::Configuration,
audience_id: &str,
update_ad_audience_request: models::UpdateAdAudienceRequest,
) -> Result<models::CreateAdAudience201Response, Error<UpdateAdAudienceError>> {
// add a prefix to parameters to efficiently prevent name collisions
let p_path_audience_id = audience_id;
let p_body_update_ad_audience_request = update_ad_audience_request;
let uri_str = format!(
"{}/v1/ads/audiences/{audienceId}",
configuration.base_path,
audienceId = crate::apis::urlencode(p_path_audience_id)
);
let mut req_builder = configuration.client.request(reqwest::Method::PUT, &uri_str);
if let Some(ref user_agent) = configuration.user_agent {
req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
}
if let Some(ref token) = configuration.bearer_access_token {
req_builder = req_builder.bearer_auth(token.to_owned());
};
req_builder = req_builder.json(&p_body_update_ad_audience_request);
let req = req_builder.build()?;
let resp = configuration.client.execute(req).await?;
let status = resp.status();
let content_type = resp
.headers()
.get("content-type")
.and_then(|v| v.to_str().ok())
.unwrap_or("application/octet-stream");
let content_type = super::ContentType::from(content_type);
if !status.is_client_error() && !status.is_server_error() {
let content = resp.text().await?;
match content_type {
ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::CreateAdAudience201Response`"))),
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::CreateAdAudience201Response`")))),
}
} else {
let content = resp.text().await?;
let entity: Option<UpdateAdAudienceError> = serde_json::from_str(&content).ok();
Err(Error::ResponseError(ResponseContent {
status,
content,
entity,
}))
}
}