infobip-sms-sdk 0.1.0

Async Rust SDK for the Infobip SMS API: send messages, manage scheduled bulks, query delivery reports and logs, fetch inbound SMS, and parse webhook payloads.
Documentation
use reqwest::Method;

use crate::api::{decode_response, ErrorKind};
use crate::client::Client;
use crate::error::Error;
use crate::models::bulks::{
    BulkResponse, BulkStatusResponse, RescheduleBulkRequest, UpdateBulkStatusRequest,
};

impl Client {
    /// Fetches the scheduled dispatch time of a bulk.
    ///
    /// Wraps `GET /sms/1/bulks?bulkId=...`. The bulk ID is either one
    /// you set explicitly via
    /// [`crate::models::send::RequestSchedulingSettings::bulk_id`] or
    /// the value Infobip auto-assigned, returned in
    /// [`crate::models::send::SmsResponse::bulk_id`].
    ///
    /// # Errors
    ///
    /// On non-2xx responses, returns
    /// [`Error::Exception`]. Notably, a
    /// bulk that has already finished or never existed yields HTTP
    /// 404.
    pub async fn get_scheduled_bulk(&self, bulk_id: &str) -> Result<BulkResponse, Error> {
        let response = self
            .request(Method::GET, "sms/1/bulks")?
            .query(&[("bulkId", bulk_id)])
            .send()
            .await?;
        decode_response(response, ErrorKind::Legacy).await
    }

    /// Reschedules a pending bulk.
    ///
    /// Wraps `PUT /sms/1/bulks?bulkId=...`. Only bulks in `PENDING`
    /// status can be rescheduled.
    ///
    /// # Errors
    ///
    /// On non-2xx responses, returns
    /// [`Error::Exception`].
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use infobip_sms::Client;
    /// use infobip_sms::models::bulks::RescheduleBulkRequest;
    ///
    /// # async fn run(client: Client, bulk_id: &str) -> Result<(), infobip_sms::Error> {
    /// client
    ///     .reschedule_bulk(
    ///         bulk_id,
    ///         &RescheduleBulkRequest { send_at: "2026-12-24T09:00:00.000+0000".into() },
    ///     )
    ///     .await?;
    /// # Ok(()) }
    /// ```
    pub async fn reschedule_bulk(
        &self,
        bulk_id: &str,
        request: &RescheduleBulkRequest,
    ) -> Result<BulkResponse, Error> {
        let response = self
            .request(Method::PUT, "sms/1/bulks")?
            .query(&[("bulkId", bulk_id)])
            .json(request)
            .send()
            .await?;
        decode_response(response, ErrorKind::Legacy).await
    }

    /// Fetches the lifecycle status of a bulk.
    ///
    /// Wraps `GET /sms/1/bulks/status?bulkId=...`. Returns one of the
    /// [`BulkStatus`](crate::models::common::BulkStatus) values.
    ///
    /// # Errors
    ///
    /// On non-2xx responses, returns
    /// [`Error::Exception`].
    pub async fn get_bulk_status(&self, bulk_id: &str) -> Result<BulkStatusResponse, Error> {
        let response = self
            .request(Method::GET, "sms/1/bulks/status")?
            .query(&[("bulkId", bulk_id)])
            .send()
            .await?;
        decode_response(response, ErrorKind::Legacy).await
    }

    /// Pauses, resumes, or cancels a bulk.
    ///
    /// Wraps `PUT /sms/1/bulks/status?bulkId=...`. Allowed transitions:
    ///
    /// - `Pending` → `Paused` (pause)
    /// - `Paused` → `Pending` (resume)
    /// - `Pending` or `Paused` → `Canceled` (terminal)
    ///
    /// # Errors
    ///
    /// On non-2xx responses, returns
    /// [`Error::Exception`]. Disallowed
    /// transitions yield HTTP 400.
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use infobip_sms::Client;
    /// use infobip_sms::models::bulks::UpdateBulkStatusRequest;
    /// use infobip_sms::models::common::BulkStatus;
    ///
    /// # async fn run(client: Client, bulk_id: &str) -> Result<(), infobip_sms::Error> {
    /// client
    ///     .update_bulk_status(bulk_id, &UpdateBulkStatusRequest { status: BulkStatus::Canceled })
    ///     .await?;
    /// # Ok(()) }
    /// ```
    pub async fn update_bulk_status(
        &self,
        bulk_id: &str,
        request: &UpdateBulkStatusRequest,
    ) -> Result<BulkStatusResponse, Error> {
        let response = self
            .request(Method::PUT, "sms/1/bulks/status")?
            .query(&[("bulkId", bulk_id)])
            .json(request)
            .send()
            .await?;
        decode_response(response, ErrorKind::Legacy).await
    }
}