Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Email Funnel AI — Rust SDK

Official Rust client for the Email Funnel AI integration API. Connect with your project key and secret, then call typed, resource-oriented methods — no manual URLs, headers, or JSON plumbing.

  • Async, built on reqwest + tokio
  • rustls TLS by default — no system OpenSSL required
  • Typed error model (EmailFunnelError) with status, error_type, and 422 field messages
  • Injectable transport for custom clients, logging, or offline tests
  • Full coverage of all 26 endpoints

Installation

# Cargo.toml
[dependencies]
emailfunnelai = "1"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
serde_json = "1"

Quick start

use emailfunnelai::EmailFunnelAi;
use serde_json::json;

#[tokio::main]
async fn main() -> emailfunnelai::Result<()> {
    // base_url defaults to https://app.emailfunnel.ai — override only for staging/local.
    let client = EmailFunnelAi::new("pk_your_project_key", "sk_your_secret_key");

    // 1. Confirm your credentials
    client.validate().await?;

    // 2. Get or create a list
    let list = client.lists().create("Newsletter signups", None).await?;
    let list_id = list["id"].as_str().unwrap_or("").to_string();

    // 3. Sync a contact into it
    client
        .contacts()
        .sync(json!({ "email": "jane@example.com", "source_type": "custom_saas" }))
        .to_list(&list_id)
        .await?;

    Ok(())
}

Every call returns the unwrapped data payload as a [serde_json::Value], so you can read fields directly or serde_json::from_value into your own structs.

Usage

Every group is reached from the client and reads as resource → verb.

Contacts

use serde_json::json;

// Single contact
client
    .contacts()
    .sync(json!({ "email": "jane@example.com", "source_type": "app" }))
    .to_list("42")
    .await?;

// Bulk (up to 500; the server queues automatically above 100 rows)
client
    .contacts()
    .bulk(vec![json!({ "email": "a@example.com" })], "import")
    .to_list("42")
    .await?;

// Force queued processing
client
    .contacts()
    .bulk(rows, "import")
    .queued()
    .to_list("42")
    .await?;

// Real-time webhook event
client
    .contacts()
    .webhook("order.completed", json!({ "email": "a@example.com" }))
    .to_list("42")
    .await?;

Lists

client.lists().all().await?;
client.lists().create("VIP customers", Some("High-value buyers")).await?;
client.lists().find("42").await?;

Bindings

client.bindings().all().await?;
client.bindings().create("custom_crm", "42", None).await?;
client.bindings().find("5").await?;
client.bindings().update("5", json!({ "sync_enabled": false })).await?;
client.bindings().delete("5").await?;
client.bindings().status("5", "completed", Some(0)).await?;

Field mappings

client.field_mappings().config("custom_saas").await?;
client.field_mappings().for_binding("5").get().await?;
client.field_mappings().for_binding("5").update(json!({ "email": "Email" })).await?;
client.field_mappings().for_binding("5").reset().await?;

Auto-tagging

client.auto_tagging().rules("custom_saas").await?;
client.auto_tagging().preview("custom_saas", json!({ "plan": "pro" })).await?;

Analytics

use emailfunnelai::HeatmapOptions;

client.analytics().dashboard().await?;
client
    .analytics()
    .heatmap(HeatmapOptions::new().range(30).email_type("campaign").timezone("America/New_York"))
    .await?;
client.analytics().funnels().await?;
client.analytics().campaigns().await?;
client.analytics().forms().await?;

SSO

client.sso().generate("admin@example.com").await?;
client.sso().team_members().await?;

Responses & errors

Successful calls return the unwrapped data payload. Any error response yields an [EmailFunnelError]:

use emailfunnelai::EmailFunnelError;

match client.contacts().sync(contact).to_list(list_id).await {
    Ok(data) => { /* … */ }
    Err(EmailFunnelError::Api(api)) => {
        api.status;       // 422
        api.error_type;   // "validation_error"
        api.messages;     // Option<HashMap<String, Vec<String>>> — set on 422
        api.retry_after;  // Option<u64> — set on 429 rate limits
    }
    Err(EmailFunnelError::Transport(message)) => { /* network / timeout */ }
    Err(EmailFunnelError::Decode(message)) => { /* malformed response body */ }
}

Branch on error_type for specific conditions — e.g. a contact list that has been deactivated rejects new members with a 409 list_inactive:

if let Err(EmailFunnelError::Api(api)) = client.contacts().sync(contact).to_list(list_id).await {
    if api.error_type == "list_inactive" {
        // The target list is inactive — reactivate it or pick another list.
    }
}

Common error_type values

error_type Status Meaning
invalid_credentials 401 Missing/invalid project key or secret
inactive_project 403 The connected project is inactive
validation_error 422 Request body failed validation (messages set)
invalid_email / suppressed 422 Email is undeliverable or suppressed
list_inactive 409 Target contact list is inactive and rejects new members
rate_limit_exceeded 429 1000 req/hour cap hit (retry_after set)
sync_failed 500 Unexpected sync failure

Custom transport & base URL

Use the builder to override the base URL or inject a transport:

use std::sync::Arc;
use emailfunnelai::{EmailFunnelAi, ReqwestHttpClient};

// Point at a local dev server
let client = EmailFunnelAi::builder("pk", "sk")
    .base_url("http://localhost:8000")
    .build();

// Wrap a pre-configured reqwest client (timeouts, proxies, pools)
let reqwest_client = reqwest::Client::builder()
    .timeout(std::time::Duration::from_secs(30))
    .build()
    .unwrap();

let client = EmailFunnelAi::builder("pk", "sk")
    .http_client(Arc::new(ReqwestHttpClient::with_client(reqwest_client)))
    .build();

Implement the HttpClient trait to stub HTTP entirely (used by this crate's own test suite) for fast, offline tests.

Testing

cargo test

License

MIT © Email Funnel AI. Authored by Email Funnel AI and Ratul Hasan.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages