late 0.0.853

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).
Documentation
/*
 * 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).
 *
 * The version of the OpenAPI document: 1.0.4
 * 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 [`get_instagram_audio`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum GetInstagramAudioError {
    Status400(models::ErrorResponse),
    Status401(models::InlineObject),
    Status404(),
    Status502(),
    UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`get_instagram_publishing_limit`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum GetInstagramPublishingLimitError {
    Status400(),
    Status401(models::InlineObject),
    Status404(),
    Status502(),
    UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`get_instagram_story_insights`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum GetInstagramStoryInsightsError {
    Status400(),
    Status401(models::InlineObject),
    Status404(),
    Status502(),
    UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`list_instagram_stories`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ListInstagramStoriesError {
    Status400(),
    Status401(models::InlineObject),
    Status404(),
    UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`search_instagram_audio`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum SearchInstagramAudioError {
    Status400(models::ErrorResponse),
    Status401(models::InlineObject),
    Status404(),
    Status502(),
    UnknownValue(serde_json::Value),
}

/// Fetch one audio asset's metadata by ID. Use it to re-validate a stored `audioId` before a scheduled Reel publishes, or to refresh the preview `downloadUrl` (Meta expires preview URLs after roughly 1.5 days).  Same connection requirement as the search endpoint: Facebook-Login Instagram accounts only.
pub async fn get_instagram_audio(
    configuration: &configuration::Configuration,
    account_id: &str,
    audio_id: &str,
) -> Result<models::GetInstagramAudio200Response, Error<GetInstagramAudioError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_path_account_id = account_id;
    let p_path_audio_id = audio_id;

    let uri_str = format!(
        "{}/v1/accounts/{accountId}/instagram/audio/{audioId}",
        configuration.base_path,
        accountId = crate::apis::urlencode(p_path_account_id),
        audioId = crate::apis::urlencode(p_path_audio_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::GetInstagramAudio200Response`"))),
            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::GetInstagramAudio200Response`")))),
        }
    } else {
        let content = resp.text().await?;
        let entity: Option<GetInstagramAudioError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

/// Returns the account's remaining content-publishing quota for Instagram's rolling 24-hour window, so you can pace publishing and warn before the cap is reached.  `quotaUsage` counts containers published since the start of the window. Always compare against the returned `quotaTotal` rather than hardcoding a number: Meta's prose documentation and the live API disagree on the value, and the live value is authoritative.
pub async fn get_instagram_publishing_limit(
    configuration: &configuration::Configuration,
    account_id: &str,
) -> Result<models::GetInstagramPublishingLimit200Response, Error<GetInstagramPublishingLimitError>>
{
    // add a prefix to parameters to efficiently prevent name collisions
    let p_path_account_id = account_id;

    let uri_str = format!(
        "{}/v1/accounts/{accountId}/instagram/publishing-limit",
        configuration.base_path,
        accountId = crate::apis::urlencode(p_path_account_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::GetInstagramPublishingLimit200Response`"))),
            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::GetInstagramPublishingLimit200Response`")))),
        }
    } else {
        let content = resp.text().await?;
        let entity: Option<GetInstagramPublishingLimitError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

/// Returns metrics for a single story. The `source` field discriminates between three states:  - `live` — fetched from Meta in real time (story is still active) - `cached` — fetched from a persisted `story_insights` webhook payload   (story has expired but we received its final-state metrics from Meta) - `unavailable` — story has expired and we never received its webhook   payload (for example, the account connected after the story expired)  Meta can report an expired story as an empty successful result rather than an error, so an expired story resolves to `cached` or `unavailable` even though the upstream request itself succeeded.  Field semantics follow Meta's API. Counts below 5 may be returned as 0 due to Meta's privacy floor on small audiences. The `navigation` field is the sum of `tapsForward + tapsBack + exits + swipesForward`.
pub async fn get_instagram_story_insights(
    configuration: &configuration::Configuration,
    account_id: &str,
    story_id: &str,
) -> Result<models::GetInstagramStoryInsights200Response, Error<GetInstagramStoryInsightsError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_path_account_id = account_id;
    let p_path_story_id = story_id;

    let uri_str = format!(
        "{}/v1/accounts/{accountId}/instagram/stories/{storyId}/insights",
        configuration.base_path,
        accountId = crate::apis::urlencode(p_path_account_id),
        storyId = crate::apis::urlencode(p_path_story_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::GetInstagramStoryInsights200Response`"))),
            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::GetInstagramStoryInsights200Response`")))),
        }
    } else {
        let content = resp.text().await?;
        let entity: Option<GetInstagramStoryInsightsError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

/// Returns the IG Business/Creator account's currently-active stories. Meta keeps stories live for 24h; expired stories are not returned.  Limitations propagated from Meta (these are NOT bugs): - 24h window only - Live videos excluded - Reshared stories not returned - `mediaUrl` may be null if Meta flagged the story for copyright - `caption`, `likeCount`, `commentsCount` do not apply to story media
pub async fn list_instagram_stories(
    configuration: &configuration::Configuration,
    account_id: &str,
) -> Result<models::ListInstagramStories200Response, Error<ListInstagramStoriesError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_path_account_id = account_id;

    let uri_str = format!(
        "{}/v1/accounts/{accountId}/instagram/stories",
        configuration.base_path,
        accountId = crate::apis::urlencode(p_path_account_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::ListInstagramStories200Response`"))),
            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::ListInstagramStories200Response`")))),
        }
    } else {
        let content = resp.text().await?;
        let entity: Option<ListInstagramStoriesError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

/// Search Instagram's audio catalog (licensed music or original sounds), or list what is currently trending by omitting `q`. Returns up to ~30 assets; Meta exposes no pagination on this edge.  Pass the returned `audioId` as `platformSpecificData.audioConfiguration.audioId` when creating a Reel to publish it with that track.  Requires an Instagram account connected via **Facebook Login**. Meta hosts this catalog on graph.facebook.com only, so accounts connected with classic Instagram Login receive a 400 (`instagram_audio_requires_facebook_login`) and must be reconnected choosing the Facebook option.
pub async fn search_instagram_audio(
    configuration: &configuration::Configuration,
    account_id: &str,
    audio_type: &str,
    q: Option<&str>,
) -> Result<models::SearchInstagramAudio200Response, Error<SearchInstagramAudioError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_path_account_id = account_id;
    let p_query_audio_type = audio_type;
    let p_query_q = q;

    let uri_str = format!(
        "{}/v1/accounts/{accountId}/instagram/audio",
        configuration.base_path,
        accountId = crate::apis::urlencode(p_path_account_id)
    );
    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);

    req_builder = req_builder.query(&[("audioType", &p_query_audio_type.to_string())]);
    if let Some(ref param_value) = p_query_q {
        req_builder = req_builder.query(&[("q", &param_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::SearchInstagramAudio200Response`"))),
            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::SearchInstagramAudio200Response`")))),
        }
    } else {
        let content = resp.text().await?;
        let entity: Option<SearchInstagramAudioError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}