zammad-api 0.4.0

Async, idiomatic Rust client for the Zammad Service Platform
Documentation

zammad-api

Async, idiomatic Rust client for the Zammad REST API, written by SiSol PRO, a French company that has its expertise in managing "communautés d'autoconsommation".

  • Builder-style Client with token, bearer or basic auth
  • Strongly typed models for tickets, articles, users, organizations, groups, tags, states and priorities
  • Streaming pagination via futures::Stream
  • Custom-field passthrough via #[serde(flatten)] extra
  • Write-verification helper for setting custom fields (Zammad silently returns 200 when a field doesn't exist on the object - set_field turns that into a loud error)
  • TLS opt-in: rustls-tls (default) or native-tls

Quick start

[dependencies]
zammad-api = "0.1"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
futures-util = "0.3"
use futures_util::TryStreamExt;
use zammad_api::{Auth, Client, models::NewArticle};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let zammad = Client::builder()
        .url("https://help.example.com")
        .auth(Auth::token(std::env::var("ZAMMAD_TOKEN")?))
        .build()?;

    // Stream every open ticket
    let mut stream = zammad.tickets().search("state.name:open").stream();
    while let Some(ticket) = stream.try_next().await? {
        println!("#{} {}", ticket.id, ticket.title.as_deref().unwrap_or(""));
    }

    // Reply to a ticket
    zammad
        .articles()
        .create(42)
        .article(NewArticle::new("Thanks for the report.").article_type("note"))
        .send()
        .await?;

    // Tag a ticket
    zammad.tags().add(42, "important").await?;

    Ok(())
}

Authentication

use zammad_api::Auth;

Auth::token("YOUR_TOKEN");                // -> Authorization: Token token=...
Auth::bearer("YOUR_OAUTH_TOKEN");         // -> Authorization: Bearer ...
Auth::basic("agent@example.com", "pw");   // -> Authorization: Basic ...

Custom fields

Every model exposes an extra: serde_json::Map<String, Value> field that captures any attribute Zammad returns that isn't part of the typed schema - perfect for the custom fields you've added in Zammad's Object Manager.

# use zammad_api::Client;
# async fn run(z: &Client) -> zammad_api::Result<()> {
let ticket = z.tickets().get(123).await?;
let link = ticket.extra.get("espocrm_link").and_then(|v| v.as_str());

// Set + verify the value was persisted (Zammad silently swallows unknown fields)
z.tickets().set_field(123, "espocrm_link", "https://crm/Contact/abc").await?;
# Ok(()) }

License

MIT