snippe 0.1.0

Async Rust client for the Snippe payments API (Tanzania) — collections, hosted checkout sessions, disbursements, and verified webhooks.
Documentation
//! Safely send a mobile-money payout.
//!
//! Demonstrates the recommended preflight pattern:
//!   1. Calculate the fee for the desired amount.
//!   2. Confirm available balance covers `total_amount`.
//!   3. Send the payout with an idempotency key.

use snippe::models::payout::{MobilePayout, SendPayoutRequest};
use snippe::{Client, IdempotencyKey};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api_key = std::env::var("SNIPPE_API_KEY").expect("set SNIPPE_API_KEY");
    let client = Client::new(api_key)?;

    let amount: u64 = 5_000;

    // 1. Fee preflight
    let fee = client.payouts().fee(amount).await?;
    println!(
        "fee={} TZS, total deducted={} TZS",
        fee.fee_amount, fee.total_amount
    );

    // 2. Balance check — `available` is the spendable amount.
    let balance = client.payments().balance().await?;
    if balance.available.value < fee.total_amount {
        return Err(format!(
            "insufficient balance: available {} < required {}",
            balance.available.value, fee.total_amount
        )
        .into());
    }

    // 3. Send with an idempotency key so retries are safe.
    let request = SendPayoutRequest::Mobile(
        MobilePayout::new(amount, "255781000000", "Recipient Name")
            .with_narration("Salary January 2026")
            .with_webhook_url("https://yoursite.com/webhooks/snippe"),
    );
    let key = IdempotencyKey::new("po-emp-001-jan26")?;
    let payout = client.payouts().send(&request, Some(&key)).await?;

    println!(
        "queued payout {} (status: {:?}, total: {} TZS)",
        payout.reference, payout.status, payout.total.value
    );
    Ok(())
}